Linux USB驱动源代码分析
+ -

USB驱动数据结构usb_device/usb_host_config/usb_interface/usb_host_interface/usb_host_endpoint

2024-03-07 495 1

相对于USB规范中的USB相关描述符,Linux定义了几个相关的结构体。这几个结构体可在以下位置查看:
https://elixir.bootlin.com/linux/v5.5-rc2/source/include/linux/usb.h

以下介绍的USB结构体关系如下:
USB结构体关系图

struct usb_device USB设备

usb_device代表着一个USB设备。其结构体定义如下:

struct usb_device {
    int devnum;         //devnum只是usb设备在一条usb总线上的编号.一条usb_bus_type类型的总线上最多可以连上128个设备
    char devpath [16];   /* Use in messages: /port/port/...*/  //对于root hub.会将dev->devpath[0]=’0’
    enum usb_device_state   state;  //设备的状态Attached,Powered,Default,Address,Configured,Suspended;
 //Attached表示设备已经连接到usb接口上了,是hub检测到设备时的初始状态。那么这里所谓的USB_STATE_NOTATTACHED就是表示设备并没有Attached。
//Address状态表示主机分配了一个唯一的地址给设备,此时设备可以使用缺省管道响应主机的请求
 //Configured状态表示设备已经被主机配置过了,也就是协议里说的处理了一个带有非0值的SetConfiguration()请求,此时主机可以使用设备提供的所有功能
//Suspended挂起状态,为了省电,设备在指定的时间内,3ms吧,如果没有发生总线传输,就要进入挂起状态。此时,usb设备要自己维护包括地址、配置在内的信息.

    enum usb_device_speed   speed;  /* high/full/low (or error) */
    struct usb_tt   *tt;            //如果一个高速设备里有这么一个TT,那么就可以连接低速/全速设备,如不然,那低速/全速设备没法用,只能连接到OHCI/UHCI那边出来的hub口里。
    int             ttport;         //如果一个高速设备里有这么一个TT,那么就可以连接低速/全速设备,如不然,那低速/全速设备没法用,只能连接到OHCI/UHCI那边出来的hub口里。

    unsigned int toggle[2];         /* one bit for each endpoint     //他实际上就是一个位图.IN方向的是toggle[0].OUT方向的是toggle[1].其实,这个数组中的每一位表示ep的toggle值
                                             * ([0] = IN, [1] = OUT) */它里面的每一位表示的就是每个端点当前发送或接收的数据包是DATA0还是DATA1

    struct usb_device *parent;      /* our hub, unless we're the root */
                              //USB设备是从Root Hub开始,一个一个往外面连的,比如Root Hub有4个口,每个口连一个USB设备,比如其中有一个是Hub,那么这个Hub有可以继续有多个口,于是一级一级的往下连,
                               //最终连成了一棵树。
    struct usb_bus *bus;            /* Bus we're part of */设备所在的总线
    struct usb_host_endpoint ep0;   //端点0的特殊地位决定了她必将受到特殊的待遇,在struct usb_device对象产生的时候它就要初始化

    struct device dev;              /* Generic device interface */嵌入到struct usb_device结构里的struct device结构

    struct usb_device_descriptor descriptor;/* Descriptor */设备描述符,此结构体的bMaxPacketSize0 filed保存了端点0的maximum packet size
    struct usb_host_config *config; //设备拥有的所有配置

    struct usb_host_config *actconfig;//设备正在使用的配置
    struct usb_host_endpoint *ep_in[16];//ep_in[16],359行,ep_out[16],除了端点0,一个设备即使在高速模式下也最多只能再有15个IN端点和15个OUT端点,端点0太特殊了,
    struct usb_host_endpoint *ep_out[16];//对应的管道是Message管道,又能进又能出特能屈能伸的那种,所以这里的ep_in和ep_out数组都有16个值

    char **rawdescriptors;          /* Raw descriptors for each config */

    unsigned short bus_mA;          /* Current available from the bus */这个值是在host controller的驱动程序中设置的,通常来讲,计算机的usb端口可以提供500mA的电流
    u8 portnum;                     //不管是root hub还是一般的hub,你的USB设备总归要插在一个hub的端口上才能用,portnum就是那个端口号。
    u8 level;                       //层次,也可以说是级别,表征usb设备树的级连关系。Root Hub的level当然就是0,其下面一层就是level 1,再下面一层就是level 2,依此类推

    unsigned discon_suspended:1;    /* Disconnected while suspended */
    unsigned have_langid:1;         /* whether string_langid is valid */
    int string_langid;              /* language ID for strings */

    /* static strings from the device */
    char *product;                  /* iProduct string, if present */
    char *manufacturer;             /* iManufacturer string, if present */
    char *serial;                   /* iSerialNumber string, if present */
                                    //分别用来保存产品、厂商和序列号对应的字符串描述符信息

    struct list_head filelist;
#ifdef CONFIG_USB_DEVICE_CLASS
    struct device *usb_classdev;
#endif

#ifdef CONFIG_USB_DEVICEFS
    struct dentry *usbfs_dentry;    /* usbfs dentry entry for the device */
#endif
    /*
    * 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 */
    struct usb_device *children[USB_MAXCHILDREN];

    int pm_usage_cnt;               /* usage counter for autosuspend */
    u32 quirks;                     //quirk就是用来判断这些有毛病的产品啥毛病的

#ifdef CONFIG_PM
    struct delayed_work autosuspend; /* for delayed autosuspends */
    struct mutex pm_mutex;          /* protects PM operations */
    unsigned long last_busy;        /* time of last use */
    int autosuspend_delay;          /* in jiffies */

    unsigned auto_pm:1;             /* autosuspend/resume in progress */
    unsigned do_remote_wakeup:1;    /* remote wakeup should be enabled */
    unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
    unsigned autoresume_disabled:1;  /*  disabled by the user */
#endif
};

struct usb_host_config 配置

usb_host_config用于struct usb_device结构体中设备的配置。

struct usb_host_config {
    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]; //usb接口的缓存

    unsigned char *extra;   /* Extra descriptors */
    int extralen;
};

struct usb_interface 接口函数

usb_interface字面意思既是接口,什么的接口:设备的接口。

为什么会出现这样的类型出来,根据实际情况,例如:
一个设备有两种功能 一个键盘 一个音频,两种接口,那这样肯定得要两个驱动程序,一个是键盘驱动程序,一个是音频流驱动程序。两种功能整合在一起称为一个设备。但是不同的接口需要不同的驱动,音频驱动 和键盘驱动。用interface来区分,就有了接口类型。

struct usb_interface {
    /* array of alternate settings for this interface,
    * stored in no particular order */
    struct usb_host_interface *altsetting;  // 当前接口的可选设置
    /* the currently active alternate setting */
    struct usb_host_interface *cur_altsetting;  // 当前接口使用的设置
    /* number of alternate settings */ 
    unsigned num_altsetting;  // 当前接口具有的可选设置总数

    /* If there is an interface association descriptor then it will list
    * the associated interfaces */
    struct usb_interface_assoc_descriptor *intf_assoc;
    /* minor number this interface is * bound to */ 
    int minor;   // 当前接口的在主设备号为USB_MAJOR时的子设备号,minor只在USB_MAJOR起作用时起
作用。 usb设备没有与其它任何子系统关联,就需要在对应驱动的probe函数里使用usb_register_dev函数来注册并获得主设备号USB_MAJOR。如果usb设备关联了其它子系统,则需要在对应驱动的probe函数里使用相应的注册函数,USB_MAJOR也就该干吗干吗去,用不着它了。比如,usb键盘关联了input子系统,驱动对应drivers/hid/usbhid目录下的usbkbd.c文件,在它的probe函数里可以看到使用了input_register_device来注册一个输入设备。

    enum usb_interface_condition condition; /* state of binding */ // 当前接口 所处的连接绑定阶段
    unsigned sysfs_files_created:1; /* the sysfs attributes exist */
    unsigned ep_devs_created:1; /* endpoint "devices" exist */
    unsigned unregistering:1; /* unregistration is in progress */
    unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
    unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */
    unsigned needs_binding:1; /* needs delayed unbind/rebind */
    unsigned resetting_device:1; /* true: bandwidth alloc after reset */

    struct device dev; /* interface specific device info */ // linux设备模型里的device嵌在这儿的对象
    struct device *usb_dev;  // 当接口使用USB_MAJOR作为主设备号时,usb_dev才会用到, usb_register_dev和usb_deregister_dev使用这个结构体,usb_dev指向的
                                   就是usb_register_dev函数里创建的usb class device。
    atomic_t pm_usage_cnt; /* usage counter for autosuspend */
    struct work_struct reset_ws; /* for resets in atomic context */
}

struct usb_interface中的struct usb_host_interface *cur_altsetting成员,表示当前正在使用的设置

  • struct device dev:我愿称其为PDO
  • struct device *usb_dev:我愿称其为FDO

struct usb_host_interface

struct usb_host_interface 
{
         struct usb_interface_descriptor desc;//usb描述符,主要有四种usb描述符,设备描述符配置描述符接口描述符端点描述符,协议里规定一个usb设备是必须支持这四大描述符的。

          //usb描述符放在usb设备的eeprom里边
         /* 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;
};

具体到接口描述符,它当然就是描述接口本身的信息的。一个接口可以有多个设置,使用不同的设置,描述接口的信息会有些不同,所以接口描述符并没有放在struct usb_interface结构里,而是放在表示接口设置的struct usb_host_interface结构里。

struct usb_host_endpoint 端点

struct usb_host_endpoint 
{
         struct usb_endpoint_descriptor desc; //端点描述符
         struct list_head                urb_list;//端点要处理的urb队列.urb是usb通信的主角,设备中的每个端点都可以处理一个urb队列.要想和你的usb通信,就得创建一个urb,并且为它赋好值,
                                   //交给咱们的usb core,它会找到合适的host controller,从而进行具体的数据传输
         void                            *hcpriv;//这是提供给HCD(host controller driver)用的
         struct ep_device                *ep_dev;        /* For sysfs info */

         unsigned char *extra;   /* Extra descriptors */
         int extralen;
};
原文转自:https://www.cnblogs.com/wen123456/p/14212652.html

0 篇笔记 写笔记

关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

    打开支付宝扫一扫,即可进行扫码打赏哦

    您的支持,是我们前进的动力!