本帖最后由 51hei小林 于 2016-9-24 22:29 編輯
1、Linux USB架構(gòu) 運(yùn)行Linux的USB主機(jī) | | 運(yùn)行Linux的USB設(shè)備 | USB設(shè)備驅(qū)動(dòng)(*) | Gadget驅(qū)動(dòng)(*) | USB核心(Core) | Gadget API | USB主控制器驅(qū)動(dòng)(UHCI\OHCI\EHCI) | UDC驅(qū)動(dòng) | USB主控制器 | USB主控制器 | ||=================== 物理電氣連接 ===============|| |
2、Linux USB設(shè)備驅(qū)動(dòng)程序在Linux所扮演的角色 用戶層 (各種基于USB的設(shè)備: USB網(wǎng)卡、USB串口、U盤、移動(dòng)硬盤、USB聲卡) | VFS layer | Block layer (U盤) | Net layer (USB網(wǎng)卡) | Char layer | TTY layer (USB串口) | …… | USB設(shè)備驅(qū)動(dòng) (位于不同的內(nèi)核子系統(tǒng)和USB主控制器直接) | USB核心層 (為USB驅(qū)動(dòng)提供一個(gè)訪問和控制USB控制器的軟件接口,使其不必考慮USB硬件控制器) | USB主控制器 | 硬件層 |
3、USB設(shè)備、配置、接口、端點(diǎn)與驅(qū)動(dòng)之間的關(guān)系。 一個(gè)設(shè)備可能有多個(gè)配置,一個(gè)配置可以擁有多種接口(功能),每個(gè)接口(功能)對應(yīng)一個(gè)USB驅(qū)動(dòng)。 例如: 我們要為一個(gè)電視機(jī)增加一個(gè)USB接口,可以通過接入筆記本來播放筆記本中各種視頻或者音樂。那么電視機(jī)就是一個(gè)USB設(shè)備。 若電視劇具備視頻、音頻兩種功能,那么就可以使用兩個(gè)接口來對應(yīng)視頻、音頻功能。這兩個(gè)接口使用兩個(gè)USB驅(qū)動(dòng)來編寫,一個(gè)對應(yīng)視頻子系統(tǒng)、一個(gè)對應(yīng)音頻子系統(tǒng)。 對于端點(diǎn),視頻需要傳輸圖像數(shù)據(jù)、分配率控制等可以通過兩個(gè)端點(diǎn)來負(fù)責(zé)傳輸。音頻需要傳輸音頻、音量、音效等數(shù)據(jù),可以通過三個(gè)端點(diǎn)來負(fù)責(zé)傳輸。 4、Linux USB driver 相關(guān)的數(shù)據(jù)結(jié)構(gòu)
/* USB 驅(qū)動(dòng)結(jié)構(gòu)體,每個(gè)USB驅(qū)動(dòng)都會(huì)需要這個(gè)結(jié)構(gòu)體 */
struct usb_driver {
// USB 名字(可以在 /sys/bus/usb/drivers/ 看到)
const char *name;
// 當(dāng) USB 核心發(fā)現(xiàn)了(id_table)該驅(qū)動(dòng)能夠處理USB接口就會(huì)回調(diào)該函數(shù)。
int (*probe) (struct usb_interface *intf, const struct usb_device_id *id);
// 當(dāng)相應(yīng)的 USB 接口被移除時(shí),會(huì)回調(diào)該函數(shù)用于釋放某些資源
void (*disconnect) (struct usb_interface *intf);
// ...
// 本 USB 驅(qū)動(dòng)能夠處理的設(shè)備列表(只要能符合此設(shè)備列表就會(huì)回調(diào) probe()函數(shù))
const struct usb_device_id *id_table;
// ...
};
/* 聲明本驅(qū)動(dòng)所支持的USB類型/設(shè)備 */
struct usb_device_id {
/* which fields to match against? */
__u16 match_flags;
/* Used for product specific matches; range is inclusive */
// 設(shè)置這組代表是一個(gè)具體的設(shè)備(羅技的鼠標(biāo))
__u16 idVendor; // 制造商 ID 由 USB 組織給某個(gè)廠商分配的
__u16 idProduct; // 產(chǎn)品 ID
__u16 bcdDevice_lo;
__u16 bcdDevice_hi;
/* Used for device class matches */
// 設(shè)置這組代表是一類設(shè)備(例如 USB HID 類型)
__u8 bDeviceClass; // 指定某種具體的識別
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
/* Used for interface class matches */
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
/* not matched against */
kernel_ulong_t driver_info;
};
構(gòu)造一個(gè)設(shè)備的宏: USB_DEVICE(vend, prod)
vend: 廠商ID 由 USB 組織統(tǒng)一給每個(gè)廠商分配
prod: 產(chǎn)品ID 廠商自行分配
例子: 構(gòu)造一個(gè)具體的 USB OV511 攝像頭
#define VEND_OMNIVISION 0x05A9
#define PROD_OV511 0x0511
USB_DEVICE(VEND_OMNIVISION, PROD_OV511)
構(gòu)造一類設(shè)備的宏: USB_INTERFACE_INFO(cl, sc, pr)
cl: blnterfaceClass value 類
sc: blnterfaceSubClass value 子類
pr: blnterfaceProtocol value 所遵循的協(xié)議
例子: 構(gòu)造一個(gè)鼠標(biāo)類型的 USB 驅(qū)動(dòng)
USB_INTERFACE_INFO( USB_INTERFACE_CLASS_HID,
USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE)
注冊一個(gè)USB驅(qū)動(dòng):
static inline int usb_register(struct usb_driver *driver)
5、usb devices 相關(guān)的數(shù)據(jù)結(jié)構(gòu)
/* USB 設(shè)備 */
struct usb_device {
// USB 設(shè)備號
int devnum;
// 設(shè)備 ID 字符串
char devpath[16];
u32 route;
// 設(shè)備狀態(tài): 未連接,已配置
enum usb_device_state state;
// 高速\全速\低速
enum usb_device_speed speed;
//...
struct device dev;
// USB 設(shè)備描述符
struct usb_device_descriptor descriptor;
struct usb_host_config *config;
//...
/* static strings from the device */
char *product; // 產(chǎn)品名
char *manufacturer; // 廠商名
char *serial; // 設(shè)備串號
//...
};
/* USB 設(shè)備描述符 USB 協(xié)議規(guī)定 261(290/60)頁 */
struct usb_device_descriptor {
__u8 bLength;//設(shè)備描述符的字節(jié)數(shù)大小,為0x12
__u8 bDescriptorType;//描述符類型編號,為0x01
__le16 bcdUSB;//USB版本號
__u8 bDeviceClass;//USB分配的設(shè)備類代碼,0x01~0xfe為標(biāo)準(zhǔn)設(shè)備類,0xff為廠商自定義類型
//0x00不是在設(shè)備描述符中定義的,如HID
__u8 bDeviceSubClass;//usb分配的子類代碼,同上,值由USB規(guī)定和分配的
__u8 bDeviceProtocol;//USB分配的設(shè)備協(xié)議代碼,同上
__u8 bMaxPacketSize0;//端點(diǎn)0的最大包的大小
__le16 idVendor;//廠商編號
__le16 idProduct;//產(chǎn)品編號
__le16 bcdDevice;//設(shè)備出廠編號
__u8 iManufacturer;//描述廠商字符串的索引
__u8 iProduct;//描述產(chǎn)品字符串的索引
__u8 iSerialNumber;//描述設(shè)備序列號字符串的索引
__u8 bNumConfigurations;//可能的配置數(shù)量
} __attribute__ ((packed));
/* 描述一個(gè)配置 Linux 特有*/
struct usb_host_config {
// USB 配置描述符
struct usb_config_descriptor desc;
char *string; /* iConfiguration string, if present */
/* List of any Interface Association Descriptors in this
* configuration. */
struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];
/* the interfaces associated with this configuration,
* stored in no particular order */
struct usb_interface *interface[USB_MAXINTERFACES];
/* Interface information available even when this is not the
* active configuration */
struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];
unsigned char *extra; /* Extra descriptors */
int extralen;
};
/* USB 配置描述符 USB協(xié)議規(guī)定 */
struct usb_config_descriptor {
__u8 bLength;//設(shè)備描述符的字節(jié)數(shù)大小,為0x12
__u8 bDescriptorType;//描述符類型編號,為0x01
__le16 wTotalLength;//配置所返回的所有數(shù)量的大小
__u8 bNumInterfaces;//此配置所支持的接口數(shù)量
__u8 bConfigurationValue;//Set_Configuration命令需要的參數(shù)值
__u8 iConfiguration;//描述該配置的字符串的索引值
__u8 bmAttributes;//供電模式的選擇
__u8 bMaxPower;//設(shè)備從總線提取的最大電流
} __attribute__ ((packed));
/*Linux kernel 使用此結(jié)構(gòu)來描述 USB 接口*/
struct usb_interface {
// 本接口對應(yīng)的所有的設(shè)置(與配置不是一個(gè)概念)
struct usb_host_interface *altsetting;
struct usb_host_interface *cur_altsetting;//當(dāng)前活躍的設(shè)置
unsigned num_altsetting; //可選設(shè)置的數(shù)量
/* If there is an interface association descriptor then it will list
* the associated interfaces */
struct usb_interface_assoc_descriptor *intf_assoc;
int minor; //本接口綁定的次設(shè)備號
enum usb_interface_condition condition; //接口是否綁定
unsigned sysfs_files_created: 1; /* 文件系統(tǒng)存在的文件的屬性 */
unsigned ep_devs_created: 1; /* endpoint "devices" exist */
unsigned unregistering: 1; /* 標(biāo)識卸載interface */
unsigned needs_remote_wakeup: 1; /* 驅(qū)動(dòng)要求遠(yuǎn)程喚醒 */
unsigned needs_altsetting0: 1; /* 當(dāng)設(shè)置0被推遲時(shí)標(biāo)識 */
unsigned needs_binding: 1; /* needs delayed unbind/rebind */
unsigned reset_running: 1;
unsigned resetting_device: 1; /* true: bandwidth alloc after reset */
struct device dev; /* interface specific device info */
//當(dāng)接口被綁定到usb主設(shè)備號的時(shí)候,它指向文件系統(tǒng)中表示的usb設(shè)備
struct device *usb_dev;
atomic_t pm_usage_cnt; /* usage counter for autosuspend */
struct work_struct reset_ws; /* for resets in atomic context */
};
/* 描述一個(gè)接口的設(shè)置 */
struct usb_host_interface {
struct usb_interface_descriptor desc;
/* array of desc.bNumEndpoint endpoints associated with this
* interface setting. these will be in no particular order.
*/
struct usb_host_endpoint *endpoint;
char *string; /* iInterface string, if present */
unsigned char *extra; /* Extra descriptors */
int extralen;
};
/* USB 接口描述符 USB協(xié)議規(guī)定 268(296/650)頁 */
struct usb_interface_descriptor {
__u8 bLength;//設(shè)備描述符的字節(jié)數(shù)大小,為0x12
__u8 bDescriptorType;//描述符類型編號,為0x01
__u8 bInterfaceNumber;//接口的編號
__u8 bAlternateSetting;//備用的接口描述符編號
__u8 bNumEndpoints;//該接口使用端點(diǎn)數(shù),不包括端點(diǎn)0
__u8 bInterfaceClass;//接口類型
__u8 bInterfaceSubClass;//接口子類型
__u8 bInterfaceProtocol;//接口所遵循的協(xié)議
__u8 iInterface;//描述該接口的字符串索引值
} __attribute__ ((packed));
/* Linux 內(nèi)核使用此結(jié)構(gòu)體來對USB端點(diǎn)描述符 */
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc; //端口描述符
struct usb_ss_ep_comp_descriptor ss_ep_comp;//超快速端口描述符
struct list_head urb_list; //本端口對應(yīng)的urb鏈表
void *hcpriv;
struct ep_device *ep_dev; /* For sysfs info */
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled;//使能的話urb才能被提交到此端口
};
/* USB 端點(diǎn)描述符 USB協(xié)議規(guī)定 */
struct usb_endpoint_descriptor {
__u8 bLength;//設(shè)備描述符的字節(jié)數(shù)大小,為0x12
__u8 bDescriptorType;//描述符類型編號,為0x01
__u8 bEndpointAddress;//端點(diǎn)地址及輸入輸出屬性
__u8 bmAttributes;//端點(diǎn)的傳輸類型屬性
__le16 wMaxPacketSize;//端點(diǎn)收、發(fā)的最大包的大小
__u8 bInterval;//主機(jī)查詢端點(diǎn)的時(shí)間間隔
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
/* USB 字符串描述符 USB協(xié)議規(guī)定 */
struct usb_string_descriptor {
__u8 bLength;//設(shè)備描述符的字節(jié)數(shù)大小,為0x12
__u8 bDescriptorType;//描述符類型編號,為0x01
__le16 wData[1]; /* UTF-16LE encoded */
} __attribute__ ((packed));
USB 配置 與 Linux 設(shè)置關(guān)系: 一個(gè)配置包含一個(gè)或多個(gè)接口、一個(gè)接口包含一個(gè)或多個(gè)設(shè)置(功能選項(xiàng))
例: 一個(gè)手機(jī)可以有多種配置(功能組合),比如可以作為電話,可以接在 PC 作為一個(gè)U盤,這兩種情況就屬于不同的配置。假如該手機(jī)選擇電話接口(電話功能),那么會(huì)有情景模式(室外模式、會(huì)議模式等)可以改變,每種場景就算是一個(gè)設(shè)置。
6、USB通信載體 --- URB
URB -> USB 請求塊,是 USB 設(shè)備驅(qū)動(dòng)中用來描述與 USB 設(shè)備通信所用的基本載體和核心數(shù)據(jù)結(jié)構(gòu)。 也就是說每次 USB 設(shè)備驅(qū)動(dòng)都是通過構(gòu)造一個(gè) URB 的請求塊通過 USB Core 傳遞給 USB 主控制器驅(qū)動(dòng)程序解析,將請求塊的數(shù)據(jù)發(fā)送到請求塊指定的 USB 設(shè)備。 7、URB 處理流程 a)USB 設(shè)備驅(qū)動(dòng)程序創(chuàng)建并初始化一個(gè)訪問 USB 設(shè)備特定端點(diǎn)的 URB ,并提交給 USB Core。 b)USB Core 提交該 URB 到 USB 主控制器驅(qū)動(dòng)程序。 c)USB 主控制器驅(qū)動(dòng)程序根據(jù)該 URB 描述的信息來訪問指定的 USB 設(shè)備中具體的端點(diǎn)。 d)當(dāng)設(shè)備訪問結(jié)束后,USB 主控制器驅(qū)動(dòng)程序會(huì)通過回調(diào)函數(shù)來通知 USB 設(shè)備驅(qū)動(dòng)程序。 8、URB 相關(guān)的接口 a)創(chuàng)建 URB
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
iso_packets: URB 所包含的等時(shí)數(shù)據(jù)包的個(gè)數(shù)(如果是等時(shí)傳輸才會(huì)用到,如果不是則為0)
mem_flags: 內(nèi)存分配標(biāo)識(如 GFP_KERNEL),參考 kmalloc.
b)初始化 URB i.對于中斷 URB static inline 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_fn, void *context, int interval); urb: 要初始化的 urb 指針 dev: urb 所要訪問的設(shè)備,指明你要與哪個(gè) USB 設(shè)備通訊。 pipe: 要訪問的端點(diǎn)所對應(yīng)的管道,使用 usb_sndintpipe() 或者 usb_rcvintpipe()創(chuàng)建 管道: 驅(qū)動(dòng)程序的數(shù)據(jù)緩沖區(qū)與一個(gè)端點(diǎn)的連接。 transfer_buffer: 要傳輸?shù)臄?shù)據(jù)的緩沖區(qū)。 buffer_length: transfer_buffer 所指緩沖區(qū)長度。 Complete_fn: 回調(diào)函數(shù)。當(dāng)完成該 urb 所請求的操作時(shí),會(huì)調(diào)用此回調(diào)函數(shù)。 Context: Complete_fn()函數(shù)所需的上下文,通常取值dev。 interval: urb被調(diào)度的時(shí)間間隔。 ii.對于批量 URB static inline 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_fn, void *context); iii.對于控制 URB
static inline void usb_fill_control_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, unsigned char *setup_packet, void *transfer_buffer, int buffer_length, usb_complete_t complete_fn, void *context) iv.對于 URB 沒有像中斷、控制和批量 URB 那樣的初始化函數(shù),我們只能手動(dòng)地初始化URB。例如等時(shí)傳輸 URB 。 c)提交URB
int usb_submit_urb(struct urb *urb, gfp_t mem_flags); urb: 執(zhí)行創(chuàng)建好的 urb 的指針 mem_flags: 內(nèi)存分配標(biāo)識,它用于告知 USB 核心如何分配內(nèi)存緩沖區(qū)
9、URB 被提交到USB核心后,USB核心指定USB主控制驅(qū)動(dòng)程序會(huì)處理該有三種情況會(huì)被認(rèn)為處理完成。 a)URB被成功發(fā)送給設(shè)備,并且是設(shè)備返回正確的的確認(rèn)。如果 urb->status == 0 ,意味著對于一個(gè)輸出類型 urb,請求數(shù)據(jù)被成功發(fā)送。對于一個(gè)輸入類型 urb,請求的數(shù)據(jù)被成功收到。 b)如果發(fā)送數(shù)據(jù)到設(shè)備或從設(shè)備接受數(shù)據(jù)時(shí)發(fā)生了錯(cuò)誤,urb->status 會(huì)記錄錯(cuò)誤值。 c)urb 被“取消”,這發(fā)生在驅(qū)動(dòng)通過 usb_unlink_urb() 或 usb_kill_urb() 函數(shù)取消 urb,或 urb 雖然已經(jīng)提交,而 USB 設(shè)備被拔出的情況下。 d)當(dāng) urb 處理完成后,urb 完成函數(shù)將會(huì)被調(diào)用。
|