<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 嵌入式Linux下USB驅(qū)動程序的設計

          嵌入式Linux下USB驅(qū)動程序的設計

          作者: 時間:2013-10-08 來源:網(wǎng)絡 收藏

           ?。?)probe()函數(shù)

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

            在里,最后一點是要注冊devfs(設備文件系統(tǒng))。首先創(chuàng)建一個緩沖用來保存那些被發(fā)送給設備的數(shù)據(jù)和那些從設備上接受的數(shù)據(jù),并為設備傳輸創(chuàng)建一個請求塊(URB)以向設備寫入數(shù)據(jù),同時 urb 被初始化,然后在devfs子系統(tǒng)中注冊設備,允許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函數(shù)失敗, devfs子系統(tǒng)會將此情況報告給用戶。如果設備從USB總線拔掉,設備指針會調(diào)用disconnect 函數(shù)。驅(qū)動程序就需要清除那些被分配了的所有私有數(shù)據(jù)、關閉urbs,并且從devfs上注銷調(diào)自己。調(diào)用函數(shù)的格式為:

            /* remove our devfs node */

            devfs_unregister(skel->devfs);

            現(xiàn)在,skeleton驅(qū)動就已經(jīng)和設備綁定上了,任何用戶態(tài)程序要操作此設備都可以通過file_operations結(jié)構所定義的函數(shù)進行了。

           ?。?)open()、write()和read()函數(shù)

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

            /* 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()函數(shù)就可以收、發(fā)數(shù)據(jù)了。

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

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

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

            skel_disconnect函數(shù):當釋放設備文件句柄時,這個函數(shù)會被調(diào)用。

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

            /* 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設備可以在任何時間點從系統(tǒng)中取走,即使程序目前正在訪問它。USB驅(qū)動程序必須要能夠很好地處理解決此問題,它需要能夠切斷任何當前的讀寫,同時通知用戶空間程序:USB設備已經(jīng)被取走。

            2.設計實例

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

            /*需要的頭文件*/

            #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>

            /* 驅(qū)動程序版本信息*/

            #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

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

            MODULE_AUTHOR( DRIVER_AUTHOR );

            MODULE_DESCRIPTION( DRIVER_DESC );

            /*此結(jié)構來自內(nèi)核中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操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)

          linux相關文章:linux教程




          評論


          相關推薦

          技術專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();