找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2945|回复: 0
打印 上一主题 下一主题
收起左侧

学习笔记-USB数据结构和相应接口2

[复制链接]
跳转到指定楼层
楼主
ID:140343 发表于 2016-9-24 22:22 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
本帖最后由 51hei小林 于 2016-9-24 22:29 编辑

1、Linux USB架构
      
运行Linux的USB主机
   
      
      
   
      
    运行Linux的USB设备      
   
      
USB设备驱动(*)
   
      
Gadget驱动(*)
   
      
USB核心(Core)
   
      
Gadget API
   
      
USB主控制器驱动(UHCI\OHCI\EHCI)
   
      
UDC驱动
   
      
USB主控制器
   
      
USB主控制器
   
      
||=================== 物理电气连接 ===============||
   

2、Linux USB设备驱动程序在Linux所扮演的角色
      
用户层 (各种基于USB的设备: USB网卡、USB串口、U盘、移动硬盘、USB声卡)
   
      
VFS layer
   
      
Block layer
      
(U盘)
   
      
Net layer
      
(USB网卡)
   
      
Char layer
   
      
TTY layer
      
(USB串口)
   
      
   
      
USB设备驱动 (位于不同的内核子系统和USB主控制器直接)
   
      
USB核心层 (为USB驱动提供一个访问和控制USB控制器的软件接口,使其不必考虑USB硬件控制器)
   
      
USB主控制器
   
      
硬件层
   

3、USB设备、配置、接口、端点与驱动之间的关系。
一个设备可能有多个配置,一个配置可以拥有多种接口(功能),每个接口(功能)对应一个USB驱动。
例如:
    我们要为一个电视机增加一个USB接口,可以通过接入笔记本来播放笔记本中各种视频或者音乐。那么电视机就是一个USB设备。
    若电视剧具备视频、音频两种功能,那么就可以使用两个接口来对应视频、音频功能。这两个接口使用两个USB驱动来编写,一个对应视频子系统、一个对应音频子系统。
    对于端点,视频需要传输图像数据、分配率控制等可以通过两个端点来负责传输。音频需要传输音频、音量、音效等数据,可以通过三个端点来负责传输。
4、Linux USB driver 相关的数据结构




/* USB 驱动结构体,每个USB驱动都会需要这个结构体 */

struct usb_driver {

    // USB 名字(可以在 /sys/bus/usb/drivers/ 看到)

    const char *name;

    // 当 USB 核心发现了(id_table)该驱动能够处理USB接口就会回调该函数。

    int (*probe) (struct usb_interface *intf, const struct usb_device_id *id);

    // 当相应的 USB 接口被移除时,会回调该函数用于释放某些资源

    void (*disconnect) (struct usb_interface *intf);

    // ...

    // 本 USB 驱动能够处理的设备列表(只要能符合此设备列表就会回调 probe()函数)

    const struct usb_device_id *id_table;

    // ...

};



/* 声明本驱动所支持的USB类型/设备 */

struct usb_device_id {

    /* which fields to match against? */

    __u16        match_flags;



    /* Used for product specific matches; range is inclusive */

    // 设置这组代表是一个具体的设备(罗技的鼠标)

    __u16        idVendor;        // 制造商 ID 由 USB 组织给某个厂商分配的

    __u16        idProduct;        // 产品 ID

    __u16        bcdDevice_lo;

    __u16        bcdDevice_hi;



    /* Used for device class matches */

    // 设置这组代表是一类设备(例如 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;

};


构造一个设备的宏: USB_DEVICE(vend, prod)
    vend: 厂商ID  由 USB 组织统一给每个厂商分配
    prod: 产品ID  厂商自行分配
例子: 构造一个具体的 USB OV511 摄像头
    #define VEND_OMNIVISION 0x05A9   
    #define PROD_OV511        0x0511   
    USB_DEVICE(VEND_OMNIVISION, PROD_OV511)
构造一类设备的宏: USB_INTERFACE_INFO(cl, sc, pr)
    cl: blnterfaceClass value 类
    sc: blnterfaceSubClass value 子类
    pr: blnterfaceProtocol value 所遵循的协议
例子: 构造一个鼠标类型的 USB 驱动
    USB_INTERFACE_INFO(    USB_INTERFACE_CLASS_HID,
                        USB_INTERFACE_SUBCLASS_BOOT,
                        USB_INTERFACE_PROTOCOL_MOUSE)
注册一个USB驱动:
static inline int usb_register(struct usb_driver *driver)                  
5、usb devices 相关的数据结构

/* USB 设备 */

struct usb_device {

    // USB 设备号

    int        devnum;

    // 设备 ID 字符串

    char        devpath[16];

    u32        route;

    // 设备状态: 未连接,已配置

    enum usb_device_state    state;

    // 高速\全速\低速

    enum usb_device_speed    speed;

    //...

    struct device dev;

    // USB 设备描述符

    struct usb_device_descriptor descriptor;

    struct usb_host_config *config;

    //...

    /* static strings from the device */

    char *product;            // 产品名

    char *manufacturer;        // 厂商名

    char *serial;            // 设备串号



    //...

};



/* USB 设备描述符 USB 协议规定 261(290/60)页 */

struct usb_device_descriptor {

    __u8  bLength;//设备描述符的字节数大小,为0x12

    __u8  bDescriptorType;//描述符类型编号,为0x01



    __le16 bcdUSB;//USB版本号

    __u8  bDeviceClass;//USB分配的设备类代码,0x01~0xfe为标准设备类,0xff为厂商自定义类型



    //0x00不是在设备描述符中定义的,如HID

    __u8  bDeviceSubClass;//usb分配的子类代码,同上,值由USB规定和分配的

    __u8  bDeviceProtocol;//USB分配的设备协议代码,同上

    __u8  bMaxPacketSize0;//端点0的最大包的大小

    __le16 idVendor;//厂商编号

    __le16 idProduct;//产品编号

    __le16 bcdDevice;//设备出厂编号

    __u8  iManufacturer;//描述厂商字符串的索引

    __u8  iProduct;//描述产品字符串的索引

    __u8  iSerialNumber;//描述设备序列号字符串的索引

    __u8  bNumConfigurations;//可能的配置数量

} __attribute__ ((packed));



/* 描述一个配置 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协议规定 */

struct usb_config_descriptor {

    __u8  bLength;//设备描述符的字节数大小,为0x12

    __u8  bDescriptorType;//描述符类型编号,为0x01

    __le16 wTotalLength;//配置所返回的所有数量的大小



    __u8  bNumInterfaces;//此配置所支持的接口数量

    __u8  bConfigurationValue;//Set_Configuration命令需要的参数值

    __u8  iConfiguration;//描述该配置的字符串的索引值

    __u8  bmAttributes;//供电模式的选择

    __u8  bMaxPower;//设备从总线提取的最大电流

} __attribute__ ((packed));



/*Linux kernel 使用此结构来描述 USB 接口*/

struct usb_interface {

    // 本接口对应的所有的设置(与配置不是一个概念)

    struct usb_host_interface *altsetting;

    struct usb_host_interface *cur_altsetting;//当前活跃的设置

    unsigned num_altsetting; //可选设置的数量



    /* If there is an interface association descriptor then it will list

    * the associated interfaces */

    struct usb_interface_assoc_descriptor *intf_assoc;



    int minor; //本接口绑定的次设备号

    enum usb_interface_condition condition; //接口是否绑定

    unsigned sysfs_files_created: 1; /* 文件系统存在的文件的属性 */

    unsigned ep_devs_created: 1; /* endpoint "devices" exist */

    unsigned unregistering: 1; /* 标识卸载interface */

    unsigned needs_remote_wakeup: 1; /* 驱动要求远程唤醒 */

    unsigned needs_altsetting0: 1; /* 当设置0被推迟时标识 */

    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 */



    //当接口被绑定到usb主设备号的时候,它指向文件系统中表示的usb设备

    struct device *usb_dev;

    atomic_t pm_usage_cnt;  /* usage counter for autosuspend */

    struct work_struct reset_ws; /* for resets in atomic context */

};



/* 描述一个接口的设置 */

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协议规定 268(296/650)页 */

struct usb_interface_descriptor {

    __u8  bLength;//设备描述符的字节数大小,为0x12

    __u8  bDescriptorType;//描述符类型编号,为0x01



    __u8  bInterfaceNumber;//接口的编号

    __u8  bAlternateSetting;//备用的接口描述符编号

    __u8  bNumEndpoints;//该接口使用端点数,不包括端点0

    __u8  bInterfaceClass;//接口类型

    __u8  bInterfaceSubClass;//接口子类型

    __u8  bInterfaceProtocol;//接口所遵循的协议

    __u8  iInterface;//描述该接口的字符串索引值

} __attribute__ ((packed));



/* Linux 内核使用此结构体来对USB端点描述符 */

struct usb_host_endpoint {

struct usb_endpoint_descriptor  desc; //端口描述符

struct usb_ss_ep_comp_descriptor ss_ep_comp;//超快速端口描述符

struct list_head  urb_list; //本端口对应的urb链表

void    *hcpriv;

struct ep_device  *ep_dev; /* For sysfs info */



unsigned char *extra;   /* Extra descriptors */

int extralen;

int enabled;//使能的话urb才能被提交到此端口

};



/* USB 端点描述符 USB协议规定 */

struct usb_endpoint_descriptor {

    __u8  bLength;//设备描述符的字节数大小,为0x12

    __u8  bDescriptorType;//描述符类型编号,为0x01



    __u8  bEndpointAddress;//端点地址及输入输出属性

    __u8  bmAttributes;//端点的传输类型属性

    __le16 wMaxPacketSize;//端点收、发的最大包的大小

    __u8  bInterval;//主机查询端点的时间间隔



    /* 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协议规定 */

struct usb_string_descriptor {

    __u8  bLength;//设备描述符的字节数大小,为0x12

    __u8  bDescriptorType;//描述符类型编号,为0x01



    __le16 wData[1];        /* UTF-16LE encoded */

} __attribute__ ((packed));


USB 配置 与 Linux 设置关系: 一个配置包含一个或多个接口、一个接口包含一个或多个设置(功能选项)
: 一个手机可以有多种配置(功能组合),比如可以作为电话,可以接在 PC 作为一个U盘,这两种情况就属于不同的配置。假如该手机选择电话接口(电话功能),那么会有情景模式(室外模式、会议模式等)可以改变,每种场景就算是一个设置。
6、USB通信载体 --- URB
URB -> USB 请求块,是 USB 设备驱动中用来描述与 USB 设备通信所用的基本载体和核心数据结构。
也就是说每次 USB 设备驱动都是通过构造一个 URB 的请求块通过 USB Core 传递给 USB 主控制器驱动程序解析,将请求块的数据发送到请求块指定的 USB 设备。
7、URB 处理流程
a)USB 设备驱动程序创建并初始化一个访问 USB 设备特定端点的 URB ,并提交给 USB Core。
b)USB Core 提交该 URB 到 USB 主控制器驱动程序。
c)USB 主控制器驱动程序根据该 URB 描述的信息来访问指定的 USB 设备中具体的端点。
d)当设备访问结束后,USB 主控制器驱动程序会通过回调函数来通知 USB 设备驱动程序。
8、URB 相关的接口
a)创建 URB
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
iso_packets: URB 所包含的等时数据包的个数(如果是等时传输才会用到,如果不是则为0)
mem_flags: 内存分配标识(如 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 所要访问的设备,指明你要与哪个 USB 设备通讯。
pipe: 要访问的端点所对应的管道,使用 usb_sndintpipe() 或者 usb_rcvintpipe()创建
      管道: 驱动程序的数据缓冲区与一个端点的连接。
transfer_buffer: 要传输的数据的缓冲区。
buffer_length: transfer_buffer 所指缓冲区长度。
Complete_fn: 回调函数。当完成该 urb 所请求的操作时,会调用此回调函数。
Context: Complete_fn()函数所需的上下文,通常取值dev。
interval: urb被调度的时间间隔。
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 那样的初始化函数,我们只能手动地初始化URB。例如等时传输 URB 。
c)提交URB
int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
urb: 执行创建好的 urb 的指针
mem_flags: 内存分配标识,它用于告知 USB 核心如何分配内存缓冲区
9、URB 被提交到USB核心后,USB核心指定USB主控制驱动程序会处理该有三种情况会被认为处理完成。
a)URB被成功发送给设备,并且是设备返回正确的的确认。如果 urb->status == 0 ,意味着对于一个输出类型 urb,请求数据被成功发送。对于一个输入类型 urb,请求的数据被成功收到。
b)如果发送数据到设备或从设备接受数据时发生了错误,urb->status 会记录错误值。
c)urb 被“取消”,这发生在驱动通过 usb_unlink_urb() 或 usb_kill_urb() 函数取消 urb,或 urb 虽然已经提交,而 USB 设备被拔出的情况下。
d)当 urb 处理完成后,urb 完成函数将会被调用。




分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表