新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 嵌入式Linux下USB驅動程序的設計

        嵌入式Linux下USB驅動程序的設計

        作者: 時間:2013-10-08 來源:網絡 收藏

          (2)probe()函數

          probe()函數的編寫格式為:static void * skel_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);需要確認插入的設備是否可以被接受,如果不接受,或者在初始化的過程中發生任何錯誤,probe()函數返回一個NULL值。否則返回一個含有設備狀態的指針,通過這個指針,就可以訪問所有結構中的回調函數。

          在里,最后一點是要注冊devfs(設備文件系統)。首先創建一個緩沖用來保存那些被發送給設備的數據和那些從設備上接受的數據,并為設備傳輸創建一個請求塊(URB)以向設備寫入數據,同時 urb 被初始化,然后在devfs子系統中注冊設備,允許devfs用戶訪問USB的設備。注冊過程如下:

          /* initialize the devfs node for this device and register it */

          sprintf(name, "skel%d", skel->minor);

          skel->devfs = devfs_register (usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, USB_SKEL_MINOR_BASE + skel->minor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, skel_fops, NULL);

          如果devfs_register函數失敗, devfs子系統會將此情況報告給用戶。如果設備從USB總線拔掉,設備指針會調用disconnect 函數。驅動程序就需要清除那些被分配了的所有私有數據、關閉urbs,并且從devfs上注銷調自己。調用函數的格式為:

          /* remove our devfs node */

          devfs_unregister(skel->devfs);

          現在,skeleton驅動就已經和設備綁定上了,任何用戶態程序要操作此設備都可以通過file_operations結構所定義的函數進行了。

          (3)open()、write()和read()函數

          首先,要打開此設備。在open()函數中MODULE_INC_USE_COUNT 宏是一個關鍵,它起到一個計數的作用,有一個用戶態程序打開一個設備,計數器就加1。例如,以模塊方式加入一個驅動,若計數器不為零,就說明仍然有用戶程序在使用此驅動,這時候,就不能通過rmmod命令卸載驅動模塊了。

          /* increment our usage count for the module */

          MOD_INC_USE_COUNT;

          ++skel->open_count;

          /* save our object in the file's private structure */

          file->private_data = skel;

          當open完設備后,read()、write()函數就可以收、發數據了。

          read()函數首先從open()函數中保存的fi。

          Write()函數和read()函數是完成驅動對讀寫等操作的響應。在skel_write中,一個FILL_BULK_URB函數,就完成了urb 系統callbak和的skel_write_bulk_callback之間的聯系。注意skel_write_bulkcallback是中斷方式,所以要注意時間不能太久,本程序中它就只是報告一些urb的狀態等。 read 函數與write 函數稍有不同在于:程序并沒有用urb 將數據從設備傳送到驅動程序,而是用usb_bulk_msg 函數代替,這個函數能夠不需要創建urbs 和操作urb函數的情況下,來發送數據給設備,或者從設備來接收數據。調用usb_bulk_msg函數并傳到一個存儲空間,用來緩沖和放置驅動收到的數據,若沒有收到數據表示失敗并返回一個錯誤信息。

          usb_bulk_msg函數:當對usb設備進行一次讀或者寫時,usb_bulk_msg 函數是非常有用的; 然而, 當需要連續地對設備進行讀/寫時,應建立一個自己的urbs,同時將urbs 提交給USB子系統。

          skel_disconnect函數:當釋放設備文件句柄時,這個函數會被調用。

          MOD_DEC_USE_COUNT宏也會被調用到(和MOD_INC_USE_COUNT剛好對應,它減少一個計數器),首先確認當前是否有其他的程序正在訪問這個設備,如果是最后一個用戶在使用,可以關閉任何正在發生的寫,操作如下:

          /* decrement our usage count for the device */

          --skel->open_count;

          if (skel->open_count = 0) {

          /* shutdown any bulk writes that might be

          going on */

          usb_unlink_urb (skel->write_urb);

          skel->open_count = 0;

          }

          /* decrement our usage count for the module */

          MOD_DEC_USE_COUNT;

          USB設備可以在任何時間點從系統中取走,即使程序目前正在訪問它。USB驅動程序必須要能夠很好地處理解決此問題,它需要能夠切斷任何當前的讀寫,同時通知用戶空間程序:USB設備已經被取走。

          2.設計實例

          下面通過介紹鍵盤飛梭驅動程序的實例來讓讀者更好的理解USB驅動程序的工作原理,實現代碼如下:

          /*需要的頭文件*/

          #include linux/kernel.h>

          #include linux/slab.h>

          #include linux/module.h>

          #include linux/input.h>

          #include linux/init.h>

          #include linux/usb.h>

          #include linux/kbd_ll.h>

          /* 驅動程序版本信息*/

          #define DRIVER_VERSION ""

          #define DRIVER_AUTHOR " TGE HOTKEY "

          #define DRIVER_DESC "USB HID Tge hotkey driver"

          #define USB_HOTKEY_VENDOR_ID 0x07e4

          #define USB_HOTKEY_PRODUCT_ID 0x9473

          /*廠商和產品ID信息就是/proc/bus/usb/devices中看到的值,通過cat/proc/bus/usb/devices得到當前系統探測到的USB總線上的設備信息。它包括Vendor、ProdID、Product等*/

          MODULE_AUTHOR( DRIVER_AUTHOR );

          MODULE_DESCRIPTION( DRIVER_DESC );

          /*此結構來自內核中drivers/usb/usbkbd.c*/

          struct usb_kbd {

          struct input_dev dev;

          struct usb_device *usbdev;

          unsigned char new[8];

          unsigned char old[8];

          struct urb irq, led;

          struct usb_ctrlrequest dr;

          unsigned char leds, newleds;

          char name[128];

          int open;

          };

          static void usb_kbd_irq(struct urb *urb) /*urb為USB請求塊*/

          {

          struct usb_kbd *kbd = urb->context;

          int *new;

          new = (int *) kbd->new;

          if(kbd->new[0] == (char)0x01)

          {

          if(((kbd->new[1]>>4)0x0f)!=0x7)

          {

          handle_scancode(0xe0,1);

          handle_scancode(0x4b,1);

          handle_scancode(0xe0,0);

          handle_scancode(0x4b,0);

          }

        linux操作系統文章專題:linux操作系統詳解(linux不再難懂)

        linux相關文章:linux教程




        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 威海市| 丽江市| 安宁市| 永德县| 三都| 太白县| 商河县| 资阳市| 旺苍县| 山阴县| 连南| 永康市| 天津市| 介休市| 阿拉善右旗| 高陵县| 鄂尔多斯市| 独山县| 洪雅县| 梧州市| 潼关县| 弥勒县| 新宁县| 桐城市| 宁津县| 哈尔滨市| 婺源县| 安丘市| 南投县| 南宫市| 普格县| 中牟县| 鸡泽县| 淄博市| 额敏县| 鱼台县| 苏尼特左旗| 永仁县| 藁城市| 杭州市| 博兴县|