usb接口驱动_乾坤合一~Linux设备驱动之USB主机和设备驱动
這一章從主機側(cè)角度看到的USB 主機控制器驅(qū)動和設(shè)備驅(qū)動從主機側(cè)的角度而言,需要編寫的USB 驅(qū)動程序包括主機控制器驅(qū)動和設(shè)備驅(qū)動兩類,USB 主機控制器驅(qū)動程序控制插入其中的USB 設(shè)備,而USB 設(shè)備驅(qū)動程序控制該設(shè)備如何作為從設(shè)備與主機通信。
1. Linux USB驅(qū)動層次
1.1 主機側(cè)與設(shè)備側(cè)USB 驅(qū)動
USB 采用樹形拓撲結(jié)構(gòu),每條總線上只有一個主機控制器,負責(zé)協(xié)調(diào)主機和設(shè)備間的通信,而設(shè)備不能主動向主機發(fā)送任何消息。
1.2 設(shè)備、配置、接口、端點
在USB 設(shè)備的邏輯組織中,包含設(shè)備、配置、接口和端點4 個層次,每個USB 設(shè)備都提供了不同級別的配置信息,可以包含一個或多個配置,不同的配置使設(shè)備表現(xiàn)出不同的功能組合,配置由多個接口組成,接口由多個端點組成,代表一個基本的功能,是USB 設(shè)備驅(qū)動程序控制的對象,如下圖是USB 設(shè)備、配置、接口和端點之間的關(guān)系。
設(shè)備描述符:關(guān)于設(shè)備的通用信息,如供應(yīng)商ID 、產(chǎn)品ID 和修訂ID,支持的設(shè)備類、子類和適用的協(xié)議以及默認(rèn)端點的最大包大小等。在Linux 內(nèi)核中,USB 設(shè)備用 usb_device 結(jié)構(gòu)體來描述,USB 設(shè)備描述符定義為usb_device_descriptor 結(jié)構(gòu)體,其代碼如下:
struct usb device descriptor{_ _u8 bLength; // 述符長度_ _u8 bDescriptorType; // 述符類型編號_ _le16 bcdUSB; //USB版本號_ _u8 bDeviceClass; //USB分配的設(shè)備類code_ _u8 bDeviceSubClass;// USB 分配的子類code_ _u8 bDeviceProtocol; //USB 分配的協(xié)議code_ _u8 bMaxPacketSize0; //endpoint0 最大包大小_ _le16 idVendor; //廠商編號_ _le16 idProduct; //產(chǎn)品編號_ _le16 bcdDevice; //設(shè)備出廠編號_ _u8 iManufacturer; // 述廠商字符串的索引_ _u8 iProduct; // 述產(chǎn)品字符串的索引_ _u8 iSerialNumber; // 述設(shè)備序列號字符串的索引_ _u8 bNumConfigurations; //可能的配置數(shù)量} _ _attribute_ _ ((packed));配置描述符:此配置中的接口數(shù)、支持的掛起和恢復(fù)能力以及功率要求。USB配置在內(nèi)核中使用usb_host_config 結(jié)構(gòu)體描述,USB 配置描述符定義為結(jié)構(gòu)體usb_config_descriptor,其代碼如下:
struct usb config descriptor{_ _u8 bLength; // 述符長度_ _u8 bDescriptorType; // 述符類型編號_ _le16 wTotalLength; //配置所返回的所有數(shù)據(jù)的大小_ _u8 bNumInterfaces; // 配置所支持的接口數(shù)_ _u8 bConfigurationValue; //Set Configuration命令需要的參數(shù)值_ _u8 iConfiguration; // 述該配置的字符串的索引值_ _ u8 bmAttributes; //供電模式的選擇_ _u8 bMaxPower; //設(shè)備從總線提取的最大電流} _ _attribute_ _ ((packed));接口描述符:接口類、子類和適用的協(xié)議,接口備用配置的數(shù)目和端點數(shù)目。USB接口在內(nèi)核中使用 usb_interface 結(jié)構(gòu)體描述,USB 接口描述符定義為結(jié)構(gòu)體 usb_interface_descriptor,其代碼如下:
struct usb interface descriptor{_ _u8 bLength; // 述符長度_ _u8 bDescriptorType; // 述符類型_ _ u8 bInterfaceNumber; // 接口的編號_ _u8 bAlternateSetting; //備用的接口 述符編號_ _u8 bNumEndpoints; //該接口使用的端點數(shù),不包括端點0_ _ u8 bInterfaceClass; //接口類型_ _ u8 bInterfaceSubClass; //接口子類型_ _ u8 bInterfaceProtocol; //接口所遵循的協(xié)議_ _ u8 iInterface; // 述該接口的字符串索引值} _ _attribute_ _ ((packed));端點描述符:端點地址、方向和類型,支持的最大包大小,如果是中斷類型的端點則還包括輪詢頻率。在 Linux 內(nèi)核中,U SB 端點使用 usb_host_endpoint 結(jié)構(gòu)體來描述,USB端點描述符定義為 usb_ endpoint_ descriptor 結(jié)構(gòu)體,其代碼如下:
struct usb endpoint descriptor{_ _u8 bLength; // 述符長度_ _u8 bDescriptorType; // 述符類型_ _u8 bEndpointAddress; //端點地址:0 ~3 位是端點號,第 7 位是方向 (0-OUT,1-IN)_ _ u8 bmAttributes; //端點屬性:bit[0:1] 的值為00表示控制,為01表示同步,為02表示批量,為03表示中_ _le16 wMaxPacketSize; 本端點接收或發(fā)送的最大信息包的大小_ _u8 bInterval; //輪詢數(shù)據(jù)傳送端點的時間間隔//對于批量傳送的端點以及控制傳送的端點,此域忽略//對于同步傳送的端點,此域必須為1//對于中 傳送的端點,此域值的范圍為1~255_ _u8 bRefresh;_ _u8 bSynchAddress;} _ _attribute_ _ ((packed));字符串描述符:在其他描述符中會為某些字段提供字符串索引,它們被用來檢索描述性字符串,可以以多種語言形式提供。字符串描述符是可選的,有的設(shè)備有,有的設(shè)備沒有 ,字符 串描述符對應(yīng)于usb_string_ descriptor 結(jié)構(gòu)體,其代碼如下:
struct usb string descriptor{_ _u8 bLength; // 述符長度_ _u8 bDescriptorType; // 述符類型_ _le16 wData [1]; /* 以UTF-16LE編碼 */} _ _attribute_ _ ((packed));2 USB主機驅(qū)動
USB 主機控制器有 3 種規(guī)格:OHCI (Open Host Controller Interface) 、UHCI (Universal Host Controller Interface) 和EHCI (Enhanced Host Controller Interface) 。
2.1 主機控制器驅(qū)動
在Linux 內(nèi)核中,用usb_hcd 結(jié)構(gòu)體描述USB 主機控制器驅(qū)動,它包含USB 主機控制器的 “家務(wù)”信息、硬件資源、狀態(tài)描述和用于操作主機控制器的 hc_driver等,其代碼如下:
struct usb hcd{/* 管理 “家務(wù)” */struct usb bus self;const char *product desc; /* 產(chǎn)品/廠商字符串 */char irq descr [24]; /* 驅(qū)動 + 總線 # */struct timer list rh timer; /* 根Hub 輪詢 */struct urb *status urb; /* 目前的狀態(tài)urb *//* 硬件信息/狀態(tài) */const struct hc driver *driver; /* 硬件特定的鉤子函數(shù) *//* 需要維護的標(biāo)志 */unsigned long flags;#define HCD FLAG HW ACCESSIBLE 0x00000001#define HCD FLAG SAW IRQ 0x00000002unsigned rh_registered: 1; /* 根Hub 注冊? *//* 下一個標(biāo)志的采用只是 “權(quán)益之計”,當(dāng)所有HCDs 支持新的根Hub 輪詢機制后將移除 */unsigned uses new polling: 1;unsigned poll rh: 1; /* 輪詢根Hub 狀態(tài)? */unsigned poll pending: 1; /* 狀態(tài)已經(jīng)改變? */int irq; /* 被分配的irq */ <br>void _ _iomem *regs; /* 設(shè)備內(nèi)存和I/O */u64 rsrc start; /* 內(nèi)存和I/O資源開始位置 */u64 rsrc len; /* 內(nèi)存和I/O資源長度 */unsigned power budget; /* mA, 0 = 無限制 */#define HCD BUFFER POOLS 4struct dma pool *pool[HCD BUFFER POOLS];int state;#define ACTIVE 0x01#define SUSPEND 0x04#define TRANSIENT 0x80#define HC STATE HALT 0#define HC STATE RUNNING ( ACTIVE)#define HC STATE QUIESCING ( SUSPEND| TRANSIENT| ACTIVE)#define HC STATE RESUMING ( SUSPEND| TRANSIENT)#define HC STATE SUSPENDED ( SUSPEND)#define HC IS RUNNING (state) ((state) & ACTIVE)#define HC IS SUSPENDED(state) ((state) & SUSPEND)/* 主機控制器驅(qū)動的私有數(shù)據(jù) */ <br>unsigned long hcd priv [0] attribute ((aligned (sizeof(unsigned long))));};Linux中采用以下函數(shù)創(chuàng)建HCD:
struct usb hcd *usb create hcd (const struct hc driver *driver, struct device *dev, char *bus name);以下函數(shù)用來增加和移除:
int usb add hcd (struct usb hcd *hcd, unsigned int irqnum, unsigned long irqflags); void usb remove hcd (struct usb hcd *
2.2 OHCI 主機控制器驅(qū)動
OHCI HCD 驅(qū)動屬于HCD 驅(qū)動的實例,它定義了一個ohci_hcd 結(jié)構(gòu)體,使用如下內(nèi)聯(lián)函數(shù)可實現(xiàn)usb_hcd 和ohci_hcd 的相互轉(zhuǎn)換:
struct ohci hcd *hcd to ohci (struct usb hcd *hcd); struct usb hcd *ohci to hcd (const struct ohci hcd *ohci);
從usb_hcd 得到ohci_hcd 只是取得“私有”數(shù)據(jù),而從ohci_hcd 得到usb_hcd 則是通過container_of()從結(jié)構(gòu)體成員獲得結(jié)構(gòu)體指,使用如下函數(shù)可初始化OHCI 主機控制器:
int ohci init (struct ohci hcd *ohci);
如下函數(shù)分別用于開啟、停止及復(fù)位OHCI 控制器:
int ohci run (struct ohci hcd *ohci); void ohci stop (struct usb hcd *hcd); void ohci usb reset (struct ohci hcd *ohci);
3 USB設(shè)備驅(qū)動
3.1 USB設(shè)備驅(qū)動整體結(jié)構(gòu)
有以下設(shè)備類
- 音頻設(shè)備類。
- 通信設(shè)備類。
- HID (人機接口)設(shè)備類。
- 顯示設(shè)備類。
- 海量存儲設(shè)備類。
- 電源設(shè)備類。
- 打印設(shè)備類。
- 集線器設(shè)備類。
Linux 內(nèi)核為各類USB 設(shè)備分配了相應(yīng)的設(shè)備號,內(nèi)核中提供了USB 設(shè)備文件系統(tǒng) (usbdevfs,Linux 2.6 改為usbfs,即USB 文件系統(tǒng)),它和/proc 類似,都是動態(tài)產(chǎn)生的。通過在/etc/fstab 文件中添加如下一行:
none /proc/bus/usb usbfs defaults
或者輸入命令:
mount -t usbfs none /proc/bus/usb
可以實現(xiàn)USB 設(shè)備文件系統(tǒng)的掛載。
此外,在sysfs 文件系統(tǒng)中,同樣包含了USB 相關(guān)信息的描述,但只限于接口級別。USB 設(shè)備和USB 接口在sysfs 中均表示為單獨的USB 設(shè)備,其目錄命名規(guī)則如下:
根集線器-集線器端口號 (-集線器端口號-...):配置.接口。
3.2 USB請求塊(URB)
USB 請求塊 (USB request block,urb )是USB 設(shè)備驅(qū)動中用來描述與USB 設(shè)備通信所用的基本載體和核心數(shù)據(jù)結(jié)構(gòu),非常類似于網(wǎng)絡(luò)設(shè)備驅(qū)動中的sk_buff 結(jié)構(gòu)體,是USB 主機與設(shè)備通信的 “電波”,urb 結(jié)構(gòu)體,代碼如下:
struct urb{/* 私有的:只能由USB核心和主機控制器訪問的字段 */struct kref kref; /*urb 引用計數(shù) */spinlock t lock; /* urb鎖 */void *hcpriv; /* 主機控制器私有數(shù)據(jù) */int bandwidth; /* INT/ISO請求的帶寬 */atomic t use count; /* 并發(fā)傳輸計數(shù) */u8 reject; /* 傳輸將失敗*//* 公共的: 可以被驅(qū)動使用的字段 */struct list head urb list; /* 鏈表頭*/struct usb device *dev; /* 關(guān)聯(lián)的USB 設(shè)備 */unsigned int pipe; /* 管道信息 */int status; /* URB 的當(dāng)前狀態(tài) */ unsigned int transfer flags; /* URB SHORT NOT OK | ...*/void *transfer buffer; /* 發(fā)送數(shù)據(jù)到設(shè)備或從設(shè)備接收數(shù)據(jù)的緩沖區(qū) */dma addr t transfer dma; /*用來以DMA 方式向設(shè)備傳輸數(shù)據(jù)的緩沖區(qū) */int transfer buffer length;/*transfer buffer 或 transfer dma 指向緩沖區(qū)的大小 */ int actual length; /* URB 結(jié)束后,發(fā)送或接收數(shù)據(jù)的實際長度 */unsigned char *setup packet; /* 指向控制URB 的設(shè)置數(shù)據(jù)包的指針*/dma addr t setup dma; /*控制URB 的設(shè)置數(shù)據(jù)包的DMA 緩沖區(qū)*/int start frame; /*等時傳輸中用于設(shè)置或返回初始幀*/int number of packets; /*等時傳輸中等時緩沖區(qū)數(shù)據(jù) */int interval; /* URB被輪詢到的時間間隔 (對中 和等時urb 有效) */int error count; /* 等時傳輸錯誤數(shù)量 */void *context; /* completion 函數(shù)上下文 */usb complete t complete; /* 當(dāng)URB 被完全傳輸或發(fā)生錯誤時,被調(diào)用 */struct usb iso packet descriptor iso frame desc[0];/*單個URB 一次可定義多個等時傳輸時,描述各個等時傳輸 */};USB 設(shè)備中的每個端點都處理一個urb 隊列,在隊列被清空之前,一個urb 的典型生命周期有以下幾個過程:
3.3 簡單的批量與控制URB
1)usb_bulk_msg()
usb_bulk_msg()函數(shù)創(chuàng)建一個USB 批量urb 并將它發(fā)送到特定設(shè)備,這個函數(shù)是同步的,它一直等待urb 完成后才返回。usb_bulk_msg()函數(shù)的原型為:
int usb bulk msg (struct usb device *usb dev, unsigned int pipe, void *data, int len, int *actual length, int timeout); //usb_dev 參數(shù)為批量消息要發(fā)送的USB //設(shè)備的指 ,pipe 為批量消息要發(fā)送到的 USB 設(shè)備的端點,data 參數(shù)為指向要發(fā)送或接收的數(shù)據(jù) //緩沖區(qū)的指 ,len 參數(shù)為data 參數(shù)//所指向的緩沖區(qū)的長度,actual_length 用于返回實際發(fā)送 //或接收的字節(jié)數(shù),timeout 是發(fā)送超時,以ji ffies 為單位,0 意味著永遠等待。 // 如果函數(shù)調(diào)用成功,返回0 ;否則,返回1 個負的錯誤值。2 )usb_control_msg()函數(shù)
usb_control_msg() 函數(shù)與 usb_bulk_msg() 函數(shù)類似,不過它提供驅(qū)動發(fā)送和結(jié)束USB 控制信息而非批量信息的能力,該函數(shù)的原型為:
int usb control msg (struct usb device *dev, unsigned int pipe, u8 request, _ _u8 requesttype, _ _u16 value, _ _u16 index, void *data, _ _u16 size, int timeout); //dev 指向控制消息發(fā)往的USB 設(shè)備,pipe 是控制消息要發(fā)往的USB 設(shè)備的端點, request 是這個控制消息的USB 請求值,requesttype 是這個控制消息的USB 請求類型, //value 是這個控制消息的USB 消息值,index 是這個控制消息的USB 消息索引值,data 指向要發(fā)送或接收的數(shù)據(jù)緩沖區(qū),size
3) 探測和斷開函數(shù)
在USB 設(shè)備驅(qū)動usb_driver 結(jié)構(gòu)體的探測函數(shù)中,應(yīng)該完成如下工作:
- 探測設(shè)備的端點地址、緩沖區(qū)大小,初始化任何可能用于控制 USB 設(shè)備的數(shù)據(jù)結(jié)構(gòu)。
- 把已初始化數(shù)據(jù)結(jié)構(gòu)的指 保存到接口設(shè)備中
- 注冊USB 設(shè)備
對探測函數(shù)的調(diào)用發(fā)生在USB 設(shè)備被安裝且USB 核心認(rèn)為該驅(qū)動程序與安裝的USB 設(shè)備對應(yīng)時 (usb_driver 的id_table 成員在此時發(fā)揮作用),而對斷開函數(shù)的調(diào)用則發(fā)生在驅(qū)動因為種種原因不再控制該設(shè)備的時候。對這兩個函數(shù)的調(diào)用都是在內(nèi)核線程中進行的.
4) USB 骨架程序
Linux 內(nèi)核源代碼中的 driver/usb/usb-skeleton.c 文件為我們提供了一個最基礎(chǔ)的USB 驅(qū)動程序,即USB 骨架程序,可被看做一個最簡單的USB 設(shè)備驅(qū)動實例。盡管USB驅(qū)動驅(qū)動程序千差萬別,但是骨架程序萬變不離其宗。這里我也不多介紹啦~
總結(jié)
以上是生活随笔為你收集整理的usb接口驱动_乾坤合一~Linux设备驱动之USB主机和设备驱动的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 紫光内存:性能、稳定性、品质三重保障,打
- 下一篇: sTC8G1K08+通过串口显示内部电压