(北京工業(yè)大學(xué) 嵌入式軟件與系統(tǒng)研究所, 北京 100022)
摘 要:
針對一些復(fù)雜設(shè)備驅(qū)動程序的特點,研究了用戶空間實現(xiàn)驅(qū)動程序的方法,將驅(qū)動程序分為兩部分:內(nèi)核空間實現(xiàn)核心部分,在用戶空間實現(xiàn)驅(qū)動程序新的接口,以適應(yīng)設(shè)備的多樣性。研究了用戶空間驅(qū)動程序的結(jié)構(gòu)、用戶空間和內(nèi)核空間驅(qū)動程序內(nèi)容的劃分及它們之間的通信方法。選擇典型的USB設(shè)備驅(qū)動程序,描述了通用USB驅(qū)動程序在用戶空間的實現(xiàn)過程,主要內(nèi)容包括初始化設(shè)備接口、操作設(shè)備接口、控制傳輸接口、批傳輸接口、中斷傳輸接口和通信部分,最后進行了測試分析。
關(guān)鍵詞:用戶空間; 驅(qū)動程序; 通用串行總線
中圖分類號:TP319 文獻標志碼: A
文章編號:10013695(2008)12364203
Driver researching in user space
HE Fugui, HOU Yibin, LI Hui
(Embedded Software Systems Institute, Beijing University of Technology, Beijing 100022, China)
Abstract:
According to characteristics of complex device driver, this paper investigated the method that driver was realized in user space. Driver was divided into two parts, the key part was realized in kernel, and new interface was realized in user space. The paper researched structure of driver, content partition and communication method between user and kernel space. And chosed typical USB driver as examples, and described the realization of generally USB driver in user space, main content included initialized interfaces, operating interfaces, control interfaces, bulk transport interfaces , interrupt transport interfaces and communication. Finally, testing and analysis were done.
Key words:user space; driver; USB(universal serial bus)
0 引言
驅(qū)動程序[1]是直接工作在各種硬件設(shè)備上的軟件,它提供給用戶操作設(shè)備的接口,是操作系統(tǒng)中內(nèi)容最豐富的一部分。對于嵌入式設(shè)備的開發(fā),其中最主要的工作就集中在設(shè)備驅(qū)動。隨著電子技術(shù)的快速發(fā)展,不斷出現(xiàn)新的輸入/輸出設(shè)備,其中使用最廣泛的就是USB設(shè)備。USB設(shè)備有豐富的種類,如USB字符設(shè)備、USB鍵盤鼠標、USB塊設(shè)備和USB硬盤等。
設(shè)備驅(qū)動程序一般都是在內(nèi)核實現(xiàn)的,對于設(shè)備類型單一的驅(qū)動程序,僅僅在內(nèi)核實現(xiàn)就可以滿足要求了;但對于一些需要復(fù)雜驅(qū)動程序的設(shè)備,內(nèi)核設(shè)備驅(qū)動程序會遇到如下的一些問題:
a)對于不同的操作系統(tǒng)平臺,要設(shè)計的設(shè)備驅(qū)動程序必須是要兼容兩個平臺的。
b)對于嵌入式系統(tǒng),不能定制操作系統(tǒng)設(shè)備驅(qū)動程序,因為修改內(nèi)核是非常困難的。
c) 出現(xiàn)了同一類型的新設(shè)備,必須開發(fā)新的設(shè)備驅(qū)動程序。
針對上述問題,本文研究了在用戶空間驅(qū)動程序的實現(xiàn)方法,將驅(qū)動程序的一部分在用戶空間實現(xiàn)[2],由用戶空間的驅(qū)動程序提供接口給應(yīng)用程序,使設(shè)備驅(qū)動程序的內(nèi)核接口限制在驅(qū)動程序內(nèi)部,設(shè)備驅(qū)動程序的結(jié)構(gòu)更加靈活,也使應(yīng)用程序訪問設(shè)備更加方便。
1 用戶空間驅(qū)動程序
在用戶空間實現(xiàn)驅(qū)動程序是把驅(qū)動程序的一部分放在用戶空間,但不能將驅(qū)動程序任意的部分放在用戶空間,也不是所有的設(shè)備驅(qū)動程序都放到用戶空間實現(xiàn),對于大部分的設(shè)備驅(qū)動程序是在內(nèi)核空間實現(xiàn)的。只有在設(shè)備種類多、驅(qū)動程序較復(fù)雜、能夠分層時,為了使用的方便,其中上層或增加的驅(qū)動程序部分可在用戶空間實現(xiàn)。
11 用戶空間驅(qū)動程序的結(jié)構(gòu)
在用戶空間實現(xiàn)驅(qū)動程序和在內(nèi)核空間實現(xiàn)驅(qū)動程序的結(jié)構(gòu)如圖1、2所示。
12 用戶空間和內(nèi)核空間設(shè)備驅(qū)動程序劃分
因為用戶空間的程序不能直接操作輸入/輸出設(shè)備內(nèi)部,這部分應(yīng)放在內(nèi)核實現(xiàn);另外在用戶空間的程序不能直接調(diào)用內(nèi)核的程序,用戶空間的程序調(diào)用內(nèi)核是通過操作系統(tǒng)的系統(tǒng)調(diào)用實現(xiàn)的。對于操作系統(tǒng)沒有提供接口的內(nèi)核程序,如果驅(qū)動程序需要調(diào)用,那么這部分設(shè)備驅(qū)動程序必須在內(nèi)核實現(xiàn),其次驅(qū)動程序的中斷部分也必須在內(nèi)核實現(xiàn)。一般將核心的、低層的和不變的驅(qū)動程序部分放在內(nèi)核空間;將上層的和變化的放在用戶空間;另外在用戶空間還可以實現(xiàn)一些原來沒有的驅(qū)動程序,以豐富驅(qū)動程序的功能。
13 用戶空間和內(nèi)核空間設(shè)備驅(qū)動程序的通信
用戶空間和內(nèi)核空間設(shè)備驅(qū)動程序的通信可以通過內(nèi)核空間設(shè)備驅(qū)動程序提供的系統(tǒng)調(diào)用來實現(xiàn),也可以設(shè)計一些專門的系統(tǒng)調(diào)用來實現(xiàn),一般使用驅(qū)動程序的系統(tǒng)調(diào)用ioctl()實現(xiàn)通信[3,4]。
Ioctl是設(shè)備驅(qū)動程序中對設(shè)備的I/O通道進行管理的函數(shù),就是對設(shè)備的一些特性進行控制,如串口的傳輸波特率、馬達的轉(zhuǎn)速等。它的一般格式如下:
int ioctl(int fd, ind cmd, …);
其中:fd是用戶程序打開設(shè)備時的設(shè)備標志;cmd就是用戶程序?qū)υO(shè)備的控制命令;后面的省略號是一些補充參數(shù)。
在驅(qū)動程序中實現(xiàn)的ioctl函數(shù)體中實際上有一個switch{case}結(jié)構(gòu),每一個case對應(yīng)一個命令碼,做出一些相應(yīng)的操作。至于怎么解釋這些命令和怎么實現(xiàn)這些命令,可以由驅(qū)動程序編寫人員自己定義。
這樣就可以在ioctl函數(shù)中,通過自定義接口在驅(qū)動程序的內(nèi)核部分實現(xiàn)、在用戶部分調(diào)用,從而實現(xiàn)它們之間的通信。
2 USB結(jié)構(gòu)
隨著USB設(shè)備的普及,USB設(shè)備的驅(qū)動開發(fā)也成為驅(qū)動開發(fā)者做得最多的事情。USB與傳統(tǒng)接口總線相比,主要優(yōu)點有三個:a)可接入多達127個設(shè)備;b)可以熱插拔,在電腦通電的情況下可以隨時熱插拔所連接的設(shè)備;c)可即插即用。
整個USB可以分為三個部分進行描述,即USB連接、USB設(shè)備和USB主機[5],如圖3所示。
在USB中只有一個主機。USB與計算機主機系統(tǒng)的接口部分就是主機控制器,它可被看做是一個硬件、固件和軟件的結(jié)合體。主機系統(tǒng)中集成了一個根hub來提供一個或多個連接點。
USB設(shè)備可被分為兩大類,即hub類(提供附加USB接入點的設(shè)備)和功能設(shè)備類(為系統(tǒng)實現(xiàn)某些功能的設(shè)備,如ISDN適配器、數(shù)字游戲桿等)。按照功能USB設(shè)備又可分為很多類,如音頻、人機交互、顯示、通信、電源、打印機、海量存儲、物理反饋等設(shè)備。每個USB設(shè)備都必須提供自鑒定信息和通用的設(shè)置。
USB設(shè)備都有一個標準的USB接口,它的作用為:解釋USB協(xié)議;對標準USB操作的響應(yīng),如掛起和設(shè)置等;提供設(shè)備的一些描述信息。
在實際的設(shè)計應(yīng)用中,USB設(shè)備的接口有自己的特點。USB接口的正確設(shè)計與設(shè)備的性能緊密相關(guān),在USB接口設(shè)計之前必須要對設(shè)備的功能、指標進行詳細的分析。連接在USB接口上的設(shè)備通過基于令牌和主機控制的協(xié)議來共同享用整個USB帶寬。在其他設(shè)備正常工作的前提下,USB允許設(shè)備連接、設(shè)置、運行和斷開連接。
隨著USB 2.0協(xié)議的推出,USB的應(yīng)用范圍將更為擴大。USB 2.0所定義的帶寬為480 Mbps,它的出現(xiàn)將徹底改變USB只能在低速設(shè)備上應(yīng)用的現(xiàn)狀。
3 USB用戶空間驅(qū)動程序的實現(xiàn)
為了使應(yīng)用程序能夠使用操作USB設(shè)備,在用戶空間的USB驅(qū)動程序分為五部分,即初始化設(shè)備接口、操作設(shè)備接口、控制傳輸接口、批傳輸接口和中斷傳輸接口。
1)初始化設(shè)備接口
這些接口也可以稱為核心函數(shù),它們主要用來初始化并尋找相關(guān)設(shè)備,包括以下函數(shù):
a)void usb_init(void);/*初始化相關(guān)數(shù)據(jù)*/
b)int usb_find_busses(void);/*尋找系統(tǒng)上的USB*/
c)int usb_find_devices(void);/*尋找總線上的USB設(shè)備*/
d)struct usb_bus *usb_get_busses(void);/*返回總線的列表*/
2)操作設(shè)備接口
這些接口完成對USB設(shè)備的操作。
a)usb_dev_handle *usb_open(struct *usb_device dev);/*打開要使用的設(shè)備*/
b)int usb_close(usb_dev_handle *dev);/*關(guān)閉設(shè)備*/
c)int usb_set_configuration(usb_dev_handle *dev, int configuration);/*設(shè)置當前設(shè)備使用的configuration*/
d) int usb_set_altinterface(usb_dev_handle *dev, int alternate);/*設(shè)置當前設(shè)備配置的interface descriptor*/
e) int usb_resetep(usb_dev_handle *dev, unsigned int ep);/*復(fù)位指定的endpoint*/
f) int usb_clear_halt (usb_dev_handle *dev, unsigned int ep);/*清除暫停*/
g) int usb_reset(usb_dev_handle *dev);/*重啟設(shè)備*/
h)int usb_claim_interface(usb_dev_handle *dev, int interface);/*注冊與操作系統(tǒng)通信接口*/
i)int usb_release_interface(usb_dev_handle *dev, int interface);/*注銷被usb_claim_interface函數(shù)調(diào)用后的接口,釋放資源,與usb_claim_interface對應(yīng)使用*/
3)控制傳輸接口
從默認的管道發(fā)送和接收控制數(shù)據(jù)。
a)int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
b) int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, size_t buflen);
c)int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen);
d)int usb_get_descriptor(usb_dev_handle *dev, unsigned char type, unsigned char index, void *buf, int size);
e)int usb_get_descriptor_by_endpoint (usb_dev_handle *dev, int ep, unsigned char type, unsigned char index, void *buf, int size)。
4)批傳輸接口
批傳輸讀寫。
a)int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
b) int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)。
5)中斷傳輸接口
中斷讀寫。
a) int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
b)int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)。
以上基本上包含了USB常用的函數(shù),通過這些函數(shù)就可以操作不同的USB設(shè)備。這些函數(shù)與內(nèi)核空間的驅(qū)動程序是通過ioctl ()函數(shù)進行通信的。例如usb_claim_interface( )通過調(diào)用 ioctl(dev->fd, IOCTL_USB_CLAIMINTF, interface)內(nèi)核函數(shù)。
4 實驗測試
設(shè)計一組測試程序調(diào)用用戶空間的驅(qū)動程序,對實際的USB設(shè)備進行操作。
測試環(huán)境:桌面PC機,操作系統(tǒng)是RedHat Linux 9.0,在USB接口插上SanDisk 的U盤。
運行測試程序,部分測試結(jié)果如下:
[root@localhost tests]# ./driver_name
bus/device idVendor/idProduct
001/001 0000/0000 driver: hub
001/002 0781/5406 driver: usbstorage
[root@localhost tests]# ./testlibusb
Dev #1: 0000USB UHCI Root Hub
Dev #2: SanDisk CorporationU3 Cruzer Micro
[root@localhost tests]# ./id_test
bus/device idVendor/idProduct/bcdDevice Class/SubClass/Protocol
001/001 0000 / 0000 / 0000 09 00 00
001/002 0781 / 5406 / 0010 00 00 00
[root@localhost tests]# ./get_resolution
idVendor/idProduct/bcdDevice
[root@localhost tests]# ./find_hubs
Class/SubClass/Protocol
09 00 00
從測試結(jié)果可以看出,用戶空間驅(qū)動程序可以有效地操作USB設(shè)備。
5 結(jié)束語
驅(qū)動程序在用戶空間實現(xiàn)能取得更大的靈活性,這對于復(fù)雜功能設(shè)備可以簡化應(yīng)用程序的操作。
參考文獻:
[1]CORBET J, RUBINI A, KROAHHARTMAN G. Linux設(shè)備驅(qū)動程序[M].魏永明,耿岳,鐘書毅,譯.3版.北京:中國電力出版社,2007:137179.
[2] 劉斌,王沛,潘金貴.Linux用戶空間打印機驅(qū)動程序的設(shè)計與實現(xiàn)[J].小型微型計算機系統(tǒng),2002, 23 (1):4749.
[3] 毛德操,胡希明.Linux情景源代碼分析(下冊)[M].杭州:浙江大學(xué)出版社,2001:326330.
[4] 武安河,邰銘,于洪濤.Windows 2000/XP WDM設(shè)備驅(qū)動程序開發(fā)[M].2版.北京:電子工業(yè)出版社,2005:7780.
[5] 張玉民,陳定方.Linux下USB驅(qū)動程序的設(shè)計與實現(xiàn)[J].湖北工業(yè)大學(xué)學(xué)報,2007(3):5355.