USB是主機和外圍設備之間的一種連接。USB最初是為了替代各種各樣的不同的接口的低速總線而設計的。(例如:串口,并口,鍵盤連接等)。它以單一類型的總線連接各種不同類型的設備。
USB拓撲機構不是以總線方式的。而是一棵由幾個點對點的連接構成的樹。連接線由4根電纜組成(電源,地線,兩個數(shù)據(jù)線)
USB主控制器(Host Controller)負責詢問每一個USB設備是否有數(shù)據(jù)需要發(fā)送。也就是說:一個USB設備在沒有主控制器要求的情況下是不能發(fā)送數(shù)據(jù)的。
USB協(xié)議規(guī)范定義了一套任何特定類型的設備都可以遵循的標準。如果一個設備遵循該設備,就不需要一個特殊的驅動程序。這些不同的特定類型稱之為類(class).例如:存儲設備,鍵盤,鼠標,游戲桿,網(wǎng)絡設備等。對于不符合這些類的其他設備。則需要對此設備編寫特定driver.
USB設備構成:
Linux Kernel提供了USB Core來處理大部分USB的復雜性。寫USB驅動,Sam覺得就是把USB硬件設備和USB Core之間給溝通起來。
USB協(xié)議把一個硬件USB設備用以下各個定義勾畫出來。
概念一. USB 端點(endpoint)
USB endpoint只能往一個方向傳送數(shù)據(jù)。從主機到設備(輸出Endpoint)或從設備到主機(輸入Endpoint)。一個Endpoint可以看作一個單向的管道。
有四種類型Endpoint,他們的區(qū)別在于傳送數(shù)據(jù)的方式:
控制Endpoint:
用來控制對USB設備不同部分的訪問。他們通常用于配置設備,獲取設備信息,發(fā)送命令到設備,或者獲取設備的狀態(tài)報告。每個USB設備都有一個名為:Endpoint0的控制Endpoint。USB Core使用該Endpoint0在插入時進行設備的配置。
中斷Endpoint:
每當USB主控制器要求設備傳輸數(shù)據(jù)時,中斷Endpoint就以一個固定的速率來傳送少量的數(shù)據(jù)。
USB Keyboard和Mouse通常使用中斷Endpoint。
請注意,中斷Endpoint和中斷不同,它還是無法主動向USB主控制器發(fā)送數(shù)據(jù)。二是需要等待USB主控制器輪詢。
批量Endpoint:
Bulk Endpoint用來傳輸大批量的數(shù)據(jù)。USB規(guī)范不保證數(shù)據(jù)能在規(guī)定時間內傳輸完成。但保證數(shù)據(jù)完整性。通常打印機,存儲設備和網(wǎng)絡設備使用之。
等時Endpoint:
用來傳輸大批量數(shù)據(jù),但數(shù)據(jù)是否能夠到達,怎無法保證。
通常數(shù)據(jù)收集設備會使用之。
Sam覺得,其實一個設備有多少個以及什么類型的Endpoint。其實是硬件設備在制造階段已經定好的。 USB Core只是去讀取了這些信息,并把這些信息傳送給USB driver.
Linux Kernel中使用struct usb_host_endpoint來描述USB Endpoint。但其實其中的struct usb_endpoint_descriptor才是真正的描述Endpoint的。
struct usb_endpoint_descriptor
{
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress;
__u8 bmAttributes;
__le16 wMaxPacketSize;
__u8 bInterval;
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
bEndpointAddress:
//此Endpoint USB地址。它還包含了Endpoint方向信息。通過掩碼USB_DIR_OUT和USB_DIR_IN判斷是輸出Endpoint還是輸入Endpoint。
bmAttributes;
Endpoint Type,也可以通過掩碼:USB_ENDPOINT_XFER_ISOC等判斷此Endpoint是中斷,等時,控制還是批量Endpoint。
wMaxPacketSize;
該Endpoint一次可以處理的最大字節(jié)數(shù)。雖然driver可以傳送更大的數(shù)據(jù),但實際傳送時,還是會分割成這個大小。
bInterval:
如果是中斷Endpoint,它就是Endpoint的間隔設置。也就是說,中斷請求間隔時間。以毫秒為單位。
概念二:接口(Interface)
數(shù)個Endpoint被捆綁為一個USB Interface。
一個 USB Interface只對應一個邏輯連接,例如鼠標,鍵盤或者音頻流。一個USB設備可以對應多個Interface。例如Sam見過的鼠標鍵盤一起的設備,就有2個Interface,一個鍵盤,一個鼠標。
另外,有些USB揚聲器有2個Interface,一個鍵盤,一個音頻流。
注意:每個USB drver只處理一個USB Interface。所以,一個設備也許會對應多個driver.
所以,USB Core在處理USB設備插入時,會針對不同的Interface喚醒它認為合適的driver。并以參數(shù)的形式把interface傳遞給drver.
Linux Kernel使用struct usb_interface來描述USB Interface。但Interface參數(shù)照例是其中的usb_interface_descriptor。
struct usb_interface
{
struct usb_host_interface *altsetting;
struct usb_host_interface *cur_altsetting;
unsigned num_altsetting;
struct usb_interface_assoc_descriptor *intf_assoc;
int minor;
enum usb_interface_condition condition;
unsigned is_active:1;
unsigned needs_remote_wakeup:1;
struct device dev;
struct device *usb_dev;
int pm_usage_cnt;
};
struct usb_host_interface *altsetting;
Interface結構體數(shù)組,包含了所有可能用于該Interface的可選配置。
struct usb_host_interface *cur_altsetting;
可選配置數(shù)
unsigned num_altsetting;
指向altsetting的指針。當前的Active 設置。
usb_interface_descriptor:Interface描述符
struct usb_interface_descriptor {
//描述符的字節(jié)長度。協(xié)議里規(guī)定,每個描述符必須以一個字節(jié)打頭來表明描述符的長度。接口描述符的bLength應該是9
//描述符的類型。各種描述符的類型都在ch9.h, * Descriptor types ... USB 2.0 spec table 9.5
//接口號。每個配置可以包含多個接口,這個值就是它們的索引值
//接口擁有的端點數(shù)量。這里并不包括端點0
//此Interface所屬Class。例如:HID=0x03
//此值基于bInterfaceClass之上。表明在某個Interface class中的子class。例如:HID中有:USB_INTERFACE_SUBCLASS_BOOT
//同上,HID中就有USB_INTERFACE_PROTOCOL_MOUSE
} __attribute__ ((packed));
概念三:配置
一個或多個USB Interface被捆綁為配置。一個USB設備可以有多個配置,并且可以在多個配置之間切換。
配置:struct usb_host_config
USB設備:usb_device.
綜上所述:
1個USB設備有一個或多個配置
1個配置有一個或多個Interface
一個Interface有一個或多個設置
Interface沒有或有多個Endpoint
USB?。眨遥?/span>
Linux Kernel中的USB代碼通過 urb(USB 請求快)與所有的USB設備通信。
urb被用來以異步方式從特定的USB設備的特定USB Endpoint上接收數(shù)據(jù),或往特定的USB設備的特定USB Endpoint上發(fā)送數(shù)據(jù)。
urb是由USB driver創(chuàng)建的。并分配給特定USB設備的特定Endpoint。并由USB driver提交給USB Core。
一:創(chuàng)建urb.
urb不能在driver中靜態(tài)的定義。因為這樣會破壞USB Core對urb的計數(shù)機制。所以必須使用:
usb_alloc_urb函數(shù)來創(chuàng)建。
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
第一個參數(shù)是:等時數(shù)據(jù)包的數(shù)量。