• 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

  • 相关阅读:
    【杭电】[1874]畅通工程续
    【杭电】[2544]最短路
    【杭电】[1087]Super Jumping! Jumping! Jumping!
    【HPU】[1689]MZY寻宝
    【杭电】[1495]非常可乐
    【杭电】[1242]Rescue
    【杭电】[1787]GCD Again
    【算法】欧拉函数——小于n的数中与n互质数的数目
    【HPU】[1738]Stack ? Queue ?
    【HPU】[1737]老王特警队
  • 原文地址:https://www.cnblogs.com/lztutumo/p/13618709.html
Copyright © 2020-2023  润新知