zoukankan      html  css  js  c++  java
  • Linux设备驱动程序学习(17)-USB 驱动程序(二)

    内核使用2.6.29.4
    USB设备其实很复杂,但是Linux内核提供了一个称为USB core的子系统来处理了大部分的复杂工作,所以这里所描述的是驱动程序和USB core之间的接口。
    在USB设备组织结构中,从上到下分为设备(device)、配置(config)、接口(interface)和端点(endpoint)四个层次。
    对于这四个层次的简单描述如下:
        设备通常具有一个或多个的配置
        配置经常具有一个或多个的接口
        接口通常具有一个或多个的设置
        接口没有或具有一个以上的端点
    设备
    很明显,地代表了一个插入的USB设备,在内核使用数据结构 struct usb_device来描述整个USB设备。(include/linux/usb.h)

    struct usb_device {
    int devnum; //设备号,是在USB总线的地址
    char devpath [16]; //用于消息的设备ID字符串
    enum usb_device_state state; //设备状态:已配置、未连接等等
    enum usb_device_speed speed; //设备速度:高速、全速、低速或错误
    struct usb_tt *tt; //处理传输者信息;用于低速、全速设备和高速HUB
    int ttport; //位于tt HUB的设备口
    unsigned int toggle[2]; //每个端点的占一位,表明端点的方向([0] = IN, [1] = OUT)
    struct usb_device *parent; //上一级HUB指针
    struct usb_bus *bus; //总线指针
    struct usb_host_endpoint ep0; //端点0数据
    struct device dev; //一般的设备接口数据结构
    struct usb_device_descriptor descriptor; //USB设备描述符
    struct usb_host_config *config; //设备的所有配置
    struct usb_host_config *actconfig; //被激活的设备配置
    struct usb_host_endpoint *ep_in[16]; //输入端点数组
    struct usb_host_endpoint *ep_out[16]; //输出端点数组
    char **rawdescriptors; //每个配置的raw描述符
    unsigned short bus_mA; //可使用的总线电流
    
    
       u8 portnum;
    
    //父端口号
       u8 level; //USB HUB的层数
    unsigned can_submit:1; //URB可被提交标志
    unsigned discon_suspended:1; //暂停时断开标志
    unsigned persist_enabled:1; //USB_PERSIST使能标志
    unsigned have_langid:1; //string_langid存在标志
    unsigned authorized:1;
    unsigned authenticated:1;
    unsigned wusb:1; //无线USB标志
    int string_langid; //字符串语言ID
    
    /* static strings from the device */ //设备的静态字符串
    char *product; //产品名
    char *manufacturer; //厂商名
    char *serial; //产品串号
    struct list_head filelist; //此设备打开的usbfs文件
    #ifdef CONFIG_USB_DEVICE_CLASS
    struct device *usb_classdev; //用户空间访问的为usbfs设备创建的USB类设备
    #endif
    #ifdef CONFIG_USB_DEVICEFS
    struct dentry *usbfs_dentry; //设备的usbfs入口
    #endif
    int maxchild; //(若为HUB)接口数
    struct usb_device *children[USB_MAXCHILDREN];//连接在这个HUB上的子设备
    int pm_usage_cnt; //自动挂起的使用计数
       u32 quirks;
       atomic_t urbnum; //这个设备所提交的URB计数
    unsigned long active_duration; //激活后使用计时
    
    #ifdef CONFIG_PM //电源管理相关
    struct delayed_work autosuspend; //自动挂起的延时
    struct work_struct autoresume; //(中断的)自动唤醒需求
    struct mutex pm_mutex; //PM的互斥锁
    
    unsigned long last_busy; //最后使用的时间
    int autosuspend_delay;
    unsigned long connect_time; //第一次连接的时间
    unsigned auto_pm:1; //自动挂起/唤醒
    unsigned do_remote_wakeup:1; //远程唤醒
    unsigned reset_resume:1; //使用复位替代唤醒
    unsigned autosuspend_disabled:1; //挂起关闭
    unsigned autoresume_disabled:1; //唤醒关闭
    unsigned skip_sys_resume:1; //跳过下个系统唤醒
    #endif
    struct wusb_dev *wusb_dev; //(如果为无线USB)连接到WUSB特定的数据结构
    };

    配置
        一个USB设备可以有多个配置,并可在它们之间转换以改变设备的状态。比如一个设备可以通过下载固件(firmware)的方式改变设备的使用状态(我感觉类似FPGA或CPLD),那么USB设备就要切换配置,来完成这个工作。一个时刻只能有一个配置可以被激活。Linux使用结构 struct usb_host_config 来描述USB配置。我们编写的USB设备驱动通常不需要读写这些结构的任何值。可在内核源码的文件include/linux/usb.h中找到对它们的描述。

    struct usb_host_config {
    struct usb_config_descriptor desc; //配置描述符
    char *string; /* 配置的字符串指针(如果存在) */
    struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS]; //配置的接口联合描述符链表
    struct usb_interface *interface[USB_MAXINTERFACES]; //接口描述符链表
    struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];
    unsigned char *extra; /* 额外的描述符 */
    int extralen;
    };

    接口
    USB端点被绑为接口,USB接口只处理一种USB逻辑连接。一个USB接口代表一个基本功能,每个USB驱动控制一个接口。所以一个物理上的硬件设备可能需要一个以上的驱动程序。这可以在“晕到死 差屁”系统中看出,有时插入一个USB设备后,系统会识别出多个设备,并安装相应多个的驱动。
    USB 接口可以有其他的设置,它是对接口参数的不同选择. 接口的初始化的状态是第一个设置,编号为0。 其他的设置可以以不同方式控制独立的端点。
    USB接口在内核中使用 struct usb_interface 来描述。USB 核心将其传递给USB驱动,并由USB驱动负责后续的控制。

    struct usb_interface {
    struct usb_host_interface *altsetting; /* 包含所有可用于该接口的可选设置的接口结构数组。每个 struct usb_host_interface 包含一套端点配置(即struct usb_host_endpoint结构所定义的端点配置。这些接口结构没有特别的顺序。*/
    struct usb_host_interface *cur_altsetting; /* 指向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; /* 如果绑定到这个接口的 USB 驱动使用 USB 主设备号, 这个变量包含由 USB 核心分配给接口的次设备号. 这只在一个成功的调用 usb_register_dev后才有效。*/
    /*以下的数据在我们写的驱动中基本不用考虑,系统会自动设置*/
    enum usb_interface_condition condition; /* state of binding */
    unsigned is_active:1; /* the interface is not suspended */
    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;
    struct device dev; /* 接口特定的设备信息 */
    struct device *usb_dev;
    int 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; //接口描述符
    struct usb_host_endpoint *endpoint; /* 这个接口的所有端点结构体的联合数组*/
    char *string; /* 接口描述字符串 */
    unsigned char *extra; /* 额外的描述符 */
    int extralen;
    };

    端点
    USB 通讯的最基本形式是通过一个称为端点的东西。一个USB端点只能向一个方向传输数据(从主机到设备(称为输出端点)或者从设备到主机(称为输入端点))。端点可被看作一个单向的管道。
    一个 USB 端点有 4 种不同类型, 分别具有不同的数据传送方式:
    控制CONTROL
    控制端点被用来控制对 USB 设备的不同部分访问. 通常用作配置设备、获取设备信息、发送命令到设备或获取设备状态报告。这些端点通常较小。每个 USB 设备都有一个控制端点称为"端点 0", 被 USB 核心用来在插入时配置设备。USB协议保证总有足够的带宽留给控制端点传送数据到设备.
    中断INTERRUPT
    每当 USB 主机向设备请求数据时,中断端点以固定的速率传送小量的数据。此为USB 键盘和鼠标的主要的数据传送方法。它还用以传送数据到 USB 设备来控制设备。通常不用来传送大量数据。USB协议保证总有足够的带宽留给中断端点传送数据到设备.
    批量BULK
    批量端点用以传送大量数据。这些端点常比中断端点大得多. 它们普遍用于不能有任何数据丢失的数据。USB 协议不保证传输在特定时间范围内完成。如果总线上没有足够的空间来发送整个BULK包,它被分为多个包进行传输。这些端点普遍用于打印机、USB Mass Storage和USB网络设备上。
    等时ISOCHRONOUS
    等时端点也批量传送大量数据, 但是这个数据不被保证能送达。这些端点用在可以处理数据丢失的设备中,并且更多依赖于保持持续的数据流。如音频和视频设备等等。
    控制和批量端点用于异步数据传送,而中断和同步端点是周期性的。这意味着这些端点被设置来在固定的时间连续传送数据,USB 核心为它们保留了相应的带宽。
    端点在内核中使用结构 struct usb_host_endpoint 来描述,它所包含的真实端点信息在另一个结构中:struct usb_endpoint_descriptor(端点描述符,包含所有的USB特定数据)。

    struct usb_host_endpoint {
    struct usb_endpoint_descriptor desc; //端点描述符
    struct list_head urb_list; //此端点的URB对列,由USB核心维护
    void *hcpriv;
    struct ep_device *ep_dev; /* For sysfs info */
    unsigned char *extra; /* Extra descriptors */
    int extralen;
    int enabled;
    };
    /*-------------------------------------------------------------------------*/
    /* 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; //这是端点的类型,位掩码如下
        __le16 wMaxPacketSize; /*端点可以一次处理的最大字节数。驱动可以发送比这个值大的数据量到端点, 但是当真正传送到设备时,数据会被分为 wMaxPakcetSize 大小的块。对于高速设备, 通过使用高位部分几个额外位,可用来支持端点的高带宽模式。*/
        __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));
    #define USB_DT_ENDPOINT_SIZE 7
    #define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
    /*
     * Endpoints
     */
    #define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress 端点的 USB 地址掩码 */
    #define USB_ENDPOINT_DIR_MASK 0x80 /* in bEndpointAddress 数据方向掩码 */
    
    
    #define USB_DIR_OUT 0 /* to device */
    #define USB_DIR_IN 0x80 /* to host */
    #define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* bmAttributes 的位掩码*/
    #define USB_ENDPOINT_XFER_CONTROL 0
    #define USB_ENDPOINT_XFER_ISOC 1
    #define USB_ENDPOINT_XFER_BULK 2
    #define USB_ENDPOINT_XFER_INT 3
    #define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
    /*-------------------------------------------------------------------------*/

    USB 和 sysfs
    由于单个 USB 物理设备的复杂性,设备在 sysfs 中的表示也非常复杂。物理 USB 设备(通过 struct usb_device 表示)和单个 USB 接口(由 struct usb_interface 表示)都作为单个设备出现在 sysfs 中,这是因为这两个结构都包含一个 struct device结构。以下内容是我的USB鼠标在 sysfs 中的目录树:   

    /sys/devices/pci0000:00/0000:00:1a.0/usb3/3-1 (表示 usb_device 结构)
    .
    |-- 3-1:1.0 (鼠标所对应的usb_interface)
    | |-- 0003:046D:C018.0003
    | | |-- driver -> http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/../bus/hid/drivers/generic-usb
    | | |-- power
    | | | `-- wakeup
    | | |-- subsystem -> http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/../bus/hid
    | | `-- uevent
    | |-- bAlternateSetting
    | |-- bInterfaceClass
    | |-- bInterfaceNumber
    | |-- bInterfaceProtocol
    | |-- bInterfaceSubClass
    | |-- bNumEndpoints
    | |-- driver -> http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/bus/usb/drivers/usbhid
    | |-- ep_81 -> usb_endpoint/usbdev3.4_ep81
    | |-- input
    | | `-- input6
    | | |-- capabilities
    | | | |-- abs
    | | | |-- ev
    | | | |-- ff
    | | | |-- key
    | | | |-- led
    | | | |-- msc
    | | | |-- rel
    | | | |-- snd
    | | | `-- sw
    | | |-- device -> http://www.cnblogs.com/../3-1:1.0
    | | |-- event3
    | | | |-- dev
    | | | |-- device -> http://www.cnblogs.com/input6
    | | | |-- power
    | | | | `-- wakeup
    | | | |-- subsystem -> http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/../class/input
    | | | `-- uevent
    | | |-- id
    | | | |-- bustype
    | | | |-- product
    | | | |-- vendor
    | | | `-- version
    | | |-- modalias
    | | |-- mouse1
    | | | |-- dev
    | | | |-- device -> http://www.cnblogs.com/input6
    | | | |-- power
    | | | | `-- wakeup
    | | | |-- subsystem -> http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/../class/input
    | | | `-- uevent
    | | |-- name
    | | |-- phys
    | | |-- power
    | | | `-- wakeup
    | | |-- subsystem -> http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/class/input
    | | |-- uevent
    | | `-- uniq
    | |-- modalias
    | |-- power
    | | `-- wakeup
    | |-- subsystem -> http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/bus/usb
    | |-- supports_autosuspend
    | |-- uevent
    | `-- usb_endpoint
    | `-- usbdev3.4_ep81
    | |-- bEndpointAddress
    | |-- bInterval
    | |-- bLength
    | |-- bmAttributes
    | |-- dev
    | |-- device -> http://www.cnblogs.com/../3-1:1.0
    | |-- direction
    | |-- interval
    | |-- power
    | | `-- wakeup
    | |-- subsystem -> http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/class/usb_endpoint
    | |-- type
    | |-- uevent
    | `-- wMaxPacketSize
    |-- authorized
    |-- bConfigurationValue
    |-- bDeviceClass
    |-- bDeviceProtocol
    |-- bDeviceSubClass
    |-- bMaxPacketSize0
    |-- bMaxPower
    |-- bNumConfigurations
    |-- bNumInterfaces
    |-- bcdDevice
    |-- bmAttributes
    |-- busnum
    |-- configuration
    |-- descriptors
    |-- dev
    |-- devnum
    |-- driver -> http://www.cnblogs.com/http://www.cnblogs.com/../bus/usb/drivers/usb
    |-- ep_00 -> usb_endpoint/usbdev3.4_ep00
    |-- idProduct
    |-- idVendor
    |-- manufacturer
    |-- maxchild
    |-- power
    | |-- active_duration
    | |-- autosuspend
    | |-- connected_duration
    | |-- level
    | |-- persist
    | `-- wakeup
    |-- product
    |-- quirks
    |-- speed
    |-- subsystem -> http://www.cnblogs.com/http://www.cnblogs.com/../bus/usb
    |-- uevent
    |-- urbnum
    |-- usb_endpoint
    | `-- usbdev3.4_ep00
    | |-- bEndpointAddress
    | |-- bInterval
    | |-- bLength
    | |-- bmAttributes
    | |-- dev
    | |-- device -> http://www.cnblogs.com/../3-1
    | |-- direction
    | |-- interval
    | |-- power
    | | `-- wakeup
    | |-- subsystem -> http://www.cnblogs.com/http://www.cnblogs.com/http://www.cnblogs.com/../class/usb_endpoint
    | |-- type
    | |-- uevent
    | `-- wMaxPacketSize
    `-- version
    38 directories, 91 files

    USB sysfs 设备命名方法是: root_hub-hub_port:config.interface
        随着USB集线器层次的增加, 集线器端口号被添加到字符串中紧随着链中之前的集线器端口号。对一个 2 层的树, 设备为: root_hub-hub_port-hub_port:config.interface ,以此类推。

  • 相关阅读:
    网站安全编程 黑客入侵 脚本黑客 高级语法入侵 C/C++ C# PHP JSP 编程
    【算法导论】贪心算法,递归算法,动态规划算法总结
    cocoa2dx tiled map添加tile翻转功能
    8月30日上海ORACLE大会演讲PPT下载
    【算法导论】双调欧几里得旅行商问题
    Codeforces Round #501 (Div. 3) B. Obtaining the String (思维,字符串)
    Codeforces Round #498 (Div. 3) D. Two Strings Swaps (思维)
    Educational Codeforces Round 89 (Rated for Div. 2) B. Shuffle (数学,区间)
    洛谷 P1379 八数码难题 (BFS)
    Educational Codeforces Round 89 (Rated for Div. 2) A. Shovels and Swords (贪心)
  • 原文地址:https://www.cnblogs.com/shenhaocn/p/1996947.html
Copyright © 2011-2022 走看看