• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 入門文章:教你學會編寫Linux設備驅動

    發表于:2007-06-08來源:作者:點擊數: 標簽:
    內核版本: 2.4.22 閱讀此文的目的: 學會編寫 Linux 設備驅動。 閱讀此文的方法: 閱讀以下2個文件: hello.c,asdf.c。 此文假設讀者: 已經能用C語言編寫Linux應用程序, 理解"字符設備文件, 塊設備文件, 主設備號, 次設備號", 會寫簡單的Shell腳本和Makefile。 1
    內核版本: 2.4.22

      閱讀此文的目的: 學會編寫Linux設備驅動。

      閱讀此文的方法: 閱讀以下2個文件: hello.c,asdf.c。

      此文假設讀者:

      已經能用C語言編寫Linux應用程序,

      理解"字符設備文件, 塊設備文件, 主設備號, 次設備號",

      會寫簡單的Shell腳本和Makefile。

      1. "hello.c"

      --------------------------------

      /*

      * 這是我們的第一個源文件,

      * 它是一個可以加載的內核模塊,

      * 加載時顯示"Hello,World!",

      * 卸載時顯示"Bye!"。

      * 需要說明一點,寫內核或內核模塊不能用寫應用程序時的系統調用或函數庫,

      * 因為我們寫的就是為應用程序提供系統調用的代碼。

      * 內核有專用的函數庫,如, , 等,

      * 現在還沒必要了解得很詳細,

      * 這里用到的printk的功能類似于printf。

      * "/usr/src/linux"是你實際的內核源碼目錄的一個符號鏈接,

      * 如果沒有現在就創建一個,因為下面和以后都會用到。

      * 編譯它用"gclearcase/" target="_blank" >cc -c -I/usr/src/linux/include hello.c",

      * 如果正常會生成文件hello.o,

      * 加載它用"insmod hello.o",

      * 只有在文本終端下才能看到輸出。

      * 卸載它用"rmmod hello"

      */

      /*

      * 小技巧: 在用戶目錄的.bashrc里加上一行:

      * alias mkmod='gcc -c -I/usr/src/linux/include'

      * 然后重新登陸Shell,

      * 以后就可以用"mkmod hello.c"的方式來編譯內核模塊了。

      */

      /* 開始例行公事 */

      #ifndef __KERNEL__

      # define __KERNEL__

      #endif

      #ifndef MODULE

      # define MODULE

      #endif

      #include

      #include

      MODULE_LICENSE("GPL");

      #ifdef CONFIG_SMP

      #define __SMP__

      #endif

      /* 結束例行公事 */

      #include /* printk()在這個文件里 */

      static int

      init_module

      (){

      printk("Hello,World!\n");

      return 0; /* 如果初始工作失敗,就返回非0 */

      }

      static void

      cleanup_module

      (){

      printk("Bye!\n");

      }

      ------------------------------------

      2. "asdf.c"

      ------------------------------------

     /*

      * 這個文件是一個內核模塊。

      * 內核模塊的編譯,加載和卸載在前面已經介紹了。

      * 這個模塊的功能是,創建一個字符設備。

      * 這個設備是一塊4096字節的共享內存。

      * 內核分配的主設備號會在加載模塊時顯示。

      */

      /* 開始例行公事 */

      #ifndef __KERNEL__

      # define __KERNEL__

      #endif

      #ifndef MODULE

      # define MODULE

      #endif

      #include

      #include

      #ifdef CONFIG_SMP

      #define __SMP__

      #endif

      MODULE_LICENSE("GPL");

      /* 結束例行公事 */

      #include /* copy_to_user(), copy_from_user */

      #include /* struct file_operations, register_chrdev(), ... */

      #include /* printk()在這個文件里 */

      #include /* 和任務調度有關 */

      #include /* u8, u16, u32 ... */

      /*

      * 關于內核功能庫,可以去網上搜索詳細資料,

      */

      /* 文件被操作時的回調功能 */

      static int asdf_open (struct inode *inode, struct file *filp);

      static int asdf_release (struct inode *inode, struct file *filp);

      static ssize_t asdf_read (struct file *filp, char *buf, size_t count,loff_t *f_pos);

      static ssize_t asdf_write (struct file *filp, const char *buf, size_t count,loff_t *f_pos);

      static loff_t asdf_lseek (struct file * file, loff_t offset, int orig);

      /* 申請主設備號時用的結構, 在linux/fs.h里定義 */

      struct file_operations asdf_fops = {

      open: asdf_open,

      release: asdf_release,

      read: asdf_read,

      write: asdf_write,

      llseek: asdf_lseek,

      };

      static int asdf_major; /* 用來保存申請到的主設備號 */

      static u8 asdf_body[4096]="asdf_body\n"; /* 設備 */

      static int

      init_module

      (){

    printk ("Hi, This' A Simple Device File!\n");

      asdf_major = register_chrdev (0, "A Simple Device File", &asdf_fops); /* 申請字符設備的主設備號 */

      if (asdf_major < 0) return asdf_major; /* 申請失敗就直接返回錯誤編號 */

      printk ("The major is:%d\n", asdf_major); /* 顯示申請到的主設備號 */

      return 0; /* 模塊正常初始化 */

      }

      static void

      cleanup_module

      (){

      unregister_chrdev(asdf_major, "A Simple Device File"); /* 注銷以后,設備就不存在了 */

      printk("A Simple Device has been removed,Bye!\n");

      }

      /*

      * 編譯這個模塊然后加載它,

      * 如果正常,會顯示你的設備的主設備號。

      * 現在你的設備就建立好了,我們可以測試一下。

      * 假設你的模塊申請到的主設備號是254,

      * 運行"mknod abc c 254 0",就建立了我們的設備文件abc。

      * 可以把它當成一個4096字節的內存塊來測試一下,

      * 比如"cat abc", "cp abc image", "cp image abc",

      * 或寫幾個應用程序用它來進行通訊。

      * 介紹一下兩個需要注意的事,

      * 一是printk()的顯示只有在非圖形模式的終端下才能看到,

      * 二是加載過的模塊最好在不用以后卸載掉。

      * 如果對Linux環境的系統調用很陌生,建議先看APUE這本書。

      */

      static int

      asdf_open /* open回調 */

      (

      struct inode *inode,

      struct file *filp

      ){

      printk("^_^ : open %s\n ",\

      current->comm);

      /*

      * 應用程序的運行環境由內核提供,內核的運行環境由硬件提供。

      * 這里的current是一個指向當前進程的指針,

      * 現在沒必要了解current的細節。

      * 在這里,當前進程正打開這個設備,

      * 返回0表示打開成功,內核會給它一個文件描述符。

      * 這里的comm是當前進程在Shell下的command字符串。

      */

      return 0;

      }

      static int

      asdf_release /* close回調 */

      (

      struct inode *inode,

      struct file *filp

      ){

      printk("^_^ : close\n ");

      return 0;

      }

      static ssize_t

      asdf_read /* read回調 */

      (

    struct file *filp,

      char *buf,

      size_t count,

      loff_t *f_pos

      ){

      loff_t pos;

      pos = *f_pos; /* 文件的讀寫位置 */

      if ((pos==4096) || (count>4096)) return 0; /* 判斷是否已經到設備尾,或寫的長度超過設備大小 */

      pos += count;

      if (pos > 4096) {

      count -= (pos - 4096);

      pos = 4096;

      }

      if (copy_to_user(buf, asdf_body+*f_pos, count)) return -EFAULT; /* 把數據寫到應用程序空間 */

      *f_pos = pos; /* 改變文件的讀寫位置 */

      return count; /* 返回讀到的字節數 */

      }

      static ssize_t

      asdf_write /* write回調,和read一一對應 */

      (

      struct file *filp,

      const char *buf,

      size_t count,

      loff_t *f_pos

      ){

      loff_t pos;

      pos = *f_pos;

      if ((pos==4096) || (count>4096)) return 0;

      pos += count;

      if (pos > 4096) {

      count -= (pos - 4096);

      pos = 4096;

      }

      if (copy_from_user(asdf_body+*f_pos, buf, count)) return -EFAULT;

      *f_pos = pos;

      return count;

      }

      static loff_t

      asdf_lseek /* lseek回調 */

      (

      struct file * file,

      loff_t offset,

      int orig

      ){

      loff_t pos;

      pos = file->f_pos;

      switch (orig) {

      case 0:

      pos = offset;

      break;

      case 1:

      pos += offset;

      break;

      case 2:

      pos = 4096+offset;

      break;

      default:

      return -EINVAL;

      }

      if ((pos>4096) || (pos<0)) {

      printk("^_^ : lseek error %d\n",pos);

      return -EINVAL;

      }

      return file->f_pos = pos;

      }

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>