在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 消費(fèi)電子 > 新品快遞 > Linux環(huán)境下USB的原理、驅(qū)動和配置

            Linux環(huán)境下USB的原理、驅(qū)動和配置

            作者:北京中科紅旗軟件技術(shù)有限公司 嵌入式工程師 梁國軍 時(shí)間:2007-10-23 來源:CSDN 收藏

               隨著生活水平的提高,人們對設(shè)備的使用也越來越多,鑒于在硬件配置上尚不能全部即插即用,因此關(guān)于如何配置和使用,成為困擾我們的一大問題。

            本文引用地址:http://www.biyoush.com/article/70029.htm

            linux文章專題:linux詳解(linux不再難懂)

               什么是

               是英文Universal Serial Bus的縮寫,意為通用串行總線。USB最初是為了替代許多不同的低速總線(包括并行、串行和鍵盤連接)而設(shè)計(jì)的,它以單一類型的總線連接各種不同的類型的設(shè)備。USB的發(fā)展已經(jīng)超越了這些低速的連接方式,它現(xiàn)在可以支持幾乎所有可以連接到PC上的設(shè)備。最新的USB規(guī)范修訂了理論上高達(dá)480Mbps的高速連接。內(nèi)核支持兩種主要類型的USB驅(qū)動程序:宿主系統(tǒng)上的驅(qū)動程序和設(shè)備上的驅(qū)動程序,從宿主的觀點(diǎn)來看(一個(gè)普通的宿主也就是一個(gè)PC機(jī)),宿主系統(tǒng)的USB設(shè)備驅(qū)動程序控制插入其中的USB設(shè)備,而USB設(shè)備的驅(qū)動程序控制該設(shè)備如何作為一個(gè)USB設(shè)備和主機(jī)通信。

               USB的具體構(gòu)成

               在動手寫USB驅(qū)動程序這前,讓我們先看看寫的USB驅(qū)動程序在內(nèi)核中的結(jié)構(gòu),如下圖:


               USB驅(qū)動程序存在于不同的內(nèi)核子系統(tǒng)和USB硬件控制器之間,USB核心為USB驅(qū)動程序提供了一個(gè)用于訪問和控制USB硬件的接口,而不必考慮系統(tǒng)當(dāng)前存在的各種不同類型的USB硬件控制器。USB是一個(gè)非常復(fù)雜的設(shè)備,linux內(nèi)核為我們提供了一個(gè)稱為USB的核心的子系統(tǒng)來處理大部分的復(fù)雜性,USB設(shè)備包括配置(configuration)、接口(interface)和端點(diǎn)(endpoint),USB設(shè)備綁定到接口上,而不是整個(gè)USB設(shè)備。如下圖所示:

               USB通信最基本的形式是通過端點(diǎn)(USB端點(diǎn)分中斷、批量、等時(shí)、控制四種,每種用途不同),USB端點(diǎn)只能往一個(gè)方向傳送數(shù)據(jù),從主機(jī)到設(shè)備或者從設(shè)備到主機(jī),端點(diǎn)可以看作是單向的管道(pipe)。所以我們可以這樣認(rèn)為:設(shè)備通常具有一個(gè)或者更多的配置,配置經(jīng)常具有一個(gè)或者更多的接口,接口通常具有一個(gè)或者更多的設(shè)置,接口沒有或具有一個(gè)以上的端點(diǎn)。驅(qū)動程序把驅(qū)動程序?qū)ο笞缘経SB子系統(tǒng)中,稍后再使用制造商和設(shè)備標(biāo)識來判斷是否已經(jīng)安裝了硬件。USB核心使用一個(gè)列表(是一個(gè)包含制造商ID和設(shè)備號ID的一個(gè)結(jié)構(gòu)體)來判斷對于一個(gè)設(shè)備該使用哪一個(gè)驅(qū)動程序,熱插撥腳本使用它來確定當(dāng)一個(gè)特定的設(shè)備插入到系統(tǒng)時(shí)該自動裝載哪一個(gè)驅(qū)動程序。

               上面我們簡要說明了驅(qū)動程序的基本理論,在寫一個(gè)設(shè)備驅(qū)動程序之前,我們還要了解以下兩個(gè)概念:模塊和設(shè)備文件。

               模塊:是在內(nèi)核空間運(yùn)行的程序,實(shí)際上是一種目標(biāo)對象文件,沒有鏈接,不能獨(dú)立運(yùn)行,但是可以裝載到系統(tǒng)中作為內(nèi)核的一部分運(yùn)行,從而可以動態(tài)擴(kuò)充內(nèi)核的功能。模塊最主要的用處就是用來實(shí)現(xiàn)設(shè)備驅(qū)動程序。Linux下對于一個(gè)硬件的驅(qū)動,可以有兩種方式:直接加載到內(nèi)核代碼中,啟動內(nèi)核時(shí)就會驅(qū)動此硬件設(shè)備。另一種就是以模塊方式,編譯生成一個(gè).ko文件(在2.4以下內(nèi)核中是用.o作模塊文件,我們以2.6的內(nèi)核為準(zhǔn),以下同)。當(dāng)應(yīng)用程序需要時(shí)再加載到內(nèi)核空間運(yùn)行。所以我們所說的一個(gè)硬件的驅(qū)動程序,通常指的就是一個(gè)驅(qū)動模塊。

               設(shè)備文件:對于一個(gè)設(shè)備,它可以在/dev下面存在一個(gè)對應(yīng)的邏輯設(shè)備節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)以文件的形式存在,但它不是普通意義上的文件,它是設(shè)備文件,更確切的說,它是設(shè)備節(jié)點(diǎn)。這個(gè)節(jié)點(diǎn)是通過mknod命令建立的,其中指定了主設(shè)備號和次設(shè)備號。主設(shè)備號表明了某一類設(shè)備,一般對應(yīng)著確定的驅(qū)動程序;次設(shè)備號一般是區(qū)分不同屬性,例如不同的使用方法,不同的位置,不同的操作。這個(gè)設(shè)備號是從/proc/devices文件中獲得的,所以一般是先有驅(qū)動程序在內(nèi)核中,才有設(shè)備節(jié)點(diǎn)在目錄中。這個(gè)設(shè)備號(特指主設(shè)備號)的主要作用,就是聲明設(shè)備所使用的驅(qū)動程序。驅(qū)動程序和設(shè)備號是一一對應(yīng)的,當(dāng)你打開一個(gè)設(shè)備文件時(shí),就已經(jīng)知道這個(gè)設(shè)備所對應(yīng)的驅(qū)動程序。對于一個(gè)硬件,Linux是這樣來進(jìn)行驅(qū)動的:首先,我們必須提供一個(gè).ko的驅(qū)動模塊文件。我們要使用這個(gè)驅(qū)動程序,首先要加載它,我們可以用insmod xxx.ko,這樣驅(qū)動就會根據(jù)自己的類型(字符設(shè)備類型或塊設(shè)備類型,例如鼠標(biāo)就是字符設(shè)備而硬盤就是塊設(shè)備)向系統(tǒng)注冊,注冊成功系統(tǒng)會反饋一個(gè)主設(shè)備號,這個(gè)主設(shè)備號就是系統(tǒng)對它的唯一標(biāo)識。驅(qū)動就是根據(jù)此主設(shè)備號來創(chuàng)建一個(gè)一般放置在/dev目錄下的設(shè)備文件。在我們要訪問此硬件時(shí),就可以對設(shè)備文件通過open、read、write、close等命令進(jìn)行。而驅(qū)動就會接收到相應(yīng)的read、write操作而根據(jù)自己的模塊中的相應(yīng)函數(shù)進(jìn)行操作了。

               USB驅(qū)動程序如何應(yīng)用

               了解了上述理論后,我們就可以動手寫驅(qū)動程序,如果你基本功好,而且寫過linux下的硬件驅(qū)動,USB的硬件驅(qū)動和pci_driver很類似,那么寫USB的驅(qū)動就比較簡單了,如果你只是大體了解了linux的硬件驅(qū)動,那也不要緊,因?yàn)樵趌inux的內(nèi)核源碼中有一個(gè)框架程序可以拿來借用一下,這個(gè)框架程序在/usr/src/~(你的內(nèi)核版本,以下同)/drivers/usb下,文件名為usb-skeleton.c。寫一個(gè)USB的驅(qū)動程序最基本的要做四件事:驅(qū)動程序要支持的設(shè)備、注冊USB驅(qū)動程序、探測和斷開、提交和控制urb(USB請求塊)(當(dāng)然也可以不用urb來傳輸數(shù)據(jù),下文我們會說到)。

               驅(qū)動程序支持的設(shè)備:有一個(gè)結(jié)構(gòu)體struct usb_device_id,這個(gè)結(jié)構(gòu)體提供了一列不同類型的該驅(qū)動程序支持的USB設(shè)備,對于一個(gè)只控制一個(gè)特定的USB設(shè)備的驅(qū)動程序來說,struct usb_device_id表被定義為:

            /* 驅(qū)動程序支持的設(shè)備列表 */

            static struct usb_device_id skel_table [] = {

                  { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },

                  { }                               /* 終止入口 */

            };

                   MODULE_DEVICE_TABLE (usb, skel_table);

               對于PC驅(qū)動程序,MODULE_DEVICE_TABLE是必需的,而且usb必需為該宏的第一個(gè)值,而USB_SKEL_VENDOR_ID和USB_SKEL_PRODUCT_ID就是這個(gè)特殊設(shè)備的制造商和產(chǎn)品的ID了,我們在程序中把定義的值改為我們這款USB的,如:

                   /* 定義制造商和產(chǎn)品的ID號 */

            #define USB_SKEL_VENDOR_ID       0x1234

            #define USB_SKEL_PRODUCT_ID     0x2345

               這兩個(gè)值可以通過命令lsusb,當(dāng)然你得先把USB設(shè)備先插到主機(jī)上了?;蛘卟榭磸S商的USB設(shè)備的手冊也能得到,在我機(jī)器上運(yùn)行l(wèi)susb是這樣的結(jié)果:

            Bus 004 Device 001: ID 0000:0000  

            Bus 003 Device 002: ID 1234:2345  Abc  Corp.  

            Bus 002 Device 001: ID 0000:0000  

            Bus 001 Device 001: ID 0000:0000

                得到這兩個(gè)值后把它定義到程序里就可以了。

               注冊USB驅(qū)動程序:所有的USB驅(qū)動程序都必須創(chuàng)建的結(jié)構(gòu)體是struct usb_driver。這個(gè)結(jié)構(gòu)體必須由USB驅(qū)動程序來填寫,包括許多回調(diào)函數(shù)和變量,它們向USB核心代碼描述USB驅(qū)動程序。創(chuàng)建一個(gè)有效的struct usb_driver結(jié)構(gòu)體,只須要初始化五個(gè)字段就可以了,在框架程序中是這樣的:

            static struct usb_driver skel_driver = {

                  .owner = THIS_MODULE,

                  .name =          "skeleton",

                  .probe =  skel_probe,

                  .disconnect =  skel_disconnect,

                  .id_table =      skel_table,

            };

               struct module *owner :指向該驅(qū)動程序的模塊所有者的批針。USB核心使用它來正確地對該USB驅(qū)動程序進(jìn)行引用計(jì)數(shù),使它不會在不合適的時(shí)刻被卸載掉,這個(gè)變量應(yīng)該被設(shè)置為THIS_MODULE宏。

               const char *name:指向驅(qū)動程序名字的指針,在內(nèi)核的所有USB驅(qū)動程序中它必須是唯一的,通常被設(shè)置為和驅(qū)動程序模塊名相同的名字。 {{分頁}}

               int (*probe) (struct usb_interface *intf,const struct usb_device_id *id):這個(gè)是指向USB驅(qū)動程序中的探測函數(shù)的指針。當(dāng)USB核心認(rèn)為它有一個(gè)接口(usb_interface)可以由該驅(qū)動程序處理時(shí),這個(gè)函數(shù)被調(diào)用。

               void (disconnect)(struct usb_interface *intf):指向USB驅(qū)動程序中的斷開函數(shù)的指針,當(dāng)一個(gè)USB接口(usb_interface)被從系統(tǒng)中移除或者驅(qū)動程序正在從USB核心中卸載時(shí),USB核心將調(diào)用這個(gè)函數(shù)。

               const struct usb_device_id *id_table:指向ID設(shè)備表的指針,這個(gè)表包含了一列該驅(qū)動程序可以支持的USB設(shè)備,如果沒有設(shè)置這個(gè)變量,USB驅(qū)動程序中的探測回調(diào)函數(shù)就不會被調(diào)用。

               在這個(gè)結(jié)構(gòu)體中還有其它的幾個(gè)回調(diào)函數(shù)不是很常用,這里就不一一說明了。以struct usb_driver 指針為參數(shù)的usb_register_driver函數(shù)調(diào)用把struct usb_driver注冊到USB核心。一般是在USB驅(qū)動程序的模塊初始化代碼中完成這個(gè)工作的:

            static int __init usb_skel_init(void)

            {

                  int result;


                  /* 驅(qū)動程序注冊到USB子系統(tǒng)中*/

                  result = usb_register(&skel_driver);

                  if (result)

                         err("usb_register failed. Error number %d", result);


                  return result;

            }

               當(dāng)USB驅(qū)動程序?qū)⒁恍堕_時(shí),需要把struct usb_driver從內(nèi)核中注銷。通過調(diào)用usb_deregister_driver來完成這個(gè)工作,當(dāng)調(diào)用發(fā)生時(shí),當(dāng)前綁定到該驅(qū)動程序上的任何USB接口都被斷開,斷開函數(shù)將被調(diào)用:

            static void __exit usb_skel_exit(void)

            {

                  /* 從子系統(tǒng)注銷驅(qū)動程序 */

                  usb_deregister(&skel_driver);

            }


               探測和斷開:當(dāng)一個(gè)設(shè)備被安裝而USB核心認(rèn)為該驅(qū)動程序應(yīng)該處理時(shí),探測函數(shù)被調(diào)用,探測函數(shù)檢查傳遞給它的設(shè)備信息,確定驅(qū)動程序是否真的適合該設(shè)備。當(dāng)驅(qū)動程序因?yàn)槟撤N原因不應(yīng)該控制設(shè)備時(shí),斷開函數(shù)被調(diào)用,它可以做一些清理工作。探測回調(diào)函數(shù)中,USB驅(qū)動程序初始化任何可能用于控制USB設(shè)備的局部結(jié)構(gòu)體,它還把所需的任何設(shè)備相關(guān)信息保存到一個(gè)局部結(jié)構(gòu)體中,下面是探測函數(shù)的部分源碼,我們加以分析。

                   /* 設(shè)置端點(diǎn)信息 */

                  /* 只使用第一個(gè)批量IN和批量OUT端點(diǎn) */

                  iface_desc = interface->cur_altsetting;

                  for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {

                         endpoint = &iface_desc->endpoint[i].desc;


                         if (!dev->bulk_in_endpointAddr &&

                             (endpoint->bEndpointAddress & USB_DIR_IN) &&

                             ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)

                                              == USB_ENDPOINT_XFER_BULK)) {

                                /* 找到一個(gè)批量IN端點(diǎn) */

                                buffer_size = endpoint->wMaxPacketSize;

                                dev->bulk_in_size = buffer_size;

                                dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;

                                dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);

                                if (!dev->bulk_in_buffer) {

                                       err("Could not allocate bulk_in_buffer");

                                       goto error;

                                }

                         }


                         if (!dev->bulk_out_endpointAddr &&

                             !(endpoint->bEndpointAddress & USB_DIR_IN) &&

                             ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)

                                              == USB_ENDPOINT_XFER_BULK)) {

                                /* 找到一個(gè)批量OUT端點(diǎn) */

                                dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;

                         }

                  }

                  if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {

                         err("Could not find both bulk-in and bulk-out endpoints");

                         goto error;

                  }

               在探測函數(shù)里,這個(gè)循環(huán)首先訪問該接口中存在的每一個(gè)端點(diǎn),給該端點(diǎn)一個(gè)局部指針以便以后訪問:


            for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {

                         endpoint = &iface_desc->endpoint[i].desc;

               在一輪探測過后,我們就有了一個(gè)端點(diǎn),在還沒有發(fā)現(xiàn)批量IN類型的端點(diǎn)時(shí),探測該端點(diǎn)方向是否為IN,這可以通過檢查USB_DIR_IN是否包含在bEndpointAddress端點(diǎn)變量有確定,如果是的話,我們在探測該端點(diǎn)類型是否為批量,先用USB_ENDPOINT_XFERTYPE_MASK位掩來取bmAttributes變量的值,然后探測它是否和USB_ENDPOINT_XFER_BULK值匹配:


                         if (!dev->bulk_out_endpointAddr &&

                             !(endpoint->bEndpointAddress & USB_DIR_IN) &&

                             ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)

                                              == USB_ENDPOINT_XFER_BULK))

               如果所有這些探測都通過了,驅(qū)動程序就知道它已經(jīng)發(fā)現(xiàn)了正確的端點(diǎn)類型,可以把該端點(diǎn)的相關(guān)信息保存到一個(gè)局部結(jié)構(gòu)體中以便稍后用它來和端點(diǎn)進(jìn)行通信:


                                /* 找到一個(gè)批量IN類型的端點(diǎn) */

                                buffer_size = endpoint->wMaxPacketSize;

                                dev->bulk_in_size = buffer_size;

                                dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;

                                dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);

                                if (!dev->bulk_in_buffer) {

                                       err("Could not allocate bulk_in_buffer");

                                       goto error;

                                }

               因?yàn)閁SB驅(qū)動程序要在設(shè)備的生命周期的稍后時(shí)間獲取和接口相關(guān)聯(lián)的局部數(shù)據(jù)結(jié)構(gòu)體,所以調(diào)用了usb_set_intfdata函數(shù),把它保存到struct usb_interface結(jié)構(gòu)體中以便后面的訪問


                  /* 把數(shù)據(jù)指針保存到這個(gè)接口設(shè)備中 */

                  usb_set_intfdata(interface, dev);

               我們以后調(diào)用usb_set_intfdata函數(shù)來獲取數(shù)據(jù)。當(dāng)這一切都完成后,USB驅(qū)動程序必須在探測函數(shù)中調(diào)用usb_register_dev函數(shù)來把該設(shè)備注冊到USB核心里:


                  /* 注冊設(shè)備到USB核心 */

                  retval = usb_register_dev(interface, &skel_class);

                  if (retval) {

                         /* 有些情況下是不允許注冊驅(qū)動程序的 */

                         err("Not able to get a minor for this device.");

                         usb_set_intfdata(interface, NULL);

                         goto error;

                  }

               當(dāng)一個(gè)USB設(shè)備被斷開時(shí),和該設(shè)備相關(guān)聯(lián)的所有資源都應(yīng)該被盡可能的清理掉,在此時(shí),如果已在在探測函數(shù)中調(diào)用了注冊函數(shù)來為該USB設(shè)備分配了一個(gè)次設(shè)備號話,必須調(diào)用usb_deregister_dev函數(shù)來把次設(shè)備號交還給USB核心。在斷開函數(shù)中,從接口獲取之前調(diào)用usb_set_intfdata設(shè)置的任何數(shù)據(jù)也是很重要的。然后設(shè)置struct usb_interface結(jié)構(gòu)體中的數(shù)據(jù)指針為NULL,以防任何不適當(dāng)?shù)膶υ摂?shù)據(jù)的錯(cuò)誤訪問。

               在探測函數(shù)中會對每一個(gè)接口進(jìn)行一次探測,所以我們在寫USB驅(qū)動程序的時(shí)候,只要做好第一個(gè)端點(diǎn),其它的端點(diǎn)就會自動完成探測。在探測函數(shù)中我們要注意的是在內(nèi)核中用結(jié)構(gòu)體struct usb_host_endpoint來描述USB端點(diǎn),這個(gè)結(jié)構(gòu)體在另一個(gè)名為struct usb_endpoint_descriptor的結(jié)構(gòu)體中包含了真正的端點(diǎn)信息,struct usb_endpoint_descriptor結(jié)構(gòu)體包含了所有的USB特定的數(shù)據(jù),該結(jié)構(gòu)體中我們要關(guān)心的幾個(gè)字段是:

               bEndpointAddress:這個(gè)是特定的USB地址,可以結(jié)合USB_DIR_IN和USB_DIR_OUT來使用,以確定該端點(diǎn)的數(shù)據(jù)是傳向設(shè)備還是主機(jī)。

               bmAttributes:這個(gè)是端點(diǎn)的類型,這個(gè)值可以結(jié)合位掩碼USB_ENDPOINT_XFERTYPE_MASK來使用,以確定此端點(diǎn)的類型是USB_ENDPOINT_XFER_ISOC(等時(shí))、USB_ENDPOINT_XFER_BULK(批量)、USB_ENDPOINT_XFER_INT的哪一種。

               wMaxPacketSize:這個(gè)是端點(diǎn)一次可以處理的最大字節(jié)數(shù),驅(qū)動程序可以發(fā)送數(shù)量大于此值的數(shù)據(jù)到端點(diǎn),在實(shí)際傳輸中,數(shù)據(jù)量如果大于此值會被分割。

               bInterval:這個(gè)值只有在端點(diǎn)類型是中斷類型時(shí)才起作用,它是端點(diǎn)中斷請求的間隔時(shí)間,以毫秒為單位。 {{分頁}}

               提交和控制urb:當(dāng)驅(qū)動程序有數(shù)據(jù)要發(fā)送到USB設(shè)備時(shí)(大多數(shù)情況是在驅(qū)動程序的寫函數(shù)中),要分配一個(gè)urb來把數(shù)據(jù)傳輸給設(shè)備:

                 /* 創(chuàng)建一個(gè)urb,并且給它分配一個(gè)緩存*/

                  urb = usb_alloc_urb(0, GFP_KERNEL);

                  if (!urb) {

                         retval = -ENOMEM;

                         goto error;

                  }

               當(dāng)urb被成功分配后,還要創(chuàng)建一個(gè)DMA緩沖區(qū)來以高效的方式發(fā)送數(shù)據(jù)到設(shè)備,傳遞給驅(qū)動程序的數(shù)據(jù)要復(fù)制到這塊緩沖中去:

                  buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);

                  if (!buf) {

                         retval = -ENOMEM;

                         goto error;

                  }


                  if (copy_from_user(buf, user_buffer, count)) {

                         retval = -EFAULT;

                         goto error;

                  }

                當(dāng)數(shù)據(jù)從用戶空間正確復(fù)制到局部緩沖區(qū)后,urb必須在可以被提交給USB核心之前被正確初始化:


                  /* 初始化urb */

                  usb_fill_bulk_urb(urb, dev->udev,

                                  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),

                                  buf, count, skel_write_bulk_callback, dev);

                  urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

                然后urb就可以被提交給USB核心以傳輸?shù)皆O(shè)備了:

                  /* 把數(shù)據(jù)從批量OUT端口發(fā)出 */

                  retval = usb_submit_urb(urb, GFP_KERNEL);

                  if (retval) {

                         err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);

                         goto error;

                  }

               當(dāng)urb被成功傳輸?shù)経SB設(shè)備之后,urb回調(diào)函數(shù)將被USB核心調(diào)用,在我們的例子中,我們初始化urb,使它指向skel_write_bulk_callback函數(shù),以下就是該函數(shù):

            static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)

            {

                  struct usb_skel *dev;


                  dev = (struct usb_skel *)urb->context;


                  if (urb->status &&  

                      !(urb->status == -ENOENT ||  

                        urb->status == -ECONNRESET ||

                        urb->status == -ESHUTDOWN)) {

                         dbg("%s - nonzero write bulk status received: %d",

                             __FUNCTION__, urb->status);

                  }


                  /* 釋放已分配的緩沖區(qū) */

                  usb_buffer_free(urb->dev, urb->transfer_buffer_length,  

                                urb->transfer_buffer, urb->transfer_dma);

            }

               有時(shí)候USB驅(qū)動程序只是要發(fā)送或者接收一些簡單的數(shù)據(jù),驅(qū)動程序也可以不用urb來進(jìn)行數(shù)據(jù)的傳輸,這是里涉及到兩個(gè)簡單的接口函數(shù):usb_bulk_msg和usb_control_msg ,在這個(gè)USB框架程序里讀操作就是這樣的一個(gè)應(yīng)用:

                    /* 進(jìn)行阻塞的批量讀以從設(shè)備獲取數(shù)據(jù) */

                  retval = usb_bulk_msg(dev->udev,

                                      usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),

                                      dev->bulk_in_buffer,

                                      min(dev->bulk_in_size, count),

                                      &count, HZ*10);


                          /*如果讀成功,復(fù)制到用戶空間 */

                  if (!retval) {

                         if (copy_to_user(buffer, dev->bulk_in_buffer, count))

                                retval = -EFAULT;

                         else

                  &n

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

            linux相關(guān)文章:linux教程




            關(guān)鍵詞: Linux USB 操作系統(tǒng)

            評論


            相關(guān)推薦

            技術(shù)專區(qū)

            關(guān)閉