usb设备驱动框架学习记录

目录

    1、usb硬件框架

    2、linux的usb驱动的软件框架(总线部分负责的工作、设备驱动部分负责的工作)

    3、usb设备插入usb主机到进入usb设备驱动probe函数的大致流程

    4、以usb鼠标为例说明usb设备驱动怎么和usb设备通信

    5、以鼠标驱动为例说明怎么编写一个usb设备驱动程序

1、usb硬件框架

  usb设备的硬件框架如下图所示,有4根线D-、D+、VCC和GND,usb设备接入usb主机后,引起主机内的D-或D+电位变化,从而通知usb主机有设备接入

2、linux的usb驱动的软件框架(总线部分负责的工作、设备驱动部分负责的工作)

  类似spi设备驱动,在linux内核中,将usb的设备驱动分为usb总线驱动和usb设备驱动两个部分,usb总线驱动是内核中usb设备驱动公有的部分,负责usb协议具体的实现,比如热插拔、设备发现、设备和驱动的匹配以及提供数据读写接口给usb设备驱动程序;总的来说,usb总线驱动程序负责如下3个功能:(1)负责识别USB设备,(2)给USB设备找到对应的驱动程序,(3)提供usb数据读写函数;

  具体的usb设备驱动程序负责使用usb总线驱动提供的接口读写usb设备。

3、usb设备插入usb主机到进入usb设备驱动probe函数的大致流程,调用probe前的动作都在usb总线驱动程序中完成

1)usb设备接入usb主机,引起主机D-或D+的电位跳变,产生中断,进入hub_irq函数;

2)给新设备分配地址 choose_address;

3)把设备地址告诉usb设备 hub_set_address;

4)获取usb设备的设备描述符 get_hub_descriptor;

5)把所有的描述符读出来并解析;

6)创建设备device;

7)把设备device放入usb总线usb_bus_type的dev链表,从usb_bus_type的driver链表里取出usb_driver,把usb_interface和usb_driver的id_table比较,如果能匹配,调用usb_driver的probe函数。

4、以usb鼠标为例说明usb设备驱动怎么和usb设备通信

1)usb通信是通过端点进行的,端点标识了usb设备具备的通信方式,每种设备都不一样,比如usb鼠标只有一个中断类型的端点,所以通信的第一步是获取usb设备的端点信息;

比如usb鼠标:

1 /* 端点个数保存在接口描述符里面 */
2     struct usb_host_interface *interface;
3     interface = intf->cur_altsetting;
4     interface->desc.bNumEndpoints
5     /* 端点描述符 */
6     endpoint = &interface->endpoint[0].desc

2)对通信要使用的端点进行设置,将usb设备编号和端点地址进行关联

 1 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); 

3)分配usb通信的buf

 1 len = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); 2 usb_buf = usb_alloc_coherent(dev, len, GFP_ATOMIC, &usb_buf_phys); 

4)分配,使用端点、usb通信buf、物理地址以及中断函数填充urb

1 uk_urb = usb_alloc_urb(0, GFP_KERNEL);
2     usb_fill_int_urb(uk_urb, dev, pipe, usb_buf,
3              len, usbmouse_as_key_irq, NULL, endpoint->bInterval);
4     uk_urb->transfer_dma = usb_buf_phys;
5     uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

5)提交urb,这个步骤完成后,usb主机会不断查询usb设备端点是否有数据,有数据就给cpu产生中断,从而调用urb绑定的中断处理函数usbmouse_as_key_irq,每次中断处理后,都要在中断函数中重新提交urb

 1 usb_submit_urb(uk_urb, GFP_KERNEL) 

5、以鼠标驱动为例说明怎么编写一个usb设备驱动程序

1)创建并注册一个usb_driver结构体,以和usb_device匹配

2)获取usb设备的端点信息,创建usb设备请求块urb

  1 #include <linux/kernel.h>
  2 #include <linux/slab.h>
  3 #include <linux/module.h>
  4 #include <linux/init.h>
  5 #include <linux/usb/input.h>
  6 #include <linux/hid.h>
  7 
  8 /*
  9  * Version Information
 10  */
 11 #define DRIVER_VERSION "v1.6"
 12 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 13 #define DRIVER_DESC "USB HID Boot Protocol mouse driver"
 14 
 15 static struct input_dev *uk_dev;
 16 static char *usb_buf;
 17 static dma_addr_t usb_buf_phys;
 18 static int len;
 19 static struct urb *uk_urb;
 20 
 21 static void usbmouse_as_key_irq(struct urb *urb)
 22 {
 23     int i;
 24     static int cnt = 0;
 25     
 26     printk("data cnt %d : ", ++cnt);
 27     for (i = 0; i < 4; i++) {
 28         printk("%02X ", usb_buf[i]);
 29     }
 30     printk("
");
 31     
 32     /* 重新提交urb */
 33     usb_submit_urb(urb, GFP_ATOMIC);
 34 }
 35 
 36 static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
 37 {
 38     /*
 39      * usb_interface表示逻辑上的设备 
 40     */
 41     struct usb_device *dev = interface_to_usbdev(intf);
 42     struct usb_host_interface *interface;
 43     struct usb_endpoint_descriptor *endpoint;
 44     int error;
 45     int pipe;
 46     
 47     interface = intf->cur_altsetting;
 48     
 49     /* 通过端点数判断是否是鼠标,鼠标设备的端点只有一个,且是中断类型 */
 50     if (interface->desc.bNumEndpoints != 1)
 51         return -ENODEV;
 52 
 53     endpoint = &interface->endpoint[0].desc;
 54     if (!usb_endpoint_is_int_in(endpoint))
 55         return -ENODEV;
 56 
 57     /* a. 分配一个input_dev */
 58     uk_dev = input_allocate_device();
 59     /* b. 设置 */
 60     /* b.1 能产生哪类事件 */
 61     set_bit(EV_KEY, uk_dev->evbit);
 62     set_bit(EV_REP, uk_dev->evbit);
 63     /* b.2 能产生哪些事件 */
 64     set_bit(KEY_L, uk_dev->keybit);
 65     set_bit(KEY_S, uk_dev->keybit);
 66     set_bit(KEY_ENTER, uk_dev->keybit);
 67     //input_set_capability(uk_dev, EV_KEY, KEY_HOME);
 68     /* c. 注册 */
 69     error = input_register_device(uk_dev);
 70     if (error) {
 71         dev_err(dev, "Unable to register uk_dev device, error: %d
",
 72             error);
 73         return error;
 74     }
 75 
 76     /* d. 硬件相关的操作 */
 77     /* 数据传输3要素:源,目的,长度 */
 78     /* 源:USB设备的某个端点 */
 79     pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 80     
 81     /* 长度 */
 82     len = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); //endpoint->wMaxPacketSize;
 83     printk("len = %d
", len);
 84 //    len = 8;
 85     
 86     /* 目的 */
 87     usb_buf = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &usb_buf_phys);
 88     
 89     /* 使用3要素 */
 90     /* 分配usb request block */
 91     uk_urb = usb_alloc_urb(0, GFP_KERNEL);
 92     /* 使用3要素设置urb */
 93     usb_fill_int_urb(uk_urb, dev, pipe, usb_buf,
 94              len, usbmouse_as_key_irq, NULL, endpoint->bInterval);
 95     uk_urb->transfer_dma = usb_buf_phys;
 96     uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 97 
 98     /* 使用urb */
 99     usb_submit_urb(uk_urb, GFP_KERNEL);
100     printk("found usbmouse11!
");
101 
102     return 0;
103 }
104 
105 static void usb_mouse_disconnect(struct usb_interface *intf)
106 {
107     printk("usb_mouse_disconnect usbmouse!
");
108     usb_kill_urb(uk_urb);
109     usb_free_urb(uk_urb);
110     usb_free_coherent(interface_to_usbdev(intf), len, usb_buf, usb_buf_phys);
111     input_free_device(uk_dev);
112 }
113 
114 static const struct usb_device_id usb_mouse_id_table[] = {
115     { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
116         USB_INTERFACE_PROTOCOL_MOUSE) },
117     //{USB_DEVICE(0x1234, 0x5678)},
118     { }    /* Terminating entry */
119 };
120 
121 static struct usb_driver usb_mouse_driver = {
122     .name        = "usbmouse",
123     .probe        = usb_mouse_probe,
124     .disconnect    = usb_mouse_disconnect,
125     .id_table    = usb_mouse_id_table,
126 };
127 
128 module_usb_driver(usb_mouse_driver);
129 
130 MODULE_AUTHOR(DRIVER_AUTHOR);
131 MODULE_DESCRIPTION(DRIVER_DESC);
132 MODULE_LICENSE("GPL");

参考

韦东山老师的usb设备驱动视频

  http://t.elecfans.com/c183.html

原文地址:https://www.cnblogs.com/lztutumo/p/13618709.html