十六、USB驱动

一、USB固件和USB传输方式

USB固件:

USB固件一般不需要我们编写,在此不做程序分析。

USB固件中包含USB设备的出厂信息,如厂商ID、产品ID、主版本号和次版本号等。这就是为什么当我们把U盘插入USB口的时候主机可以知道这是一个U盘设备。

 

除包含出厂信息外,固件中还包含处理USB协议和设备读写操作的程序,如将数据从设备发送到总线上或从总线中将数据读取到设备中。驱动程序只是将USB规范定义的请求发送给固件程序,固件程序负责将数据写入设备中。USB规范定义了USB设备间的通信方式。

 

USB结构:

USB是主从结构的。所有的USB传输,都是从USB主机这方发起,USB设备没有“主动”通知USB主机的能力。

如USB鼠标滑动一下产生了数据,但它没有能力通知PC机来读数据,只能被动地等待PC来读。

 

USB传输类型:

1. 控制传输:可靠,时间有保证。如:USB设备的识别过程

2. 批量传输: 可靠, 时间没有保证。如:U盘

3. 中断传输:可靠,实时。如:USB鼠标

4. 实时传输:不可靠,实时。如:USB摄像头

 

 

二、Linux USB设备驱动模型

USB设备驱动模型采用总线设备驱动模型,所以它具有三部分:

1. USB Bus

2. USB Device

3. USB Driver

 

usb_bus和usb_bus_type:

每一条USB总线对应一个struct usb_bus。

 1 struct usb_bus {
 2     struct device *controller;    /* host/master side hardware */
 3     int busnum;            /* Bus number (in order of reg) */
 4     const char *bus_name;        /* stable id (PCI slot_name etc) */
 5     u8 uses_dma;            /* Does the host controller use DMA? */
 6     u8 uses_pio_for_control;    /*
 7                      * Does the host controller use PIO
 8                      * for control transfers?
 9                      */
10     u8 otg_port;            /* 0, or number of OTG/HNP port */
11     unsigned is_b_host:1;        /* true during some HNP roleswitches */
12     unsigned b_hnp_enable:1;    /* OTG: did A-Host enable HNP? */
13     unsigned sg_tablesize;        /* 0 or largest number of sg list entries */
14 
15     int devnum_next;        /* Next open device number in
16                      * round-robin allocation */
17 
18     struct usb_devmap devmap;    /* device address allocation map */
19     struct usb_device *root_hub;    /* Root hub */
20     struct usb_bus *hs_companion;    /* Companion EHCI bus, if any */
21     struct list_head bus_list;    /* list of busses */
22 
23     int bandwidth_allocated;    /* on this bus: how much of the time
24                      * reserved for periodic (intr/iso)
25                      * requests is used, on average?
26                      * Units: microseconds/frame.
27                      * Limits: Full/low speed reserve 90%,
28                      * while high speed reserves 80%.
29                      */
30     int bandwidth_int_reqs;        /* number of Interrupt requests */
31     int bandwidth_isoc_reqs;    /* number of Isoc. requests */
32 
33 #ifdef CONFIG_USB_DEVICEFS
34     struct dentry *usbfs_dentry;    /* usbfs dentry entry for the bus */
35 #endif
36 
37 #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
38     struct mon_bus *mon_bus;    /* non-null when associated */
39     int monitored;            /* non-zero when monitored */
40 #endif
41 };
View Code

 

usb_bus_type定义了一种usb总线类型。在软件层次中,usb_bus属于usb_bus_type。

usb_bus_type通过bus_register(&usb_bus_type)函数向内核注册usb总线。

struct bus_type usb_bus_type = {
    .name   = "usb",
    .match  = usb_device_match,
    .uevent = usb_uevent,
    .pm     = &usb_bus_pm_ops,
};

其中,match()函数通过id_table来匹配device和driver。

 1 static int usb_device_match(struct device *dev, struct device_driver *drv)
 2 {
 3     /* devices and interfaces are handled separately */
 4     if (is_usb_device(dev)) {
 5 
 6         /* interface drivers never match devices */
 7         if (!is_usb_device_driver(drv))
 8             return 0;
 9 
10         /* TODO: Add real matching code */
11         return 1;
12 
13     } else if (is_usb_interface(dev)) {
14         struct usb_interface *intf;
15         struct usb_driver *usb_drv;
16         const struct usb_device_id *id;
17 
18         /* device drivers never match interfaces */
19         if (is_usb_device_driver(drv))
20             return 0;
21 
22         intf = to_usb_interface(dev);
23         usb_drv = to_usb_driver(drv);
24         
25         /* 匹配interface和driver->id_table */
26         id = usb_match_id(intf, usb_drv->id_table);
27         if (id)
28             return 1;
29 
30         id = usb_match_dynamic_id(intf, usb_drv);
31         if (id)
32             return 1;
33     }
34 
35     return 0;
36 }
View Code

 

USB总线的任务有:

1. 识别USB设备

  a. 分配地址并将地址告诉USB设备

  b. 发出命令获取描述符

2. 查找并安装对应的设备驱动程序

3. 提供USB读写接口

 

我们现在来分析总线框架:

usb_init()
  -> bus_register(&usb_bus_type);   /* 注册usb总线 */
  -> bus_register_notifier(&usb_bus_type, &usb_bus_nb);
  -> usb_major_init()
    -> register_chrdev(180, "usb", &usb_fops);
  -> usb_register(&usbfs_driver);   /* usbfs驱动 */
  -> usb_hub_init();                /* 初始化USB集线器 */
    -> usb_register(&hub_driver);
    -> kthread_run(hub_thread, NULL, "khubd");        /* 执行线程 */
      -> hub_events();
        /* 如果有插拔USB设备操作 */
        -> hub_port_connect_change(hub, i, portstatus, portchange);
          -> usb_alloc_dev(hdev, hdev->bus, port1);   /* 分配usb内存 */
          -> choose_address(udev);                    /* 设置地址 */
          -> hub_port_init(hub, udev, port1, i);      /* 获取设备描述符 */
    -> usb_deregister(&hub_driver);
  -> usb_register_device_driver(&usb_generic_driver, THIS_MODULE);

 

usb_device:

每一个USB设备对应一个struct usb_device。

 1 struct usb_device {
 2     int        devnum;                    /* 设备号 */
 3     char        devpath[16];        /* 设备路径 */
 4     u32        route;
 5     enum usb_device_state    state;
 6     enum usb_device_speed    speed;
 7 
 8     struct usb_tt    *tt;
 9     int        ttport;
10 
11     unsigned int toggle[2];
12 
13     struct usb_device *parent;
14     struct usb_bus *bus;            /* 设备所属总线 */
15     struct usb_host_endpoint ep0;    /* 设备端点 */
16 
17     struct device dev;
18 
19     struct usb_device_descriptor descriptor;
20     struct usb_host_config *config;    /* 设备配置 */
21 
22     struct usb_host_config *actconfig;
23     struct usb_host_endpoint *ep_in[16];
24     struct usb_host_endpoint *ep_out[16];
25 
26     char **rawdescriptors;
27 
28     unsigned short bus_mA;
29     u8 portnum;
30     u8 level;
31 
32     unsigned can_submit:1;
33     unsigned persist_enabled:1;
34     unsigned have_langid:1;
35     unsigned authorized:1;
36     unsigned authenticated:1;
37     unsigned wusb:1;
38     int string_langid;
39 
40     /* static strings from the device */
41     char *product;
42     char *manufacturer;
43     char *serial;
44 
45     struct list_head filelist;
46 ...
47     int maxchild;
48     struct usb_device *children[USB_MAXCHILDREN];
49 
50     u32 quirks;
51     atomic_t urbnum;
52 ...
53     struct wusb_dev *wusb_dev;
54     int slot_id;
55 };
View Code

其注册函数为int usb_new_device(struct usb_device *udev)。

 

在USB设备的逻辑组织中,包含设备、配置、接口和端点四个层次。在此我使用宋宝华老师书中图片作为解释:

 

在Linux内核中,这四个层次通过一组标准的描述符来描述,如下所示。

1. 设备描述符:usb_device用于定义USB设备,usb_device_descriptor用于定义产品ID等。

struct usb_device_descriptor {
    __u8  bLength;            /* 描述符长度 */
    __u8  bDescriptorType;    /* 描述符类型编号 */

    __le16 bcdUSB;            /* USB版本号 */
    __u8  bDeviceClass;       /* USB分配的设备类 */
    __u8  bDeviceSubClass;    /* USB分配的子类 */
    __u8  bDeviceProtocol;    /* USB分配的协议 */
    __u8  bMaxPacketSize0;    /* 端点0的最大包大小 */
    __le16 idVendor;          /* 厂商编号 */
    __le16 idProduct;         /* 产品编号 */
    __le16 bcdDevice;         /* 出厂编号 */
    __u8  iManufacturer;
    __u8  iProduct;
    __u8  iSerialNumber;
    __u8  bNumConfigurations;
} __attribute__ ((packed));

当一个USB设备插入时,默认的设备编号为0,在未分配新的编号前,PC使用编号0与它通信。

由于PC可能拥有多个USB设备,因此在PC需要访问某个USB设备时,发出的命令含有此USB设备对应的编号地址。

 

2. 配置描述符:usb_host_config用于定义USB配置,usb_config_descriptor用于定义此配置下的接口数,供电模式和功率要求等。

struct usb_config_descriptor {
    __u8  bLength;            /* 描述符长度 */
    __u8  bDescriptorType;    /* 描述符类型编号 */

    __le16 wTotalLength;      /* 配置返回的所有数据大小 */
    __u8  bNumInterfaces;     /* 配置支持的接口数 */
    __u8  bConfigurationValue;
    __u8  iConfiguration;     /* 配置索引值 */
    __u8  bmAttributes;       /* 供电模式 */
    __u8  bMaxPower;          /* 最大电流 */
} __attribute__ ((packed));

 

3. 接口描述符:usb_interface用于定义USB接口,usb_interface_descriptor用于定义此接口下的端点数,协议等。

struct usb_interface_descriptor {
    __u8  bLength;            /* 描述符长度 */
    __u8  bDescriptorType;    /* 描述符类型 */

    __u8  bInterfaceNumber;   /* 接口编号 */
    __u8  bAlternateSetting;
    __u8  bNumEndpoints;      /* 端点数 */
    __u8  bInterfaceClass;    /* 接口类型 */
    __u8  bInterfaceSubClass;
    __u8  bInterfaceProtocol;
    __u8  iInterface;         /* 接口索引值 */
} __attribute__ ((packed));

 

4. 端点描述符:usb_host_endpoint用于定义USB端点,usb_endpoint_descriptor用于定义此端点下的端点地址,方向和类型等。

struct usb_endpoint_descriptor {
    __u8  bLength;            /* 描述符长度 */
    __u8  bDescriptorType;    /* 描述符类型 */

    __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));

 

我们可以使用“lsusb -v -s 总线号:设备号”查看设备的详细信息

 

usb_driver:

每一个USB设备驱动对应一个struct usb_driver。

 1 struct usb_driver {
 2     const char *name;
 3 
 4     int (*probe) (struct usb_interface *intf,
 5               const struct usb_device_id *id);
 6 
 7     void (*disconnect) (struct usb_interface *intf);
 8 
 9     int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
10             void *buf);
11 
12     int (*suspend) (struct usb_interface *intf, pm_message_t message);
13     int (*resume) (struct usb_interface *intf);
14     int (*reset_resume)(struct usb_interface *intf);
15 
16     int (*pre_reset)(struct usb_interface *intf);
17     int (*post_reset)(struct usb_interface *intf);
18 
19     const struct usb_device_id *id_table;
20 
21     struct usb_dynids dynids;
22     struct usbdrv_wrap drvwrap;
23     unsigned int no_dynamic_id:1;
24     unsigned int supports_autosuspend:1;
25     unsigned int soft_unbind:1;
26 };
View Code

其注册函数为int usb_register(struct usb_driver *driver)。

1 #define usb_register(driver) \
2     usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)

 

 

三、USB数据传输

USB设备驱动和USB设备通信所有的结构体为USB请求块(USB Request Block,URB)。

struct urb {
    /* private: usb core and host controller only fields in the urb */
    struct kref kref;        /* reference count of the URB */
    void *hcpriv;            /* private data for host controller */
    atomic_t use_count;      /* 用于计数,URB若提交则加1,URB若返回驱动程序减1 */
    atomic_t reject;         /* submissions will fail */
    int unlinked;            /* unlink error code */

    /* public: documented fields in the urb that can be used by drivers */
    struct list_head urb_list;    /* list head for use by the urb's
                     * current owner */
    struct list_head anchor_list; /* the URB may be anchored */
    struct usb_anchor *anchor;
    struct usb_device *dev;       /* URB需要发送到的设备 */
    struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
    unsigned int pipe;            /* (in) pipe information */
    unsigned int stream_id;       /* (in) stream ID */
    int status;            /* (return) non-ISO status */
    unsigned int transfer_flags;  /* (in) URB_SHORT_NOT_OK | ...*/
    void *transfer_buffer;        /* 缓冲区,其数据可以从设备发送到主机,也可以从主机发送到设备 */
    dma_addr_t transfer_dma;      /* (in) dma addr for transfer_buffer */
    struct scatterlist *sg;       /* (in) scatter gather buffer list */
    int num_sgs;                  /* (in) number of entries in the sg list */
    u32 transfer_buffer_length;   /* 表示transfer_buffer或transfer_dma的长度 */
    u32 actual_length;            /* (return) actual transfer length */
    unsigned char *setup_packet;  /* (in) setup packet (control only) */
    dma_addr_t setup_dma;         /* (in) dma addr for setup_packet */
    int start_frame;              /* (modify) start frame (ISO) */
    int number_of_packets;        /* (in) number of ISO packets */
    int interval;                 /* (modify) transfer interval
                     * (INT/ISO) */
    int error_count;              /* (return) number of ISO errors */
    void *context;                /* (in) context for completion */
    usb_complete_t complete;      /* (in) completion routine */
    struct usb_iso_packet_descriptor iso_frame_desc[0];
                    /* (in) ISO ONLY */
};

 

URB的处理流程:

在USB设备的逻辑层次中,interface是逻辑上的设备,它使用endpoint传输urb。

也就是说,USB设备中每个endpoint都处理一个urb队列,在队列清空之前,一个urb的传输过程如下:

当要进行数据传输时,需要分配、设置和提交一个urb给USB核心。核心对urb进行解析,将控制信息提交给主机控制器,由主机控制器完成数据到设备的传输。此时,驱动程序只需等待。当数据回传到主机控制器后,会转发给USB核心,唤醒等待的驱动程序。

 

具体函数操作如下图:

各函数声明如下:

struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)

inline void usb_fill_int_urb (struct urb *urb,    /* 要初始化的urb指针 */
                        struct usb_device *dev,    /* 所要访问的设备 */
                        unsigned int      pipe,    /* 要访问的端点所对应的管道,使用usb_sndintpipe()或usb_rcvintpipe()创建 */
                        void              *transfer_buffer,    /* 要传输的数据缓冲区 */
                        int               buffer_length,    /* 缓冲区长度 */
                        usb_complete_t    complete_fn,        /* 当完成该urb所请求的操作时,要调用的回调函数 */
                        void              *context,            /* complet_fn函数所需的上下文,通常取值为dev */
                        int               interval)            /*urb被调度的时间间隔 */
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)
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)

int usb_submit_urb(struct urb *urb, gfp_t mem_flags);

void usb_kill_urb(struct urb *urb);

void usb_free_urb(struct urb *urb);

其中complete_fn()就是传输完成函数

 

 

四、USB鼠标设备驱动

在熟悉各个函数后,我们在本节完成USB鼠标设备驱动,步骤如下:

1. 分配设置usb_driver

.id_table

.probe

.disconnect

2. 使用usb_register()注册usb_driver

3. 在probe()函数中完成输入子系统和urb设置,最后提交urb

4. 在传输完成函数函数中判断数据,上报数据,重新提交urb

5. 在disconnect()函数中注销urb和输入子系统

6. 使用usb_deregister()注销usb_driver

 

在编写驱动时,可参考例子drivers/hid/usbhid/usbmouse.c

 

USB鼠标驱动源代码:

  1 #include <linux/module.h>
  2 #include <linux/fs.h>
  3 #include <linux/init.h>
  4 #include <linux/cdev.h>
  5 #include <linux/slab.h>
  6 #include <linux/device.h>
  7 #include <linux/usb/input.h>
  8 #include <linux/hid.h>
  9 
 10 #include <asm/uaccess.h>
 11 
 12 static struct usb_device_id mouse_table [] = {
 13     { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
 14         USB_INTERFACE_PROTOCOL_MOUSE) },
 15     { }    /* Terminating entry */
 16 };
 17 
 18 static struct input_dev *usbinput;
 19 static dma_addr_t usb_buf_phys;
 20 static char *buf_mem;
 21 static struct urb *usb_urb;
 22 static int len;
 23 
 24 static unsigned int cnt;
 25 
 26 static void usb_mouse_irq(struct urb *purb)
 27 {
 28 #if 0
 29     /* 用于测试哪个bit是用于表示左、中、右键
 30      * 我所使用的鼠标使用bit[0]表示左、中、右键
 31      */
 32     int i;
 33     
 34     printk("cnt: %02d, ", cnt++);
 35     for(i = 0; i < len; ++i)
 36     {
 37         printk("%02x ", buf_mem[i]);
 38     }
 39     printk("\n");
 40 #else
 41     static unsigned char preval = 0;    /* 用于存储上一个数据 */
 42     if((preval & 1) != (buf_mem[0] & 1)) {    /* 鼠标左键数据有变化 */
 43         input_report_key(usbinput, KEY_L, (buf_mem[0] & 1) ? 1 : 0);
 44         input_sync(usbinput);
 45     }
 46     if((preval & (1 << 1)) != (buf_mem[0] & (1 << 1))) {
 47         input_report_key(usbinput, KEY_S,   (buf_mem[0] & (1 << 1)) ? 1 : 0);
 48         input_sync(usbinput);
 49     }
 50     if((preval & (1 << 2)) != (buf_mem[0] & (1 << 2))) {
 51         input_report_key(usbinput, KEY_ENTER,   (buf_mem[0] & (1 << 2)) ? 1 : 0);
 52         input_sync(usbinput);
 53     }
 54     preval = buf_mem[0];
 55 #endif
 56 
 57     usb_submit_urb(usb_urb, GFP_KERNEL);
 58 
 59 }
 60 
 61 static int mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
 62 {
 63     struct usb_device *dev = interface_to_usbdev(intf);
 64     struct usb_host_interface *interface;
 65     struct usb_endpoint_descriptor *endpoint;
 66     unsigned int pipe;
 67     int ret;
 68 
 69     interface = intf->cur_altsetting;
 70     endpoint = &interface->endpoint[0].desc;
 71 
 72     /* 1. 输入子系统设置 */
 73     usbinput = input_allocate_device();
 74 
 75     set_bit(EV_KEY, usbinput->evbit);
 76     set_bit(EV_REP, usbinput->evbit);
 77 
 78     set_bit(KEY_L, usbinput->keybit);
 79     set_bit(KEY_S, usbinput->keybit);
 80     set_bit(KEY_ENTER, usbinput->keybit);
 81 
 82     ret = input_register_device(usbinput);
 83 
 84     /* 2. urb设置 */
 85     usb_urb = usb_alloc_urb(0, GFP_KERNEL);
 86     pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 87     
 88     len = endpoint->wMaxPacketSize;
 89     buf_mem = usb_alloc_coherent(dev, len, GFP_ATOMIC, &usb_buf_phys);
 90 
 91     usb_fill_int_urb(usb_urb, dev, pipe, buf_mem, len, 
 92         usb_mouse_irq, NULL, endpoint->bInterval);
 93     usb_urb->transfer_dma = usb_buf_phys;
 94     usb_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 95 
 96     return usb_submit_urb(usb_urb, GFP_KERNEL);
 97 }
 98 
 99 static void mouse_disconnect(struct usb_interface *intf)
100 {
101     struct usb_device *dev = interface_to_usbdev(intf);
102 
103     usb_kill_urb(usb_urb);
104     usb_free_urb(usb_urb);
105 
106     usb_free_coherent(dev, len, buf_mem, usb_buf_phys);
107     input_unregister_device(usbinput);
108     input_free_device(usbinput);
109 }
110 
111 static struct usb_driver mouse_driver = {
112     .name  = "itop4412_mouse",
113     .probe = mouse_probe,
114     .disconnect = mouse_disconnect,
115     .id_table   = mouse_table,
116 };
117 
118 static int __init usbmouse_init(void)
119 {
120     return usb_register(&mouse_driver);
121 }
122  
123 static void __exit usbmouse_exit(void)
124 {
125     usb_deregister(&mouse_driver);
126 }
127  
128 /* 声明段属性 */
129 module_init(usbmouse_init);
130 module_exit(usbmouse_exit);
131 
132 MODULE_LICENSE("GPL");
View Code

Makefile:

 1 KERN_DIR = /work/itop4412/tools/linux-3.5
 2 
 3 all:
 4     make -C $(KERN_DIR) M=`pwd` modules 
 5 
 6 clean:
 7     make -C $(KERN_DIR) M=`pwd` modules clean
 8     rm -rf modules.order
 9 
10 obj-m    += usbmouse.o
View Code

 

测试:

在编译并在开发板上insmod后,会出现如下信息:

input: Unspecified device as /devices/virtual/input/input4

插入USB鼠标后,会出现如下信息:

sbcore: registered new interface driver itop4412_mouse

 

接下来执行:

# ls /dev/event*

最后一个/dev/event2为USB鼠标对应事件

执行:

#hexdump /dev/event2

接下来按键,效果如下图:

在此我以第一行数据为例解释一下各个数字的意义:

0000000 0393 0000 55a4 0008   0001    001f    0001 0000

 次数    秒    微秒    按键类  哪个按键    按下

 

 

下一章  十七、块设备驱动

 

转载于:https://www.cnblogs.com/Lioker/p/10933171.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值