找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2888|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

學(xué)習(xí)筆記-USB數(shù)據(jù)結(jié)構(gòu)和相應(yīng)接口2

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:140343 發(fā)表于 2016-9-24 22:22 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
本帖最后由 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)用。




分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表