Linux下USB子系統軟體結構為
USB
核心(USB驅動,USBD
)處於系統的中心,對於它進行研究是能夠進行USB驅動開發(包括客戶驅動和主機驅動)的第一步。它為用戶端驅動和主機控制器驅動提供了主要資料結構和接
口函數,主要有四類功能:用戶端驅動管理,USB裝置的配置和管理,主機控制器的管理,協議控制命令集和資料轉送的管理。具體代碼主要集中在
linux/drivers/usb下的usb.c, usb.h中
主要資料結構分析
主要有四個資料結構,分別是USB裝置usb_device,儲存了一個USB裝置的資訊,包括裝置地址,裝置描述符,配置描述符,等等
USB匯流排系統usb_bus,儲存了一個USB匯流排系統的資訊,包括匯流排上裝置地址資訊,根集線器,頻寬使用方式等。一個USB匯流排系統肯定有一個主機控制器和一個根集線器。Linux支援多USB匯流排系統
用戶端驅動程式usb_driver,儲存了客戶驅動資訊,包括驅動名稱,以及驅動提供給USB核心使用的函數指標等
(USB Request Block)urb,是進行USB通訊的資料結構。Linux的USB子系統只使用這麼一種資料結構來進行USB通訊,urb包含了建立任何 USB傳輸所需的所有資訊,並貫穿於USB協議棧對資料處理的整個過程。
下面是對各部分進行詳細分析。
struct usb_device { //代表一個USB裝置
int devnum; //分配的裝置地址,1-127
enum {
USB_SPEED_UNKNOWN = 0, /* enumerating */
USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */
USB_SPEED_HIGH /* usb 2.0 */
} speed; //裝置速度,低速/全速/高速
struct usb_device *tt; /* usb1.1 device on usb2.0 bus */,交易處理解譯器
int ttport; /* device/hub port on that tt */裝置所串連的具有交易處理解譯器功能的集線器連接埠
atomic_t refcnt; /* Reference count */引用計數
struct semaphore serialize; //用於同步
unsigned int toggle[2]; /* one bit for each endpoint ([0]
= IN, [1] = OUT) */用於同步切換的位元影像,每個端點佔用1位,[0]表示輸入,[1]輸出
unsigned
int halted[2]; /* endpoint halts; one bit per endpoint # &
direction; [0] = IN, [1] = OUT */表示端點是否處於停止狀態的位元影像
int epmaxpacketin[16]; /* INput endpoint specific maximums */輸入端點的最大包長
int epmaxpacketout[16]; /* OUTput endpoint specific maximums */輸出端點的最大包長
struct usb_device *parent; //表示裝置所連的上遊集線器指標
struct usb_bus *bus; /* Bus we're part of */裝置所屬的USB匯流排系統
struct usb_device_descriptor descriptor;/* Descriptor */ 裝置描述符
struct usb_config_descriptor *config; /* All of the configs */指向裝置的配置描述符和其所包含的介面描述符,端點描述符的指標
struct usb_config_descriptor *actconfig;/* the active configuration */當前的配置描述符指標
char **rawdescriptors; /* Raw descriptors for each config */
int have_langid; /* whether string_langid is valid yet *// 是否有string_langid
int string_langid; /* language ID for strings */和字元描述符相關的語言ID
void *hcpriv; /* Host Controller private data */裝置在HCD層佔用的資源指標,對USB核心層是透明的
/* usbdevfs inode list */ 裝置在usbdevfs中的inode列表
struct list_head inodes;
struct list_head filelist;
/*
* Child devices - these can be either new devices
* (if this is a hub device), or different instances
* of this same device.
*
* Each instance needs its own set of data structures.
*/只對當前裝置是集線器的情況有效
int maxchild; /* Number of ports if hub */ hub的下遊連接埠數
struct usb_device *children[USB_MAXCHILDREN]; hub所連裝置指標
};
struct usb_bus { //USB匯流排系統
int busnum; /* Bus number (in order of reg) */當前匯流排系統的序號,Linux支援多匯流排系統並為它們編號
#ifdef DEVNUM_ROUND_ROBIN
int devnum_next; /* Next open device number in round-robin allocation */
#endif /* DEVNUM_ROUND_ROBIN */給串連到子系統上的裝置分配裝置號的資料結構
struct usb_devmap devmap; /* Device map */給串連到子系統上的裝置分配裝置號的資料結構
struct usb_operations *op; /* Operations (specific to the HC) */HCD為USB核心提供的一系統函數集指標
struct usb_device *root_hub; /* Root hub */指向根Hub的指標
struct list_head bus_list; 雙向鏈表指標,USB核心用一個雙向鏈表來維護系統中所有USB匯流排系統
void *hcpriv; /* Host Controller private data */與主機控制器相關資料,對USB核心層是透明
int bandwidth_allocated; /* on this Host Controller; applies to
Int. and Isoc. pipes; measured in microseconds/frame; range is 0..900,
where 900 = 90% of a 1-millisecond frame
*/當前子系統的頻寬使用方式,單位是毫秒/幀,取值範圍[0,900]
int bandwidth_int_reqs; /* number of Interrupt requesters */子系統中當前的中斷傳輸的數量
int bandwidth_isoc_reqs; /* number of Isoc. requesters */子系統中當前的即時傳輸的數量
/* usbdevfs inode list */ 在usbdevfs中的inode列表 struct list_head inodes;
atomic_t refcnt;
};
struct usb_driver { //用戶端驅動程式為USB核心提供的調用介面
const char *name; //用戶端驅動程式的字串名稱,用於避免重複安裝和卸載
void *(*probe)(//給USB核心提供的函數,用於判斷驅動程式是否能對裝置的某個介面進行驅動,如能則分配資源
struct usb_device *dev, /* the device */
unsigned intf, /* what interface */
const struct usb_device_id *id /* from id_table */
);
void (*disconnect)(struct usb_device *, void *);//給USB核心提供的函數,用於釋放裝置的某個介面所佔用的資源
struct list_head driver_list;//對應的雙向指標,USB核心通過一個雙向指標鏈表維護USB子系統中所用的用戶端驅動程式
struct file_operations *fops;
int minor; 驅動的次版本號碼
struct semaphore serialize;
/* ioctl -- userspace apps can talk to drivers through usbdevfs */
int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
/* support for "new-style" USB hotplugging
* binding policy can be driven from user mode too
*/
const struct usb_device_id *id_table;
/* suspend before the bus suspends;
* disconnect or resume when the bus resumes */
// void (*suspend)(struct usb_device *dev);
// void (*resume)(struct usb_device *dev);
};
typedef struct urb //USB Request Block,包含了建立任何 USB傳輸所需的所有資訊,並貫穿於USB協議棧對資料處理的整個過程
{
spinlock_t lock; // lock for the URB
void *hcpriv; // private data for host controller與主機控制器相關資料,對USB核心層是透明
struct list_head urb_list; // list pointer to all active urbs雙向指標,用於將此URB串連到處於活動的URB雙向鏈表中
struct urb *next; // pointer to next URB 指向下一個URB的指標
struct usb_device *dev; // pointer to associated USB device 接受此URB的USB裝置指標
unsigned int pipe;// pipe information表示裝置的某個端點和用戶端驅動程式之間的管道
int status; // returned status 返回狀態
unsigned int transfer_flags; // USB_DISABLE_SPD | USB_ISO_ASAP | etc.
USB_DISABLE_SPD //拒絕短資料包,即比最大傳輸包長度小的資料包
USB_ISO_ASAP //用於即時傳輸,告訴主機控制器立即進行此請求的資料轉送。如果沒有置位,則需要給start_frame賦值,用來通知主機控制器該在哪個幀上開始此請求的資料轉送
USB_ASYNC_UNLINK //告訴USBD採用非同步方式取消請求
USB_QUEUE_BULK //表示批量請求可以排隊,一般一個裝置的批量請求端點只有一個URB
USB_NO_FSBR //表示全速傳輸站用的頻寬不要回收
USB_ZERO_PACKET //表示批量傳輸的資料長度等於端點的包最大長度時,主機控制器在發送完資料後,再發送一個零長度的包表示資料結束
USB_TIMEOUT_KILLED //本位只被HCD設定,表示發生了逾時。客戶驅動可以給URB的處理設定一個逾時時間,如果處理逾時,則要求USBD結束對此URB的處理,URB的返回資訊中會反映該此狀態。
void *transfer_buffer; // associated data buffer傳輸資料緩衝區指標,接收或發送裝置的資料,它必須是物理連續的,不可換頁的記憶體塊,用kmalloc(,GFP_KERNEL)分配
int transfer_buffer_length; // data buffer length緩衝區長度
int actual_length; // actual data buffer length 實際資料長度
int bandwidth; // bandwidth for this transfer request (INT or ISO) 此請求每次佔用一幀的頻寬,只適用即時/中斷傳輸
unsigned char *setup_packet; // setup packet (control only) 用於指向控制傳輸中控制命令的指標,只適用控制傳輸
int start_frame; // start frame (iso/irq
only)此請求所開始傳輸的幀號,只適用即時/中斷傳輸。中斷傳輸時,表示返回啟動此請求的第一次中斷傳輸的幀號。即時傳輸時,指明處理第一個即時請求
資料報包的幀號,如果設定了USB_ISO_ASAP,此變數表示返回啟動第一次即時傳輸的幀號。
int number_of_packets; // number of packets in this request (iso)此請求所包含的資料包數,只適合即時傳輸
int interval; // polling interval (irq only) 中斷傳輸的周期,1〈= interval〈=255
int error_count; // number of errors in this transfer (iso only)發生傳輸錯誤次數的累加值,只適用即時傳輸
int timeout; // timeout (in jiffies)
void *context; // context for completion routine回呼函數中的參數
usb_complete_t complete; // pointer to completion routine 指向回呼函數的指標。當資料轉送完成後,主機控制器驅動會回調該函數。
iso_packet_descriptor_t iso_frame_desc[0]; 要進行即時傳輸的結構數組,每個結構表示一次資料轉送
} urb_t, *purb_t;