本帖最后由 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è)接口(功能)對(duì)應(yīng)一個(gè)USB驅(qū)動(dòng)。 例如: 我們要為一個(gè)電視機(jī)增加一個(gè)USB接口,可以通過接入筆記本來播放筆記本中各種視頻或者音樂。那么電視機(jī)就是一個(gè)USB設(shè)備。 若電視劇具備視頻、音頻兩種功能,那么就可以使用兩個(gè)接口來對(duì)應(yīng)視頻、音頻功能。這兩個(gè)接口使用兩個(gè)USB驅(qū)動(dòng)來編寫,一個(gè)對(duì)應(yīng)視頻子系統(tǒng)、一個(gè)對(duì)應(yīng)音頻子系統(tǒng)。 對(duì)于端點(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; // 指定某種具體的識(shí)別
__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)
注冊(cè)一個(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è)備號(hào)
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è)備串號(hào)
//...
};
/* USB 設(shè)備描述符 USB 協(xié)議規(guī)定 261(290/60)頁 */
struct usb_device_descriptor {
__u8 bLength;//設(shè)備描述符的字節(jié)數(shù)大小,為0x12
__u8 bDescriptorType;//描述符類型編號(hào),為0x01
__le16 bcdUSB;//USB版本號(hào)
__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;//廠商編號(hào)
__le16 idProduct;//產(chǎn)品編號(hào)
__le16 bcdDevice;//設(shè)備出廠編號(hào)
__u8 iManufacturer;//描述廠商字符串的索引
__u8 iProduct;//描述產(chǎn)品字符串的索引
__u8 iSerialNumber;//描述設(shè)備序列號(hào)字符串的索引
__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;//描述符類型編號(hào),為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 {
// 本接口對(duì)應(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è)備號(hào)
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)識(shí)卸載interface */
unsigned needs_remote_wakeup: 1; /* 驅(qū)動(dòng)要求遠(yuǎn)程喚醒 */
unsigned needs_altsetting0: 1; /* 當(dāng)設(shè)置0被推遲時(shí)標(biāo)識(shí) */
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è)備號(hào)的時(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;//描述符類型編號(hào),為0x01
__u8 bInterfaceNumber;//接口的編號(hào)
__u8 bAlternateSetting;//備用的接口描述符編號(hào)
__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)體來對(duì)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; //本端口對(duì)應(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;//描述符類型編號(hào),為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;//描述符類型編號(hào),為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ì)議模式等)可以改變,每種場(chǎng)景就算是一個(gè)設(shè)置。
6、USB通信載體 --- URB
URB -> USB 請(qǐng)求塊,是 USB 設(shè)備驅(qū)動(dòng)中用來描述與 USB 設(shè)備通信所用的基本載體和核心數(shù)據(jù)結(jié)構(gòu)。 也就是說每次 USB 設(shè)備驅(qū)動(dòng)都是通過構(gòu)造一個(gè) URB 的請(qǐng)求塊通過 USB Core 傳遞給 USB 主控制器驅(qū)動(dòng)程序解析,將請(qǐng)求塊的數(shù)據(jù)發(fā)送到請(qǐng)求塊指定的 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)識(shí)(如 GFP_KERNEL),參考 kmalloc.
b)初始化 URB i.對(duì)于中斷 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)所對(duì)應(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 所請(qǐng)求的操作時(shí),會(huì)調(diào)用此回調(diào)函數(shù)。 Context: Complete_fn()函數(shù)所需的上下文,通常取值dev。 interval: urb被調(diào)度的時(shí)間間隔。 ii.對(duì)于批量 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.對(duì)于控制 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.對(duì)于 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)識(shí),它用于告知 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 ,意味著對(duì)于一個(gè)輸出類型 urb,請(qǐng)求數(shù)據(jù)被成功發(fā)送。對(duì)于一個(gè)輸入類型 urb,請(qǐng)求的數(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)用。
|