亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        嵌入式Linux的USB讀卡器驅(qū)動(dòng)深入研究*

        2018-09-07 02:31:50
        關(guān)鍵詞:描述符讀卡器驅(qū)動(dòng)程序

        (江西財(cái)經(jīng)大學(xué) 現(xiàn)代經(jīng)濟(jì)管理學(xué)院,南昌330013)

        引 言

        Linux內(nèi)核支持兩種主要類型的USB驅(qū)動(dòng)程序:宿主(host)系統(tǒng)上的驅(qū)動(dòng)程序和設(shè)備(device)上的驅(qū)動(dòng)程序。從宿主的觀點(diǎn)來(lái)看(一個(gè)普通的USB宿主是一個(gè)桌面計(jì)算機(jī)),宿主系統(tǒng)的USB驅(qū)動(dòng)層次控制插入其中的USB設(shè)備,而USB設(shè)備的驅(qū)動(dòng)程序控制該設(shè)備如何作為一個(gè)USB設(shè)備和主機(jī)通信。設(shè)備驅(qū)動(dòng)程序一般存放在內(nèi)核的drivers/usb/gadget目錄中,針對(duì)某個(gè)具體設(shè)備的USB驅(qū)動(dòng)程序一般都是指宿主設(shè)備驅(qū)動(dòng),本文的USB讀卡器驅(qū)動(dòng)就是這一類。在Linux內(nèi)核中,USB設(shè)備驅(qū)動(dòng)是分很多層的,驅(qū)動(dòng)層只是整個(gè)框架中的一小部分,要所有層的配合才能將設(shè)備驅(qū)動(dòng)起來(lái)。USB驅(qū)動(dòng)程序存在于不同的內(nèi)核子系統(tǒng)(塊設(shè)備、網(wǎng)絡(luò)設(shè)備、字符設(shè)備等)和USB硬件控制器中。

        USB核心為USB驅(qū)動(dòng)程序提供了一個(gè)用于訪問(wèn)和控制USB硬件的接口,而不必考慮系統(tǒng)當(dāng)前存在的各種不同類型的USB硬件控制器,在USB 核心中對(duì)USB需要使用的各種資源進(jìn)行分配及初始化,如注冊(cè)USB總線usb_bus_type、初始化USB主控制器、初始化USB HUB等;同時(shí)還提供了一些接口給其它層使用,如usb_alloc_dev函數(shù)(當(dāng)有USB設(shè)備插入時(shí),用于分配并初始化usb_device)。USB控制器主要負(fù)責(zé)處理各個(gè)USB設(shè)備的通信,解析驅(qū)動(dòng)發(fā)送給每個(gè)設(shè)備的請(qǐng)求,并按照請(qǐng)求通知USB設(shè)備進(jìn)行相應(yīng)的處理,同時(shí)發(fā)送處理結(jié)果給驅(qū)動(dòng)程序,并調(diào)用驅(qū)動(dòng)傳入的complete函數(shù)。

        1 USB驅(qū)動(dòng)層

        1.1 USB設(shè)備基礎(chǔ)

        USB設(shè)備是一個(gè)非常復(fù)雜的東西。如圖1所示,USB設(shè)備由配置、接口、端點(diǎn)組成,而USB驅(qū)動(dòng)是綁定到接口上的,每個(gè)接口對(duì)應(yīng)于一個(gè)設(shè)備驅(qū)動(dòng),對(duì)于某些多接口的設(shè)備(如帶音頻接口的USB鍵盤(pán)),此設(shè)備就同時(shí)需要USB鍵盤(pán)和USB音頻這2個(gè)驅(qū)動(dòng)。

        圖1 USB設(shè)備框架

        如圖1所示,一個(gè)USB設(shè)備通常包含一個(gè)或多個(gè)配置,一個(gè)配置通常包含一個(gè)或多個(gè)接口,一個(gè)接口通常包含0個(gè)或多個(gè)端點(diǎn)。層次結(jié)構(gòu)如圖2所示。

        圖2 USB設(shè)備層次結(jié)構(gòu)

        (1)端點(diǎn)

        USB通信的最基本形式是通過(guò)端點(diǎn)來(lái)實(shí)現(xiàn)的,驅(qū)動(dòng)和接口的通信都是通過(guò)端點(diǎn),一個(gè)接口可以有0個(gè)或多個(gè)端點(diǎn),端點(diǎn)根據(jù)傳輸方式的不同分為以下4種:控制端點(diǎn)、中斷端點(diǎn)、等時(shí)端點(diǎn)和批量端點(diǎn),分別對(duì)應(yīng)于4種不同傳輸方式。

        控制端點(diǎn)主要通過(guò)向USB設(shè)備發(fā)送請(qǐng)求來(lái)設(shè)置或獲取USB設(shè)備的配置、狀態(tài)等信息,每個(gè)USB設(shè)備都有一個(gè)名為“端點(diǎn)0”的控制端點(diǎn),USB核心使用該端點(diǎn)在插入時(shí)進(jìn)行設(shè)備的配置;中斷端點(diǎn)主要實(shí)現(xiàn)以一個(gè)固定的速率來(lái)傳輸少量的數(shù)據(jù),中斷端點(diǎn)是USB鍵盤(pán)、鼠標(biāo)等設(shè)備所使用的主要傳輸方式;批量端點(diǎn)用于傳輸大量數(shù)據(jù),這些端點(diǎn)通常比中斷端點(diǎn)大得多,常用于需要確保沒(méi)有數(shù)據(jù)丟失的設(shè)備(如打印機(jī)、存儲(chǔ)設(shè)備、網(wǎng)絡(luò)設(shè)備);等時(shí)端點(diǎn)同樣可以傳輸大批量數(shù)據(jù),當(dāng)數(shù)據(jù)是否到達(dá)沒(méi)有保證,等時(shí)端點(diǎn)用于可以應(yīng)付數(shù)據(jù)丟失的設(shè)備,這類設(shè)備更注重于保持一個(gè)恒定的數(shù)據(jù)流(如USB音頻、視頻)。

        (2)接口

        USB端點(diǎn)被捆綁為接口,USB接口對(duì)應(yīng)于一個(gè)設(shè)備驅(qū)動(dòng),對(duì)應(yīng)于一種功能的設(shè)備,對(duì)于多接口的復(fù)合設(shè)備就需要多個(gè)驅(qū)動(dòng)。

        (3)配置

        USB接口被捆綁為配置,一個(gè)USB設(shè)備可以有多個(gè)配置,而且可以在配置之間切換已改變?cè)O(shè)備的狀態(tài)。例如一些允許下載固件到其上的設(shè)備包含多個(gè)配置以完成這個(gè)工作,而某一個(gè)時(shí)刻只能激活一個(gè)配置。

        1.2 USB urb

        Linux內(nèi)核中的USB代碼通過(guò)一個(gè)稱為urb(USB請(qǐng)求塊)的東西和所有的USB設(shè)備通信。這個(gè)請(qǐng)求塊使用struct urb結(jié)構(gòu)體來(lái)描述,可以從include/linux/usb.h文件中找到。urb被用來(lái)以一種異步的方式向/從特定的USB 設(shè)備上的特定USB端點(diǎn)發(fā)送/接收數(shù)據(jù)。USB設(shè)備驅(qū)動(dòng)程序可能會(huì)為單個(gè)端點(diǎn)分配許多urb,也可能對(duì)許多不同的端點(diǎn)重用單個(gè)的urb,這取決于驅(qū)動(dòng)程序的需要。設(shè)備中的每個(gè)端點(diǎn)都可以處理一個(gè)urb隊(duì)列,所以多個(gè)urb可以在隊(duì)列為空之前發(fā)送到同一個(gè)端點(diǎn)。一個(gè)urb的典型生命周期如下:

        ①由USB設(shè)備驅(qū)動(dòng)程序創(chuàng)建;②分配給一個(gè)特定USB 設(shè)備的特定端點(diǎn);③由USB設(shè)備驅(qū)動(dòng)程序遞交到USB 核心;④由USB核心遞交到特定設(shè)備的特定USB 主控制器驅(qū)動(dòng)程序;⑤由USB主控制器驅(qū)動(dòng)程序處理,從設(shè)備進(jìn)行USB 傳送;⑥當(dāng)urb結(jié)束之后,USB主控制器驅(qū)動(dòng)程序通知USB設(shè)備驅(qū)動(dòng)程序。

        urb可以在任何時(shí)刻被遞交該urb的驅(qū)動(dòng)程序取消掉,或者被USB核心取消,如果該設(shè)備已從系統(tǒng)中移除。urb被動(dòng)態(tài)地創(chuàng)建,它包含一個(gè)內(nèi)部引用計(jì)數(shù),使得它們可以在最后一個(gè)使用者釋放它們時(shí)自動(dòng)地銷(xiāo)毀。

        struct urb結(jié)構(gòu)體不能在驅(qū)動(dòng)程序中或者另一個(gè)結(jié)構(gòu)體中靜態(tài)地創(chuàng)建,因?yàn)檫@樣會(huì)破壞USB核心對(duì)urb所使用的引用計(jì)數(shù)機(jī)制。它必須使用usb_alloc_urb函數(shù)來(lái)創(chuàng)建。該函數(shù)原型如下:

        struct urb *usb_alloc_urb(int iso_packets, int mem_flags);

        第一個(gè)參數(shù)iso_packets是該urb應(yīng)該包含的等時(shí)數(shù)據(jù)包的數(shù)量。如果不打算創(chuàng)建等時(shí)urb,該值應(yīng)該設(shè)置為0。第二個(gè)參數(shù)mem_flags和傳遞給用于從內(nèi)核分配內(nèi)存的kmalloc函數(shù)的標(biāo)志有相同的類型。如果該函數(shù)成功地為urb分配了足夠的內(nèi)存空間,指向該urb的指針將被返回給調(diào)用函數(shù)。如果返回值為NULL,說(shuō)明USB核心內(nèi)發(fā)生了錯(cuò)誤,驅(qū)動(dòng)程序需要進(jìn)行適當(dāng)?shù)那謇怼?/p>

        當(dāng)一個(gè)urb被創(chuàng)建之后,在它可以被USB核心使用之前必須被正確地初始化。

        驅(qū)動(dòng)程序必須調(diào)用usb_free_urb函數(shù)來(lái)告訴USB核心驅(qū)動(dòng)程序已經(jīng)使用完urb。該函數(shù)只有一個(gè)參數(shù):

        void usb_free_urb(struct urb *urb);

        這個(gè)參數(shù)指向所需釋放的struct urb的指針。在該函數(shù)被調(diào)用之后,urb結(jié)構(gòu)體就消失了,驅(qū)動(dòng)程序不能再訪問(wèn)它。

        一旦urb被USB驅(qū)動(dòng)程序正確地創(chuàng)建和初始化之后,就可以提交到USB核心以發(fā)送到USB設(shè)備了。這是通過(guò)調(diào)用usb_submit_urb函數(shù)來(lái)完成的:

        int usb_submit_urb(struct urb *urb, int mem_flags);

        urb參數(shù)是指向即將被發(fā)送到設(shè)備的urb的指針。mem_flags參數(shù)等同于傳遞給kmalloc調(diào)用的同一個(gè)參數(shù),用于通知USB核心如何在此時(shí)及時(shí)地分配內(nèi)存緩沖區(qū)。

        當(dāng)一個(gè)urb被成功地提交到USB核心之后,在接收函數(shù)被調(diào)用之前不能訪問(wèn)該urb結(jié)構(gòu)體中的任何字段。因?yàn)閡sb_submit_urb函數(shù)可以在任何時(shí)刻調(diào)用(包括從一個(gè)中斷上下文中),mem_flags變量的內(nèi)容必須是正確的。其實(shí)只有三個(gè)有效的值可以被使用,取決于usb_submit_urb何時(shí)被調(diào)用:

        (1)GFP_ATOMIC

        只要下列條件成立就應(yīng)該使用該值:

        ①調(diào)用者是在一個(gè)urb結(jié)束處理例程、中斷處理例程、底半部、tasklet或者定時(shí)器回調(diào)函數(shù)中。

        ②調(diào)用者正持有一個(gè)自旋鎖或讀寫(xiě)鎖,注意如果持有了信號(hào)量,該值就不需要了。

        ③current->state不是TASK_RUNNING,該狀態(tài)永遠(yuǎn)是TASK_RUNNING,除非驅(qū)動(dòng)程序自己改變了當(dāng)前的狀態(tài)。

        (2)GFP_NOIO

        如果驅(qū)動(dòng)程序處于塊I/O路徑中應(yīng)該使用該值,在所有存儲(chǔ)類型的設(shè)備的錯(cuò)誤處理路徑中也應(yīng)該使用它。

        (3)GFP_KERNEL

        該值應(yīng)該在前述類別之外的所有情況中使用。

        1.3 USB驅(qū)動(dòng)寫(xiě)法

        在寫(xiě)USB驅(qū)動(dòng)前,首先需要確定當(dāng)前設(shè)備的一些基本信息,例如當(dāng)前設(shè)備屬于哪類設(shè)備,有哪些接口,每個(gè)接口有哪些端點(diǎn),設(shè)備、接口、端點(diǎn)、配置描述符的信息是什么,這些信息都可以通過(guò)軟件來(lái)獲取,常用軟件有windriver、USBtrace、bushound等,其中windriver不但可以看到設(shè)備的相關(guān)信息,還可以向設(shè)備發(fā)送標(biāo)準(zhǔn)請(qǐng)求,也可以直接向端點(diǎn)傳輸數(shù)據(jù),通過(guò)此工具也可以驗(yàn)證寫(xiě)好的驅(qū)動(dòng)通信是否正確。

        U盤(pán)一般提供4個(gè)端點(diǎn):一個(gè)控制端點(diǎn)、一個(gè)中斷端點(diǎn)、兩個(gè)批量端點(diǎn),進(jìn)入每個(gè)端點(diǎn)后就可以對(duì)各個(gè)端點(diǎn)進(jìn)行操作了,對(duì)于控制端點(diǎn)可以對(duì)其發(fā)送各種USB標(biāo)準(zhǔn)請(qǐng)求,這里就可以發(fā)送獲取描述符的請(qǐng)求了,對(duì)于兩個(gè)bulk端點(diǎn)可以直接對(duì)其進(jìn)行讀寫(xiě)。

        2 USB讀卡器驅(qū)動(dòng)的設(shè)計(jì)與實(shí)現(xiàn)

        2.1 獲取讀卡器信息

        剛剛拿到讀卡器,首先當(dāng)然是要獲取USB讀卡器的相關(guān)信息,通過(guò)工具USBtrace獲取各描述符信息如表1所列。

        表1 USBtrace獲取各描述符信息

        續(xù)表1

        從這張表中可以獲取到一些有用的信息,USB設(shè)備的venderID為0x3EB,deviceID為0x6124,設(shè)備有兩個(gè)接口,第一個(gè)接口的類型為0x2,即Communications and CDC Control,這是一個(gè)通信類的接口,子類型為0x2 (Abstract Control Model),這個(gè)接口提供了1個(gè)端點(diǎn),端點(diǎn)類型為中斷端點(diǎn),方向?yàn)閕n。第二個(gè)接口類型為0xa(CDC DATA),這個(gè)接口一般用于傳輸數(shù)據(jù),所以這個(gè)結(jié)構(gòu)提供2個(gè)bulk端點(diǎn),一個(gè)作為輸入,一個(gè)作為輸出。當(dāng)然每個(gè)設(shè)備都會(huì)有控制端點(diǎn),控制端點(diǎn)既可作為輸入又可作為輸出。每個(gè)端點(diǎn)都是最大允許傳輸數(shù)據(jù)大小,2個(gè)bulk端點(diǎn)最大可傳輸64 B,而中斷端點(diǎn)最大8 B。至此信息基本獲取完畢,開(kāi)始寫(xiě)驅(qū)動(dòng)。

        2.2 讀卡器驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)

        首先注冊(cè)u(píng)sb_driver到設(shè)備模型,前面講了是通過(guò)函數(shù)usb_register實(shí)現(xiàn)的,下面就是實(shí)現(xiàn)usb_driver了,在這里只實(shí)現(xiàn)了4個(gè)成員:id_table、probe、disconnect、name。id_table就是利用前面獲取的venderID、deviceID來(lái)判斷設(shè)備,probe和disconnect就是相應(yīng)的初始化和卸載函數(shù)。

        2.2.1 初始化、卸載設(shè)備

        初始化工作在probe函數(shù)中實(shí)現(xiàn),主要就是針對(duì)前面獲取的端點(diǎn)信息,對(duì)每個(gè)端點(diǎn)進(jìn)行初始化。首先要獲取設(shè)備的端點(diǎn),從設(shè)備描述符中看到設(shè)備有2個(gè)bulk端點(diǎn)和1個(gè)interrupt端點(diǎn)。Probe函數(shù)傳入的是當(dāng)前接口,即一個(gè)usb_interface結(jié)構(gòu)體,如何從usb_interface中獲取端點(diǎn)信息呢?在usb_interface結(jié)構(gòu)中有個(gè)成員cur_altsetting,表示當(dāng)前設(shè)置,這是一個(gè)usb_host_interface結(jié)構(gòu)體,其中又有一個(gè)成員endpoint,這是一個(gè)usb_host_endpoint結(jié)構(gòu)體的數(shù)組,每一個(gè)元素代表一個(gè)端點(diǎn),但這里不保存控制端點(diǎn),因?yàn)榭刂贫它c(diǎn)是被單獨(dú)保存在設(shè)備結(jié)構(gòu)體usb_device中的。

        找到每個(gè)端點(diǎn)后開(kāi)始為其創(chuàng)建相應(yīng)管道。USB通信中有4種端點(diǎn):控制、等時(shí)、中斷、批量,同時(shí)對(duì)應(yīng)4種傳輸方式,也對(duì)應(yīng)了4種管道,其中4種管道中又分in或out管道,內(nèi)核中提供了8個(gè)宏來(lái)創(chuàng)建管道,定義如下:

        #defineusb_sndctrlpipe(dev,endpoint)/*創(chuàng)建out控制管道*/

        ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))

        #defineusb_rcvctrlpipe(dev,endpoint)/*創(chuàng)建in控制管道*/

        ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)

        #defineusb_sndisocpipe(dev,endpoint)/*創(chuàng)建out等時(shí)管道*/

        ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))

        #defineusb_rcvisocpipe(dev,endpoint)/*創(chuàng)建in等時(shí)管道*/

        ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) |USB_DIR_IN)

        #defineusb_sndbulkpipe(dev,endpoint)/*創(chuàng)建out批量管道*/

        ((PIPE_BULK << 30) | __create_pipe(dev,endpoint))

        #defineusb_rcvbulkpipe(dev,endpoint)/*創(chuàng)建in批量管道*/

        ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)

        #defineusb_sndintpipe(dev,endpoint)/*創(chuàng)建out中斷管道*/

        ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))

        #defineusb_rcvintpipe(dev,endpoint)/*創(chuàng)建in中斷管道*/

        ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)

        其中__create_pipe也是一個(gè)宏,定義如下:

        static inline unsigned int __create_pipe(struct usb_device *dev,

        unsigned int endpoint){

        return (dev->devnum << 8) | (endpoint << 15);

        }

        從以上幾個(gè)宏可以知道管道的組成,其實(shí)管道就是提供了一個(gè)通信地址,讓HC知道這個(gè)urb包應(yīng)該發(fā)到哪個(gè)設(shè)備、哪個(gè)端點(diǎn)、是什么類型的包。在這里看到了4個(gè)宏,其中PIPE_ISOCHRONOUS就是標(biāo)志等時(shí)通道、PIPE_INTERRUPT就是中斷通道、PIPE_CONTROL就是控制通道、PIPE_BULK 就是BULK通道。

        在內(nèi)核里使用一個(gè)unsigned int類型的變量來(lái)表征一個(gè)pipe,其中8~14位是設(shè)備號(hào),即devnum,15~18位是端點(diǎn)號(hào),即endpoint。宏USB_DIR_IN用來(lái)在pipe里面標(biāo)志數(shù)據(jù)傳輸方向,一個(gè)管道要么只能輸入,要么只能輸出。在pipe里面,第7位(bit 7)是表征方向的。所以這里0x80也就是說(shuō)讓bit 7 為1,這就表示傳輸方向是由設(shè)備向主機(jī),也就是所謂的in,而如果這一位是0,就表示傳輸方向是由主機(jī)向設(shè)備的,也就是所謂的out。正是因?yàn)閁SB_DIR_OUT是0,而USB_DIR_IN是1,所以定義管道的時(shí)候只用到了USB_DIR_IN,而沒(méi)有用到USB_DIR_OUT,因?yàn)樗?,任何數(shù)和0相或都沒(méi)有意義。

        圖3 循環(huán)緩沖區(qū)

        接下來(lái)為每一個(gè)端點(diǎn)分配一個(gè)緩沖區(qū),這個(gè)緩沖區(qū)就是urb結(jié)構(gòu)體中的transfer_buffer,這個(gè)緩沖區(qū)就是傳輸過(guò)程中用來(lái)保存數(shù)據(jù)的,這時(shí)使用的分配函數(shù)是usb_buffer_alloc,這個(gè)函數(shù)的作用就是先分配一段內(nèi)存空間,然后對(duì)其進(jìn)行dma映射,就是從dma緩沖池分配一段內(nèi)存,即usb_hcd->pool[i]。

        最后將接口注冊(cè)到字符設(shè)備層,通過(guò)函數(shù)usb_register_dev實(shí)現(xiàn),由于客戶需要定位每個(gè)USB口,這里筆者做了一個(gè)封裝,做了一點(diǎn)點(diǎn)簡(jiǎn)單的改動(dòng),下面會(huì)講到。

        2.2.2 讀、寫(xiě)數(shù)據(jù)

        所謂讀、寫(xiě)設(shè)備就是實(shí)現(xiàn)file_operations中的read、write函數(shù)。

        這里的read、write就是實(shí)現(xiàn)對(duì)usb的讀、寫(xiě)數(shù)據(jù)和USB通信,這里在一個(gè)接口函數(shù)基礎(chǔ)上筆者做了一個(gè)簡(jiǎn)單的封裝,根據(jù)實(shí)際需求改進(jìn)了一點(diǎn)小地方,函數(shù)聲明如下:

        int usb_reader_bulk_msg(struct urb *urb, struct usb_reader_data *usb_reader, unsigned int pipe,void *data, int len,int *actual_length, int timeout);

        函數(shù)傳入7個(gè)參數(shù),第一個(gè)參數(shù)為需要發(fā)送的urb包,這個(gè)urb在probe函數(shù)中已分配好內(nèi)存,usb_reader就是讀卡器相關(guān)信息結(jié)構(gòu)體,這是為該驅(qū)動(dòng)專門(mén)定義的結(jié)構(gòu)體,data是傳輸數(shù)據(jù)的緩沖區(qū),len為希望傳輸多少數(shù)據(jù),actual_length為實(shí)際傳輸?shù)臄?shù)據(jù)大小,timeout為傳輸?shù)某瑫r(shí)值,若在timeout內(nèi)未完成傳輸則返回傳輸失敗。

        這個(gè)函數(shù)主要實(shí)現(xiàn)填充傳入的urb,主要填充管道、緩沖區(qū)、傳輸數(shù)據(jù)長(zhǎng)度、dma緩沖區(qū)、complete函數(shù)等成員,最后通過(guò)usb_submit_urb將urb提交到HC層做處理,usb_submit_urb在講HC層時(shí)已經(jīng)分析過(guò)了,這里只要提交過(guò)去就行了。

        在實(shí)現(xiàn)讀寫(xiě)函數(shù)時(shí),使用了一個(gè)4 096 B大小的循環(huán)緩沖區(qū),每次應(yīng)用程序調(diào)用write時(shí),先將應(yīng)用程序傳入的數(shù)據(jù)寫(xiě)到USB讀卡器,然后馬上從讀卡器上讀取返回?cái)?shù)據(jù),并將返回?cái)?shù)據(jù)寫(xiě)到緩沖區(qū)中。當(dāng)應(yīng)用程序調(diào)用read時(shí),將循環(huán)緩沖區(qū)的數(shù)據(jù)返回給用戶,而不是直接從設(shè)備讀取數(shù)據(jù)再返回。這樣處理的好處就是允許用戶進(jìn)行多次連續(xù)寫(xiě)入操作,最后只要通過(guò)一個(gè)讀取操作就能把前幾次寫(xiě)入操作的結(jié)果全部讀取出去。

        循環(huán)緩沖區(qū)寫(xiě)入時(shí)將數(shù)據(jù)存入數(shù)組的尾部,讀取時(shí)從數(shù)組的另一端開(kāi)始,當(dāng)寫(xiě)入數(shù)據(jù)到達(dá)數(shù)組的尾部時(shí),回到數(shù)組頭部繼續(xù)寫(xiě)。因此,一個(gè)循環(huán)緩沖區(qū)需要一個(gè)數(shù)組以及兩個(gè)索引值:一個(gè)用于下一個(gè)要寫(xiě)入的數(shù)據(jù)的位置,另一個(gè)用于指定下一個(gè)要從緩沖區(qū)中移走的位置。

        如圖3所示,這個(gè)緩存被定義成一個(gè)空情況,由讀寫(xiě)指針相同來(lái)指示, 而滿情況發(fā)生在寫(xiě)指針緊跟在讀指針后面的時(shí)候(小心解決繞回!)。

        2.2.3 ioctl函數(shù)

        這里還提供了一個(gè)ioctl接口,主要用于實(shí)現(xiàn)USB的標(biāo)準(zhǔn)請(qǐng)求,USB標(biāo)準(zhǔn)請(qǐng)求都是通過(guò)控制端點(diǎn)來(lái)實(shí)現(xiàn)的,控制端點(diǎn)的管道創(chuàng)建比較特殊,最后一個(gè)參數(shù)為0,創(chuàng)建函數(shù)如下:

        usb_rcvctrlpipe(usb_reader->dev, 0);

        usb_sndctrlpipe(usb_reader->dev, 0);

        標(biāo)準(zhǔn)請(qǐng)求和請(qǐng)求參數(shù)通過(guò)setup包傳送給USB設(shè)備,一個(gè)setup包由8個(gè)字節(jié)組成,在內(nèi)核中用usb_ctrlrequest結(jié)構(gòu)體表示,結(jié)構(gòu)體定義如下:

        struct usb_ctrlrequest{

        __u8bRequestType;

        __u8bRequest;

        __le16wValue;

        __le16wIndex;

        __le16wLength;

        } __attribute__((packed));

        usb_ctrlrequest被保存在urb->setup_packet里,共8個(gè)字節(jié),意義如下:

        byte0:bmRequestType,注意在剛才代碼中數(shù)據(jù)結(jié)構(gòu)struct ctrlrequest 里邊寫(xiě)的是bRequestType,但是它們對(duì)應(yīng)的是相同的內(nèi)容。而之所以USB協(xié)議里寫(xiě)成bmRequestType,是因?yàn)樗鼘?shí)際上又是一個(gè)位圖(m表示map),也就是說(shuō),盡管它只有1個(gè)字節(jié),但是仍然被當(dāng)作8位來(lái)用。

        USB協(xié)議定義了11個(gè)標(biāo)準(zhǔn)請(qǐng)求,各請(qǐng)求對(duì)應(yīng)setup包的各成員的值。

        每個(gè)標(biāo)準(zhǔn)請(qǐng)求對(duì)應(yīng)的代碼見(jiàn)表2,這個(gè)表對(duì)應(yīng)的代碼和內(nèi)核中為每個(gè)請(qǐng)求定義的宏是一一對(duì)應(yīng)的。

        對(duì)于DESCRIPTOR設(shè)置或獲取請(qǐng)求,需要填充一個(gè)描述符種類或索引,USB設(shè)備描述符對(duì)應(yīng)的索引見(jiàn)表3。

        表中列出了USB設(shè)備的5大描述符,USB設(shè)備的所有信息都保存在這些描述符中,在內(nèi)核中為這5大描述符分別定義了相應(yīng)的結(jié)構(gòu)體,分別是usb_device_descriptor、usb_config_descriptor、usb_string_descriptor、usb_interface_descriptor、usb_endpoint_descriptor,上面提到的一些標(biāo)準(zhǔn)請(qǐng)求就是圍繞這些結(jié)構(gòu)體來(lái)展開(kāi)的。

        表2 USB標(biāo)準(zhǔn)請(qǐng)求對(duì)應(yīng)代碼

        表3 設(shè)備描述符代碼

        結(jié) 語(yǔ)

        猜你喜歡
        描述符讀卡器驅(qū)動(dòng)程序
        基于結(jié)構(gòu)信息的異源遙感圖像局部特征描述符研究
        與淘汰命運(yùn)抗?fàn)帯】炊P記本的讀卡器
        Linux單線程并發(fā)服務(wù)器探索
        利用CNN的無(wú)人機(jī)遙感影像特征描述符學(xué)習(xí)
        基于EMV非接通信規(guī)范的非接觸讀卡器設(shè)計(jì)
        為二維碼識(shí)別的獻(xiàn)禮之作——評(píng)測(cè)平治二維碼門(mén)禁讀卡器
        MATLAB實(shí)現(xiàn)組態(tài)王中TCP/IP讀卡器監(jiān)控方法
        基于PDIUSBD12的USB接口設(shè)計(jì)應(yīng)用研究
        驅(qū)動(dòng)程序更新與推薦
        驅(qū)動(dòng)程序更新與推薦
        亚洲av成人波多野一区二区| 极品美女高潮喷白浆视频| 成人综合婷婷国产精品久久蜜臀| 中文字幕人妻久久久中出| 亚洲av本道一本二本三区| 射进去av一区二区三区| 亚洲三级视频一区二区三区| 末成年人av一区二区| 老熟女的中文字幕欲望| 男人天堂网2017| 欧美日韩精品乱国产| 国产大片黄在线观看| 正在播放强揉爆乳女教师| 成年女人黄小视频| 国产喷水1区2区3区咪咪爱av| 国产揄拍国产精品| a级国产乱理伦片在线播放| 国产在线不卡一区二区三区 | 欧美成人午夜精品久久久| 国产女人精品视频国产灰线| 国产美女自拍国语对白| 在线免费观看亚洲天堂av| 久久久精品国产亚洲av网不卡| 中文字幕色一区二区三区页不卡 | 中文字幕日韩欧美一区二区三区 | 亚洲欧美日韩国产精品一区| 国产自在自线午夜精品视频在| 两个人免费视频大全毛片| 在线无码免费看黄网站| 天堂av在线播放观看| 日本一区二区三级免费| 国产精品熟女一区二区三区| 国产一区二区视频免费在| 无码人妻久久一区二区三区蜜桃| 特级av毛片免费观看| 亚洲国产一区二区三区最新| 日本精品人妻在线观看| 国产精品区二区东京在线| 久久精品国产亚洲综合av| 精品国产三级a在线观看不卡| 丝袜人妻一区二区三区|