现在的位置: 首页 > 综合 > 正文

USB设备基础

2014年03月02日 ⁄ 综合 ⁄ 共 8979字 ⁄ 字号 评论关闭

1. 端点 (endpoint)

USB端点只能单向传送数据,从主机到设备(输出端点)或从设备到主机(输入端点)。

依据传输数据方式的不同,可以分为4种端点:

a. 控制端点(control endpoint):通常用于配置设备,获取设备信息,发送命令到设备,或获取设备的状态。

b. 中断端点(interrupt endpoint):当USB host要求设备传输数据时,中断端点就以一个固定的速率来传送少量的数据。USB键盘和鼠标就是这种方式。

c. 批量端点(bulk endpoint):传输大批量数据。打印机,存储设备和网络设备多用这采用传输方式。

d. 等时端点(也交同步端点,isochronous endpoint):可以传输大批量数据,等待功能使得可以确保数据不丢失。可以保持一个恒定的数据流,如实时的数据收集(音频和视频设备)都使用这种方式。

控制和批量端点用于异步传输数据。

内核中使用struct usb_host_endpoint结构体描述USB端点:

    /**
     * struct usb_host_endpoint - host-side endpoint descriptor and queue
     * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
     * @ss_ep_comp: SuperSpeed companion descriptor for this endpoint
     * @urb_list: urbs queued to this endpoint; maintained by usbcore
     * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH)
     *    with one or more transfer descriptors (TDs) per urb
     * @ep_dev: ep_device for sysfs info
     * @extra: descriptors following this endpoint in the configuration
     * @extralen: how many bytes of "extra" are valid
     * @enabled: URBs may be submitted to this endpoint
     *
     * USB requests are always queued to a given endpoint, identified by a
     * descriptor within an active interface in a given USB configuration.
     */
    struct usb_host_endpoint {
        struct usb_endpoint_descriptor        desc;      //这里包含真正的端点信息
        struct usb_ss_ep_comp_descriptor    ss_ep_comp;
        struct list_head        urb_list;
        void                *hcpriv;
        struct ep_device        *ep_dev;    /* For sysfs info */
        unsigned char *extra; /* Extra descriptors */
        int extralen;
        int enabled;
    };

struct usb_endpoint_descriptor 结构体包含了所有USB特定的数据,这些数据的格式是由设备自己定义的:

    /* USB_DT_ENDPOINT: Endpoint descriptor */
    struct usb_endpoint_descriptor {
        __u8 bLength;
        __u8 bDescriptorType;
        __u8 bEndpointAddress;   //特定端点的USB地址,这8位值中还包括了端点的方向。
                             //该字段可以结合掩码 USB_DIR_OUT 和 USB_DIR_IN 来使用,
                             //以确定该端点的数据时传向设备还是主机。
        __u8 bmAttributes;       //这里描述端点的类型,
                             //该值可以结合位掩码 USB_ENDPOINT_XFERTYPE_MASK
                             //来确定此端点的类型是 USB_ENDPOINT_XFER_ISOC(等时),
                             //USB_ENDPOINT_XFER_BULK(批量)
                             //还是USB_ENDPOINT_XFER_INT(中断)      
        __le16 wMaxPacketSize;   //该端点一次可以处理的最大字节数。
                                 //驱动可以发送数量大于此值的数据到端点,
                                 //但实际传输中,数据会被分割成 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));

2. 接口 (interface):

一个USB接口可以包含多个USB端点,一个USB接口处理一种USB逻辑连接(如 鼠标,键盘 或者 音频流)。

一些USB设备具有多个接口,如USB扬声器可以包括两个接口:一个USB键盘用于按键 和 一个音频流。

每个USB驱动控制一个接口,因此一扬声器为例,Linux需要两个不同的驱动程序来处理一个硬件设备。

内核使用struct usb_interface 来描述 USB 接口:

    /**
     * struct usb_interface - what usb device drivers talk to
     * @altsetting: array of interface structures, one for each alternate
     *    setting that may be selected. Each one includes a set of
     *    endpoint configurations. They will be in no particular order.
     * @cur_altsetting: the current altsetting.
     * @num_altsetting: number of altsettings defined.
     * @intf_assoc: interface association descriptor
     * @minor: the minor number assigned to this interface, if this
     *    interface is bound to a driver that uses the USB major number.
     *    If this interface does not use the USB major, this field should
     *    be unused. The driver should set this value in the probe()
     *    function of the driver, after it has been assigned a minor
     *    number from the USB core by calling usb_register_dev().
     * @condition: binding state of the interface: not bound, binding
     *    (in probe()), bound to a driver, or unbinding (in disconnect())
     * @sysfs_files_created: sysfs attributes exist
     * @ep_devs_created: endpoint child pseudo-devices exist
     * @unregistering: flag set when the interface is being unregistered
     * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
     *    capability during autosuspend.
     * @needs_altsetting0: flag set when a set-interface request for altsetting 0
     *    has been deferred.
     * @needs_binding: flag set when the driver should be re-probed or unbound
     *    following a reset or suspend operation it doesn't support.
     * @dev: driver model's view of this device
     * @usb_dev: if an interface is bound to the USB major, this will point
     *    to the sysfs representation for that device.
     * @pm_usage_cnt: PM usage counter for this interface
     * @reset_ws: Used for scheduling resets from atomic context.
     * @reset_running: set to 1 if the interface is currently running a
     * queued reset so that usb_cancel_queued_reset() doesn't try to
     * remove from the workqueue when running inside the worker
     * thread. See __usb_queue_reset_device().
     *
     * USB device drivers attach to interfaces on a physical device. Each
     * interface encapsulates a single high level function, such as feeding
     * an audio stream to a speaker or reporting a change in a volume control.
     * Many USB devices only have one interface. The protocol used to talk to
     * an interface's endpoints can be defined in a usb "class" specification,
     * or by a product's vendor. The (default) control endpoint is part of
     * every interface, but is never listed among the interface's descriptors.
     *
     * The driver that is bound to the interface can use standard driver model
     * calls such as dev_get_drvdata() on the dev member of this structure.
     *
     * Each interface may have alternate settings. The initial configuration
     * of a device sets altsetting 0, but the device driver can change
     * that setting using usb_set_interface(). Alternate settings are often
     * used to control the use of periodic endpoints, such as by having
     * different endpoints use different amounts of reserved USB bandwidth.
     * All standards-conformant USB devices that use isochronous endpoints
     * will use them in non-default settings.
     *
     * The USB specification says that alternate setting numbers must run from
     * 0 to one less than the total number of alternate settings. But some
     * devices manage to mess this up, and the structures aren't necessarily
     * stored in numerical order anyhow. Use usb_altnum_to_altsetting() to
     * look up an alternate setting in the altsetting array based on its number.
     */
    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;    //指向altsetting数组内部的指针,
                                                      //表示该接口当前的接口设置
        /* number of alternate settings */
        unsigned num_altsetting;        //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核心分配给该接口的次设备号
                      //这个仅在usb_register_dev()调用成功后有效
            
        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 reset_running:1;
        unsigned resetting_device:1;    /* true: bandwidth alloc after reset */
        struct device dev;        /* interface specific device info */
        struct device *usb_dev;
        atomic_t pm_usage_cnt;        /* usage counter for autosuspend */
        struct work_struct reset_ws;    /* for resets in atomic context */
    };
    #define    to_usb_interface(d) container_of(d, struct usb_interface, dev)

3. 配置 (config):

一个USB 配置 可以包含多个 USB 接口。

一个USB 设备可以有多个配置,可以在配置之间切换以改变设备的状态,如手机插上USB会弹出,debug状态还是数据存储状态。这就是不同的配置。

同一时刻只能激活一种配置。

linux内核使用 struct usb_host_config 来描述 USB 配置:

    /**
     * struct usb_host_config - representation of a device's configuration
     * @desc: the device's configuration descriptor.
     * @string: pointer to the cached version of the iConfiguration string, if
     *    present for this configuration.
     * @intf_assoc: list of any interface association descriptors in this config
     * @interface: array of pointers to usb_interface structures, one for each
     *    interface in the configuration. The number of interfaces is stored
     *    in desc.bNumInterfaces. These pointers are valid only while the
     *    the configuration is active.
     * @intf_cache: array of pointers to usb_interface_cache structures, one
     *    for each interface in the configuration. These structures exist
     *    for the entire life of the device.
     * @extra: pointer to buffer containing all extra descriptors associated
     *    with this configuration (those preceding the first interface
     *    descriptor).
     * @extralen: length of the extra descriptors buffer.
     *
     * USB devices may have multiple configurations, but only one can be active
     * at any time. Each encapsulates a different operational environment;
     * for example, a dual-speed device would have separate configurations for
     * full-speed and high-speed operation. The number of configurations
     * available is stored in the device descriptor as bNumConfigurations.
     *
     * A configuration can contain multiple interfaces. Each corresponds to
     * a different function of the USB device, and all are available whenever
     * the configuration is active. The USB standard says that interfaces
     * are supposed to be numbered from 0 to desc.bNumInterfaces-1, but a lot
     * of devices get this wrong. In addition, the interface array is not
     * guaranteed to be sorted in numerical order. Use usb_ifnum_to_if() to
     * look up an interface entry based on its number.
     *
     * Device drivers should not attempt to activate configurations. The choice
     * of which configuration to install is a policy decision based on such
     * considerations as available power, functionality provided, and the user's
     * desires (expressed through userspace tools). However, drivers can call
     * usb_reset_configuration() to reinitialize the current configuration and
     * all its interfaces.
     */
    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];
        unsigned char *extra; /* Extra descriptors */
        int extralen;
    };

总结:USB设备非常复杂,它由许多不同的逻辑单元组成,这些逻辑单元之间可以简单描述如下:

a. USB 设备通常具有一个或多个USB 配置

b. USB 配置通常具有一个或多个USB 接口

c. USB 接口通常具有一个或多个USB 设置

d. USB 接口没有或者具有一个以上USB 端点

抱歉!评论已关闭.