版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、Linux USB驅(qū)動框架分析(一)事實(shí)上,Linux的設(shè)備驅(qū)動都遵循一個慣例表征驅(qū)動程序(用driver更貼切一些,應(yīng)該稱為驅(qū)動器比較好吧)的結(jié)構(gòu)體,結(jié)構(gòu)體里面應(yīng)該包含了驅(qū)動程序所需要的所有資源。用OO的術(shù)語來說,就是這個驅(qū)動器對象所擁有的屬性及成員。由于Linux的內(nèi)核用c來編寫,所以我們也按照這種結(jié)構(gòu)化的思想來分析代碼,但我還是希望從OO的角度來闡述這些細(xì)節(jié)。這個結(jié)構(gòu)體的名字有驅(qū)動開發(fā)人員決定,比如說,鼠標(biāo)可能有一個叫做mouse_dev的struct,鍵盤可能由一個keyboard_dev的struct(dev for device,我們做的只是設(shè)備驅(qū)動)。而這次我們來分析一下Linu
2、x內(nèi)核源碼中的一個usb-skeleton(就是usb驅(qū)動的骨架咯),自然,他定義的設(shè)備結(jié)構(gòu)體就叫做usb-skel:struct usb_skel struct usb_device *udev; /* the usb device for this device */ struct usb_interface * interface; /* the interface for this device */ struct semaphore limit_sem; /* limiting the number of writes in progress */ unsigned char * b
3、ulk_in_buffer; /* the buffer to receive data */ size_t bulk_in_size; /* the size of the receive buffer */ _u8 bulk_in_endpointAddr;/* the address of the bulk in endpoint */ _u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ struct kref kref; 這里我們得補(bǔ)充說明一下一些USB的協(xié)議規(guī)范細(xì)節(jié)。USB能夠自動監(jiān)測設(shè)備,并調(diào)用
4、相應(yīng)的驅(qū)動程序處理設(shè)備,所以其規(guī)范實(shí)際上是相當(dāng)復(fù)雜的,幸好,我們不必理會大部分細(xì)節(jié)問題,因?yàn)長inux已經(jīng)提供相應(yīng)的解決方案。就我現(xiàn)在的理解來說,USB的驅(qū)動分為兩塊,一塊是USB的bus驅(qū)動,這個東西,Linux內(nèi)核已經(jīng)做好了,我們可以不管,但我們至少要了解他的功能。形象得說,USB的bus驅(qū)動相當(dāng)于鋪出一條路來,讓所有的信息都可以通過這條USB通道到達(dá)該到的地方,這部分工作由usb_core來完成。當(dāng)設(shè)備接到USB接口時,usb_core就檢測該設(shè)備的一些信息,例如生產(chǎn)廠商ID和產(chǎn)品的ID,或者是設(shè)備所屬的class、subclass跟protocol,以便確定應(yīng)該調(diào)用哪一個驅(qū)動處理該設(shè)備
5、。里面復(fù)雜細(xì)節(jié)我們不用管,我們要做的是另一塊工作usb的設(shè)備驅(qū)動。也就是說,我們就等著usb_core告訴我們要工作了,我們才工作。對于usb規(guī)范定義的設(shè)備,他們有一個設(shè)備的框架,對于開發(fā)人員來說,他大概如圖所示: 從開發(fā)人員的角度看,每一個usb設(shè)備有若干個配置(configuration)組成,每個配置又可以有多個接口(interface),每個接口又有多個設(shè)置(setting圖中沒有給出),而接口本身可能沒有端點(diǎn)或者多個端點(diǎn)(endpoint)。USB的數(shù)據(jù)交換通過端點(diǎn)來進(jìn)行,主機(jī)與各個端點(diǎn)之間建立起單向的管道來傳輸數(shù)據(jù)。而這些接口可以分為四類: 控制(control)用于配置設(shè)備、獲取
6、設(shè)備信息、發(fā)送命令或者獲取設(shè)備的狀態(tài)報告 中斷(interrupt)當(dāng)USB宿主要求設(shè)備傳輸數(shù)據(jù)時,中斷端點(diǎn)會以一個固定的速率傳送少量數(shù)據(jù),還用于發(fā)送數(shù)據(jù)到USB設(shè)備以控制設(shè)備,一般不用于傳送大量數(shù)據(jù)。 批量(bulk)用于大量數(shù)據(jù)的可靠傳輸,如果總線上的空間不足以發(fā)送整個批量包,它會被分割成多個包傳輸。 等時(isochronous)大量數(shù)據(jù)的不可靠傳輸,不保證數(shù)據(jù)的到達(dá),但保證恒定的數(shù)據(jù)流,多用于數(shù)據(jù)采集。 Linux中用struct usb_host_endpoint來描述USB端點(diǎn),每個usb_host_endpoint中包含一個struct usb_endpoint_descript
7、or結(jié)構(gòu)體,當(dāng)中包含該端點(diǎn)的信息以及設(shè)備自定義的各種信息,這些信息包括:bEndpointAddress(b for byte)8位端點(diǎn)地址,其地址還隱藏了端點(diǎn)方向的信息(之前說過,端點(diǎn)是單向的),可以用掩碼USB_DIR_OUT和USB_DIR_IN來確定。bmAttributes端點(diǎn)的類型,結(jié)合USB_ENDPOINT_XFERTYPE_MASK可以確定端點(diǎn)是USB_ENDPOINT_XFER_ISOC(等時)、USB_ENDPOINT_XFER_BULK(批量)還是USB_ENDPOINT_XFER_INT(中斷)。wMaxPacketSize端點(diǎn)一次處理的最大字節(jié)數(shù)。發(fā)送的BULK包可
8、以大于這個數(shù)值,但會被分割傳送。bInterval如果端點(diǎn)是中斷類型,該值是端點(diǎn)的間隔設(shè)置,以毫秒為單位。 在邏輯上,一個USB設(shè)備的功能劃分是通過接口來完成的。比如說一個USB揚(yáng)聲器,可能會包括有兩個接口:一個用于鍵盤控制,另外一個用于音頻流傳輸。而事實(shí)上,這種設(shè)備需要用到不同的兩個驅(qū)動程序來操作,一個控制鍵盤,一個控制音頻流。但也有例外,比如藍(lán)牙設(shè)備,要求有兩個接口,第一用于ACL跟EVENT的傳輸,另外一個用于SCO鏈路,但兩者通過一個驅(qū)動控制。在Linux上,接口使用struct usb_interface來描述,以下是該結(jié)構(gòu)體中比較重要的字段:struct usb_host_inte
9、rface *altsetting(注意不是usb_interface)其實(shí)據(jù)我理解,他應(yīng)該是每個接口的設(shè)置,雖然名字上有點(diǎn)奇怪。該字段是一個設(shè)置的數(shù)組(一個接口可以有多個設(shè)置),每個usb_host_interface都包含一套由struct usb_host_endpoint定義的端點(diǎn)配置。但這些配置次序是不定的。unsigned num_altstting可選設(shè)置的數(shù)量,即altsetting所指數(shù)組的元素個數(shù)。struct usb_host_interface *cur_altsetting當(dāng)前活動的設(shè)置,指向altsetting數(shù)組中的一個。int minor當(dāng)捆綁到該接口的USB驅(qū)
10、動程序使用USB主設(shè)備號時,USB core分配的次設(shè)備號。僅在成功調(diào)用usb_register_dev之后才有效。除了它可以用struct usb_host_config來描述之外,到現(xiàn)在為止,我對配置的了解不多。而整個USB設(shè)備則可以用struct usb_device來描述,但基本上只會用它來初始化函數(shù)的接口,真正用到的應(yīng)該是我們之前所提到的自定義的一個結(jié)構(gòu)體。Linux USB驅(qū)動框架分析(二)好,了解過USB一些規(guī)范細(xì)節(jié)之后,我們現(xiàn)在來看看Linux的驅(qū)動框架。事實(shí)上,Linux的設(shè)備驅(qū)動,特別是這種hotplug的USB設(shè)備驅(qū)動,會被編譯成模塊,然后在需要時掛在到內(nèi)核。要寫一個Li
11、nux的模塊并不復(fù)雜,以一個helloworld為例:#include#includeMODULE_LICENSE(“GPL”);static int hello_init(void) printk(KERN_ALERT “Hello World!n”); return 0;static int hello_exit(void) printk(KERN_ALERT “GOODBYE!n”);module_init(hello_init);module_exit(hello_exit); 這個簡單的程序告訴大家應(yīng)該怎么寫一個模塊,MODULE_LICENSE告訴內(nèi)核該模塊的版權(quán)信息,很多情況下,
12、用GPL或者BSD,或者兩個,因?yàn)橐粋€私有模塊一般很難得到社區(qū)的幫助。module_init和module_exit用于向內(nèi)核注冊模塊的初始化函數(shù)和模塊退出函數(shù)。如程序所示,初始化函數(shù)是hello_init,而退出函數(shù)是hello_exit。 另外,要編譯一個模塊通常還需要用到內(nèi)核源碼樹種的makefile,所以模塊的Makefile可以寫成:ifneq ($(KERNELRELEASE),)obj-m:= hello.o#usb-dongle.oelseKDIR:= /usr/src/linux-headers-$(shell uname -r)BDIR:= $(shell pwd)defa
13、ult: $(MAKE) -C $(KDIR) M=$(PWD) modules.PHONY: cleanclean: make -C $(KDIR) M=$(BDIR) cleanendif可以用insmod跟rmmod來驗(yàn)證模塊的掛在跟卸載,但必須用root的身份登陸命令行,用普通用戶加su或者sudo在Ubuntu上的測試是不行的。Linux USB驅(qū)動框架分析(三)下面分析一下usb-skeleton的源碼。這個范例程序可以在linux-2.6.17/drivers/usb下找到,其他版本的內(nèi)核程序源碼可能有所不同,但相差不大。大家可以先找到源碼看一看,先有個整體印象。之前已經(jīng)提到,模
14、塊先要向內(nèi)核注冊初始化跟銷毀函數(shù): static int _init usb_skel_init(void) int result; /* register this driver with the USB subsystem */ result = usb_register(&skel_driver); if (result) err(usb_register failed. Error number %d, result); return result; static void _exit usb_skel_exit(void) /* deregister this driver with
15、 the USB subsystem */ usb_deregister(&skel_driver); module_init (usb_skel_init); module_exit (usb_skel_exit); MODULE_LICENSE(GPL); 從代碼開來,這個init跟exit函數(shù)的作用只是用來注冊驅(qū)動程序,這個描述驅(qū)動程序的結(jié)構(gòu)體是系統(tǒng)定義的標(biāo)準(zhǔn)結(jié)構(gòu)struct usb_driver,注冊和注銷的方法很簡單,usb_register(struct *usb_driver), usb_deregister(struct *usb_driver)。那這個結(jié)構(gòu)體需要做些什么呢?他
16、要向系統(tǒng)提供幾個函數(shù)入口,跟驅(qū)動的名字: static struct usb_driver skel_driver = .name = skeleton, .probe = skel_probe, .disconnect = skel_disconnect, .id_table = skel_table, ; 從代碼看來,usb_driver需要初始化四個東西:模塊的名字skeleton,probe函數(shù)skel_probe, disconnect函數(shù)skel_disconnect,以及id_table。 在解釋skel_driver各個成員之前,我們先來看看另外一個結(jié)構(gòu)體。這個結(jié)構(gòu)體的名字有開
17、發(fā)人員自定義,它描述的是該驅(qū)動擁有的所有資源及狀態(tài): struct usb_skel struct usb_device * udev; /* the usb device for this device */ struct usb_interface * interface; /* the interface for this device */ struct semaphore limit_sem; /* limiting the number of writes in progress */ unsigned char * bulk_in_buffer; /* the buffer to
18、 receive data */ size_t bulk_in_size; /* the size of the receive buffer */ _u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ _u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ struct kref kref; ; 我們先來對這個usb_skel作個簡單分析,他擁有一個描述usb設(shè)備的結(jié)構(gòu)體udev,一個接口interface,用于并發(fā)訪問控制的s
19、emaphore(信號量) limit_sem,用于接收數(shù)據(jù)的緩沖bulk_in_buffer及其尺寸bulk_in_size,然后是批量輸入輸出端口地址bulk_in_endpointAddr、bulk_out_endpointAddr,最后是一個內(nèi)核使用的引用計數(shù)器。他們的作用我們將在后面的代碼中看到。 我們再回過頭來看看skel_driver。 name用來告訴內(nèi)核模塊的名字是什么,這個注冊之后由系統(tǒng)來使用,跟我們關(guān)系不大。 id_table用來告訴內(nèi)核該模塊支持的設(shè)備。usb子系統(tǒng)通過設(shè)備的production ID和vendor ID的組合或者設(shè)備的class、subclass跟pr
20、otocol的組合來識別設(shè)備,并調(diào)用相關(guān)的驅(qū)動程序作處理。我們可以看看這個id_table到底是什么東西: /* Define these values to match your devices */ #define USB_SKEL_VENDOR_ID 0xfff0 #define USB_SKEL_PRODUCT_ID 0xfff0 /* table of devices that work with this driver */ static struct usb_device_id skel_table = USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKE
21、L_PRODUCT_ID) , /* Terminating entry */ ; MODULE_DEVICE_TABLE (usb, skel_table); MODULE_DEVICE_TABLE的第一個參數(shù)是設(shè)備的類型,如果是USB設(shè)備,那自然是usb(如果是PCI設(shè)備,那將是pci,這兩個子系統(tǒng)用同一個宏來注冊所支持的設(shè)備。這涉及PCI設(shè)備的驅(qū)動了,在此先不深究)。后面一個參數(shù)是設(shè)備表,這個設(shè)備表的最后一個元素是空的,用于標(biāo)識結(jié)束。代碼定義了USB_SKEL_VENDOR_ID是0xfff0,USB_SKEL_PRODUCT_ID是0xfff0,也就是說,當(dāng)有一個設(shè)備接到集線器時,us
22、b子系統(tǒng)就會檢查這個設(shè)備的vendor ID和product ID,如果它們的值是0xfff0時,那么子系統(tǒng)就會調(diào)用這個skeleton模塊作為設(shè)備的驅(qū)動。Linux USB驅(qū)動框架分析(四)probe是usb子系統(tǒng)自動調(diào)用的一個函數(shù),有USB設(shè)備接到硬件集線器時,usb子系統(tǒng)會根據(jù)production ID和vendor ID的組合或者設(shè)備的class、subclass跟protocol的組合來識別設(shè)備調(diào)用相應(yīng)驅(qū)動程序的probe(探測)函數(shù),對于skeleton來說,就是skel_probe。系統(tǒng)會傳遞給探測函數(shù)一個usb_interface *跟一個struct usb_device_i
23、d *作為參數(shù)。他們分別是該USB設(shè)備的接口描述(一般會是該設(shè)備的第0號接口,該接口的默認(rèn)設(shè)置也是第0號設(shè)置)跟它的設(shè)備ID描述(包括Vendor ID、Production ID等)。probe函數(shù)比較長,我們分段來分析這個函數(shù): dev-udev = usb_get_dev(interface_to_usbdev(interface); dev-interface = interface; 在初始化了一些資源之后,可以看到第一個關(guān)鍵的函數(shù)調(diào)用interface_to_usbdev。他同uo一個usb_interface來得到該接口所在設(shè)備的設(shè)備描述結(jié)構(gòu)。本來,要得到一個usb_device
24、只要用interface_to_usbdev就夠了,但因?yàn)橐黾訉υ搖sb_device的引用計數(shù),我們應(yīng)該在做一個usb_get_dev的操作,來增加引用計數(shù),并在釋放設(shè)備時用usb_put_dev來減少引用計數(shù)。這里要解釋的是,該引用計數(shù)值是對該usb_device的計數(shù),并不是對本模塊的計數(shù),本模塊的計數(shù)要由kref來維護(hù)。所以,probe一開始就有初始化kref。事實(shí)上,kref_init操作不單只初始化kref,還將其置設(shè)成1。所以在出錯處理代碼中有kref_put,它把kref的計數(shù)減1,如果kref計數(shù)已經(jīng)為0,那么kref會被釋放。kref_put的第二個參數(shù)是一個函數(shù)指針,指
25、向一個清理函數(shù)。注意,該指針不能為空,或者kfree。該函數(shù)會在最后一個對kref的引用釋放時被調(diào)用(如果我的理解不準(zhǔn)確,請指正)。下面是內(nèi)核源碼中的一段注釋及代碼: /* * kref_put - decrement refcount for object. * kref: object. * release: pointer to the function that will clean up the object when the * last reference to the object is released. * This pointer is required, and it
26、is not acceptable to pass kfree * in as this function. * * Decrement the refcount, and if 0, call release(). * Return 1 if the object was removed, otherwise return 0. Beware, if this * function returns 0, you still can not count on the kref from remaining in * memory. Only use the return value if yo
27、u want to see if the kref is now * gone, not present. */ int kref_put(struct kref *kref, void (*release)(struct kref *kref) WARN_ON(release = NULL); WARN_ON(release = (void (*)(struct kref *)kfree); /* * if current count is one, we are the last user and can release object * right now, avoiding an at
28、omic operation on refcount */ if (atomic_read(&kref-refcount) = 1) | (atomic_dec_and_test(&kref-refcount) release(kref); return 1; return 0; 當(dāng)我們執(zhí)行打開操作時,我們要增加kref的計數(shù),我們可以用kref_get,來完成。所有對struct kref的操作都有內(nèi)核代碼確保其原子性。得到了該usb_device之后,我們要對我們自定義的usb_skel各個狀態(tài)跟資源作初始化。這部分工作的任務(wù)主要是向usb_skel注冊該usb設(shè)備的端點(diǎn)。這里可能要補(bǔ)充以
29、下一些關(guān)于usb_interface_descriptor的知識,但因?yàn)閮?nèi)核源碼對該結(jié)構(gòu)體的注釋不多,所以只能靠個人猜測。在一個usb_host_interface結(jié)構(gòu)里面有一個usb_interface_descriptor叫做desc的成員,他應(yīng)該是用于描述該interface的一些屬性,其中bNumEndpoints是一個8位(b for byte)的數(shù)字,他代表了該接口的端點(diǎn)數(shù)。probe然后遍歷所有的端點(diǎn),檢查他們的類型跟方向,注冊到usb_skel中。 /* set up the endpoint information */ /* use only the first bulk-
30、in and bulk-out endpoints */ iface_desc = interface-cur_altsetting; for (i = 0; i desc.bNumEndpoints; +i) endpoint = &iface_desc-endpoint.desc;if ( !dev-bulk_in_endpointAddr & (endpoint-bEndpointAddress & USB_ENDPOINT_DIR_MASK) = = USB_DIR_IN) & (endpoint-bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) =
31、 = USB_ENDPOINT_XFER_BULK) /* we found a bulk in endpoint */ buffer_size = le16_to_cpu(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 allocat
32、e bulk_in_buffer); goto error; if (!dev-bulk_out_endpointAddr & (endpoint-bEndpointAddress & USB_ENDPOINT_DIR_MASK)= =USB_DIR_OUT) & (endpoint-bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)= = USB_ENDPOINT_XFER_BULK) /* we found a bulk out endpoint */ dev-bulk_out_endpointAddr = endpoint-bEndpointAddres
33、s; if (!(dev-bulk_in_endpointAddr & dev-bulk_out_endpointAddr) err(Could not find both bulk-in and bulk-out endpoints); goto error; Linux USB驅(qū)動框架分析(五)接下來的工作是向系統(tǒng)注冊一些以后會用的信息。首先我們來說明一下usb_set_intfdata(),他向內(nèi)核注冊一個data,這個data的結(jié)構(gòu)可以是任意的,這段程序向內(nèi)核注冊了一個usb_skel結(jié)構(gòu),就是我們剛剛看到的被初始化的那個,這個data可以在以后用usb_get_intfdata來得到
34、。usb_set_intfdata(interface, dev); retval = usb_register_dev(interface, &skel_class); 然后我們向這個interface注冊一個skel_class結(jié)構(gòu)。這個結(jié)構(gòu)又是什么?我們就來看看這到底是個什么東西: static struct usb_class_driver skel_class = .name = skel%d, .fops = &skel_fops, .minor_base = USB_SKEL_MINOR_BASE, ; 它其實(shí)是一個系統(tǒng)定義的結(jié)構(gòu),里面包含了一個名字、一個文件操作結(jié)構(gòu)體還有一個次
35、設(shè)備號的基準(zhǔn)值。事實(shí)上它才是定義真正完成對設(shè)備IO操作的函數(shù)。所以他的核心內(nèi)容應(yīng)該是skel_fops。這里補(bǔ)充一些我個人的估計:因?yàn)閡sb設(shè)備可以有多個interface,每個interface所定義的IO操作可能不一樣,所以向系統(tǒng)注冊的usb_class_driver要求注冊到某一個interface,而不是device,因此,usb_register_dev的第一個參數(shù)才是interface,而第二個參數(shù)就是某一個usb_class_driver。通常情況下,linux系統(tǒng)用主設(shè)備號來識別某類設(shè)備的驅(qū)動程序,用次設(shè)備號管理識別具體的設(shè)備,驅(qū)動程序可以依照次設(shè)備號來區(qū)分不同的設(shè)備,所以,這
36、里的次設(shè)備號其實(shí)是用來管理不同的interface的,但由于這個范例只有一個interface,在代碼上無法求證這個猜想。 static struct file_operations skel_fops = .owner = THIS_MODULE, .read = skel_read, .write = skel_write, .open = skel_open, .release = skel_release, ; 這個文件操作結(jié)構(gòu)中定義了對設(shè)備的讀寫、打開、釋放(USB設(shè)備通常使用這個術(shù)語release)。他們都是函數(shù)指針,分別指向skel_read、skel_write、skel_op
37、en、skel_release這四個函數(shù),這四個函數(shù)應(yīng)該有開發(fā)人員自己實(shí)現(xiàn)。 當(dāng)設(shè)備被拔出集線器時,usb子系統(tǒng)會自動地調(diào)用disconnect,他做的事情不多,最重要的是注銷class_driver(交還次設(shè)備號)和interface的data: dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); /* give back our minor */ usb_deregister_dev(interface, &skel_class); 然后他會用kref_put(&dev-kref, skel_delet
38、e)進(jìn)行清理,kref_put的細(xì)節(jié)參見前文。 到目前為止,我們已經(jīng)分析完usb子系統(tǒng)要求的各個主要操作,下一部分我們在討論一下對USB設(shè)備的IO操作。Linux USB驅(qū)動框架分析(六)說到usb子系統(tǒng)的IO操作,不得不說usb request block,簡稱urb。事實(shí)上,可以打一個這樣的比喻,usb總線就像一條高速公路,貨物、人流之類的可以看成是系統(tǒng)與設(shè)備交互的數(shù)據(jù),而urb就可以看成是汽車。在一開始對USB規(guī)范細(xì)節(jié)的介紹,我們就說過USB的endpoint有4種不同類型,也就是說能在這條高速公路上流動的數(shù)據(jù)就有四種。但是這對汽車是沒有要求的,所以urb可以運(yùn)載四種數(shù)據(jù),不過你要先告訴
39、司機(jī)你要運(yùn)什么,目的地是什么。我們現(xiàn)在就看看struct urb的具體內(nèi)容。它的內(nèi)容很多,為了不讓我的理解誤導(dǎo)各位,大家最好還是看一看內(nèi)核源碼的注釋,具體內(nèi)容參見源碼樹下include/linux/usb.h。 在這里我們重點(diǎn)介紹程序中出現(xiàn)的幾個關(guān)鍵字段: struct usb_device *dev /* urb所發(fā)送的目標(biāo)設(shè)備*/unsigned int pipe 一個管道號碼,該管道記錄了目標(biāo)設(shè)備的端點(diǎn)以及管道的類型。每個管道只有一種類型和一個方向,它與他的目標(biāo)設(shè)備的端點(diǎn)相對應(yīng),我們可以通過以下幾個函數(shù)來獲得管道號并設(shè)置管道類型: unsigned int usb_sndctrlpipe
40、(struct usb_device *dev, unsigned int endpoint) 把指定USB設(shè)備的指定端點(diǎn)設(shè)置為一個控制OUT端點(diǎn)。 unsigned int usb_rcvctrlpipe(struct usb_device *dev, unsigned int endpoint) 把指定USB設(shè)備的指定端點(diǎn)設(shè)置為一個控制IN端點(diǎn)。 unsigned int usb_sndbulkpipe(struct usb_device *dev, unsigned int endpoint) 把指定USB設(shè)備的指定端點(diǎn)設(shè)置為一個批量OUT端點(diǎn)。 unsigned int usb_rcv
41、bulkpipe(struct usb_device *dev, unsigned int endpoint) 把指定USB設(shè)備的指定端點(diǎn)設(shè)置為一個批量OUT端點(diǎn)。 unsigned int usb_sndintpipe(struct usb_device *dev, unsigned int endpoint) 把指定USB設(shè)備的指定端點(diǎn)設(shè)置為一個中斷OUT端點(diǎn)。 unsigned int usb_rcvintpipe(struct usb_device *dev, unsigned int endpoint) 把指定USB設(shè)備的指定端點(diǎn)設(shè)置為一個中斷IN端點(diǎn)。 unsigned int u
42、sb_sndisocpipe(struct usb_device *dev, unsigned int endpoint) 把指定USB設(shè)備的指定端點(diǎn)設(shè)置為一個等時OUT端點(diǎn)。 unsigned int usb_rcvisocpipe(struct usb_device *dev, unsigned int endpoint) 把指定USB設(shè)備的指定端點(diǎn)設(shè)置為一個等時IN端點(diǎn)。 unsigned int transfer_flags 當(dāng)不使用DMA時,應(yīng)該transfer_flags |= URB_NO_TRANSFER_DMA_MAP(按照代碼的理解,希望沒有錯)。 int status 當(dāng)
43、一個urb把數(shù)據(jù)送到設(shè)備時,這個urb會由系統(tǒng)返回給驅(qū)動程序,并調(diào)用驅(qū)動程序的urb完成回調(diào)函數(shù)處理。這時,status記錄了這次數(shù)據(jù)傳輸?shù)挠嘘P(guān)狀態(tài),例如傳送成功與否。成功的話會是0。 要能夠運(yùn)貨當(dāng)然首先要有車,所以第一步當(dāng)然要創(chuàng)建urb: struct urb *usb_alloc_urb(int isoc_packets, int mem_flags); 第一個參數(shù)是等時包的數(shù)量,如果不是乘載等時包,應(yīng)該為0,第二個參數(shù)與kmalloc的標(biāo)志相同。 要釋放一個urb可以用: void usb_free_urb(struct urb *urb); 要承載數(shù)據(jù),還要告訴司機(jī)目的地信息跟要運(yùn)的貨
44、物,對于不同的數(shù)據(jù),系統(tǒng)提供了不同的函數(shù),對于中斷urb,我們用 void usb_fill_int_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context, int interval); 這里要解釋一下,transfer_buffer是一個要送/收的數(shù)據(jù)的緩沖,buffer_length是它的長度,complete是urb完成回調(diào)函數(shù)的入口,context由用戶
45、定義,可能會在回調(diào)函數(shù)中使用的數(shù)據(jù),interval就是urb被調(diào)度的間隔。 對于批量urb和控制urb,我們用: void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context); void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev, unsigned int
46、 pipe, unsigned char* setup_packet,void *transfer_buffer, int buffer_length, usb_complete_t complete,void *context); 控制包有一個特殊參數(shù)setup_packet,它指向即將被發(fā)送到端點(diǎn)的設(shè)置數(shù)據(jù)報的數(shù)據(jù)。 對于等時urb,系統(tǒng)沒有專門的fill函數(shù),只能對各urb字段顯示賦值。 有了汽車,有了司機(jī),下一步就是要開始運(yùn)貨了,我們可以用下面的函數(shù)來提交urb int usb_submit_urb(struct urb *urb, int mem_flags); mem_flags有
47、幾種:GFP_ATOMIC、GFP_NOIO、GFP_KERNEL,通常在中斷上下文環(huán)境我們會用GFP_ATOMIC。 當(dāng)我們的卡車運(yùn)貨之后,系統(tǒng)會把它調(diào)回來,并調(diào)用urb完成回調(diào)函數(shù),并把這輛車作為函數(shù)傳遞給驅(qū)動程序。我們應(yīng)該在回調(diào)函數(shù)里面檢查status字段,以確定數(shù)據(jù)的成功傳輸與否。下面是用urb來傳送數(shù)據(jù)的細(xì)節(jié)。 /* initialize the urb properly */ usb_fill_bulk_urb(urb, dev-udev, usb_sndbulkpipe(dev-udev, dev-bulk_out_endpointAddr), buf, writesize, skel_write_bulk_callback, dev); urb-tr
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年行政服務(wù)協(xié)議范本下載:詳盡條款版版B版
- 2024年股權(quán)擔(dān)保合同
- 2024年高檔會所食堂牛羊肉定制采購配送合同3篇
- 2024年跨境電子商務(wù)平臺建設(shè)標(biāo)前協(xié)議書
- 2024年規(guī)范化幼兒園租賃協(xié)議樣本版B版
- 2024年質(zhì)押借款合同正式樣本
- 2024年電影業(yè)演員勞務(wù)協(xié)議示例版B版
- 2024年食品生產(chǎn)加工合作協(xié)議
- 2024建筑施工合同標(biāo)的及工程進(jìn)度安排
- 2024環(huán)保技術(shù)研發(fā)與污染治理服務(wù)合同
- 博物館展覽活動應(yīng)急預(yù)案
- 2025年包鋼(集團(tuán))公司招聘筆試參考題庫含答案解析
- 2025年沈陽水務(wù)集團(tuán)招聘筆試參考題庫含答案解析
- 2025年高三語文八省聯(lián)考作文題目詳解:7個立意、15個標(biāo)題、5個素材
- 《科學(xué)與工程倫理》課件-1港珠澳大橋工程建設(shè)中的白海豚保護(hù)相關(guān)案例分析
- 肘關(guān)節(jié)鏡手術(shù)
- 浙江省杭州市錢塘區(qū)2023-2024學(xué)年四年級上學(xué)期數(shù)學(xué)期末試卷
- 2024年北師大版四年級數(shù)學(xué)上學(xué)期學(xué)業(yè)水平測試期末測試卷(含答案)
- 天車租賃合同范例
- 多任務(wù)并行處理中的計算資源分配
- 第二單元《第8課循環(huán)結(jié)構(gòu)-for循環(huán)》教學(xué)實(shí)錄 -2023-2024學(xué)年浙教版(2020)初中信息技術(shù)八年級上冊
評論
0/150
提交評論