linux设备驱动(30)usb驱动-usb鼠标驱动详解

内核自带的USB鼠标驱动位于:/drivers/hid/usbhid/usbmouse.c

1 usb mouse driver

 1 static struct usb_driver usb_mouse_driver = {
 2     .name        = "usbmouse",
 3     .probe        = usb_mouse_probe,
 4     .disconnect    = usb_mouse_disconnect,
 5     .id_table    = usb_mouse_id_table,
 6 };
 7 
 8 static struct usb_device_id usb_mouse_id_table [] = {
 9     { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
10         USB_INTERFACE_PROTOCOL_MOUSE) },
11     { }    /* Terminating entry */
12 };

USB_INTERFACE_INFO()设置usb_driver驱动的id_table成员

USB_INTERFACE_CLASS_HID:接口类,我们USB鼠标为HID类,所以填入0X03

USB_INTERFACE_SUBCLASS_BOOT:接口子类为启动设备

USB_INTERFACE_PROTOCOL_MOUSE :接口协议为鼠标协议,填入

2 usb mouse probe函数

 1 static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
 2 {
 3     struct usb_device *dev = interface_to_usbdev(intf);
 4     struct usb_host_interface *interface;
 5     struct usb_endpoint_descriptor *endpoint;
 6     struct usb_mouse *mouse;
 7     struct input_dev *input_dev;
 8     int pipe, maxp;
 9     int error = -ENOMEM;
10 
11     interface = intf->cur_altsetting;
12 
13     if (interface->desc.bNumEndpoints != 1)
14         return -ENODEV;
15 
16     endpoint = &interface->endpoint[0].desc;
17     if (!usb_endpoint_is_int_in(endpoint))
18         return -ENODEV;
19 
20     pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
21     maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
22 
23     mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
24     input_dev = input_allocate_device();//分配input设备
25     if (!mouse || !input_dev)
26         goto fail1;
27 
28     mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
29     if (!mouse->data)
30         goto fail1;
31 
32     mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
33     if (!mouse->irq)
34         goto fail2;
35 
36     mouse->usbdev = dev;
37     mouse->dev = input_dev;
38 
39     if (dev->manufacturer)
40         strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));
41 
42     if (dev->product) {
43         if (dev->manufacturer)
44             strlcat(mouse->name, " ", sizeof(mouse->name));
45         strlcat(mouse->name, dev->product, sizeof(mouse->name));
46     }
47 
48     if (!strlen(mouse->name))
49         snprintf(mouse->name, sizeof(mouse->name),
50              "USB HIDBP Mouse %04x:%04x",
51              le16_to_cpu(dev->descriptor.idVendor),
52              le16_to_cpu(dev->descriptor.idProduct));
53 
54     usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
55     strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
56 
57     input_dev->name = mouse->name;
58     input_dev->phys = mouse->phys;
59     usb_to_input_id(dev, &input_dev->id);
60     input_dev->dev.parent = &intf->dev;
61     /*设置input支持的按键*/
62     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
63     input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
64         BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
65     input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
66     input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
67         BIT_MASK(BTN_EXTRA);
68     input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
69 
70     input_set_drvdata(input_dev, mouse);
71 
72     input_dev->open = usb_mouse_open;
73     input_dev->close = usb_mouse_close;
74     /*设置usb数据传输*/
75     usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,//初始化urb,对于中断 urb,使用usb_fill_int_urb()函数来初始化 urb。
76              (maxp > 8 ? 8 : maxp),
77              usb_mouse_irq, mouse, endpoint->bInterval);
78     mouse->irq->transfer_dma = mouse->data_dma;
79     mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
80 
81     error = input_register_device(mouse->dev);//注册input设备
82     if (error)
83         goto fail3;
84 
85     usb_set_intfdata(intf, mouse);
86     return 0;
87 
88 fail3:    
89     usb_free_urb(mouse->irq);
90 fail2:    
91     usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);
92 fail1:    
93     input_free_device(input_dev);
94     kfree(mouse);
95     return error;
96 }

2.1  函数usb_fill_int_urb

 对于中断 urb,使用usb_fill_int_urb()函数来初始化 urb。

详见:linux设备驱动(30)usb驱动-urb详解

urb完成时被调用的完成处理函数complete :usb_mouse_irq

2.2 函数 usb_mouse_irq

 1 static void usb_mouse_irq(struct urb *urb)
 2 {
 3     struct usb_mouse *mouse = urb->context;
 4     signed char *data = mouse->data;
 5     struct input_dev *dev = mouse->dev;
 6     int status;
 7 
 8     switch (urb->status) {
 9     case 0:            /* success */
10         break;
11     case -ECONNRESET:    /* unlink */
12     case -ENOENT:
13     case -ESHUTDOWN:
14         return;
15     /* -EPIPE:  should clear the halt */
16     default:        /* error */
17         goto resubmit;
18     }
19 
20     input_report_key(dev, BTN_LEFT,   data[0] & 0x01);
21     input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);
22     input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
23     input_report_key(dev, BTN_SIDE,   data[0] & 0x08);
24     input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);
25 
26     input_report_rel(dev, REL_X,     data[1]);
27     input_report_rel(dev, REL_Y,     data[2]);
28     input_report_rel(dev, REL_WHEEL, data[3]);
29 
30     input_sync(dev);
31 resubmit:
32     status = usb_submit_urb (urb, GFP_ATOMIC);
33     if (status)
34         dev_err(&mouse->usbdev->dev,
35             "can't resubmit intr, %s-%s/input0, status %d\n",
36             mouse->usbdev->bus->bus_name,
37             mouse->usbdev->devpath, status);
38 }

3 usb鼠标驱动总结:

首先先定义全局变量:usb_driver结构体,input_dev指针结构体 ,虚拟地址缓存区,DMA地址缓存区

(1) 入口函数中

     1)通过usb_register()函数注册usb_driver结构体

(2) 在usb_driver的probe函数中

     1)分配一个input_dev结构体

     2)设置input_dev支持L、S、回车、3个按键事件

     3)注册input_dev结构体

     4)设置USB数据传输:

      4.1)通过usb_rcvintpipe()创建一个接收中断类型的端点管道,用来端点和数据缓冲区之间的连接

      4.2)通过usb_buffer_alloc()申请USB缓冲区

      4.3)申请并初始化urb结构体,urb:用来传输数据

      4.4) 因为我们2440支持DMA,所以要告诉urb结构体,使用DMA缓冲区地址

      4.5)使用usb_submit_urb()提交urb

(3) 在鼠标中断函数中

   1)判断缓存区数据是否改变,若改变则上传鼠标事件

   2)使用usb_submit_urb()提交urb

(4)在usb_driver的disconnect函数中

   1)通过usb_kill_urb()杀掉提交到内核中的urb

   2)释放urb

   3)释放USB缓存区

   4)注销input_device,释放input_device

(5)出口函数

   1)通过usb_deregister ()函数注销usb_driver结构体

4 usb鼠标示例

将USB鼠标的左键当作L按键,将USB鼠标的右键当作S按键,中键当作回车按键。

  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 static struct input_dev *myusb_mouse_dev;              //input_dev
  9 static char *myusb_mouse_buf;                         //虚拟地址缓存区
 10 static dma_addr_t myusb_mouse_phyc;                     //DMA缓存区;
 11 
 12 static __le16 myusb_mouse_size;                        //数据包长度
 13 
 14 static struct urb  *myusb_mouse_urb;                     //urb
 15 
 16 
 17 static void myusb_mouse_irq(struct urb *urb)               //鼠标中断函数
 18 {
 19    static char buf1=0;
 20    //for(i=0;i<myusb_mouse_size;i++)
 21   // printk("%02x  ",myusb_mouse_buf[i]);
 22  //  printk("\n");
 23 
 24 
 25     /*bit 1-左右中键  0X01:左键   0X02:右键     0x04:中键   */
 26      if((buf1&(0X01))    !=      (myusb_mouse_buf[1]&(0X01)))
 27         {
 28                 input_report_key(myusb_mouse_dev, KEY_L, buf1&(0X01)? 1:0);
 29                 input_sync(myusb_mouse_dev);
 30         }
 31      if((buf1&(0X02))    !=    (myusb_mouse_buf[1]&(0X02)))
 32         {
 33                 input_report_key(myusb_mouse_dev, KEY_S, buf1&(0X02)? 1:0);
 34                 input_sync(myusb_mouse_dev);
 35         }
 36      if((buf1&(0X04))    !=    (myusb_mouse_buf[1]&(0X04))  )
 37           {
 38                 input_report_key(myusb_mouse_dev, KEY_ENTER, buf1&(0X04)? 1:0);
 39                 input_sync(myusb_mouse_dev);
 40           }
 41 
 42      buf1=myusb_mouse_buf[1];                                   //更新数据
 43 
 44      usb_submit_urb(myusb_mouse_urb, GFP_KERNEL);
 45 }
 46 
 47 
 48 static int myusb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
 49 {
 50        struct usb_device *dev = interface_to_usbdev(intf);             //设备
 51        struct usb_endpoint_descriptor *endpoint;
 52        struct usb_host_interface *interface;                         //当前接口
 53        int pipe;                                                   //端点管道
 54 
 55        interface=intf->cur_altsetting;
 56        endpoint = &interface->endpoint[0].desc;                                    //当前接口下的端点描述符
 57 
 58 
 59        printk("VID=%x,PID=%x\n",dev->descriptor.idVendor,dev->descriptor.idProduct); //打印VID,PID
 60 
 61 
 62  /*   1)分配一个input_dev结构体  */
 63        myusb_mouse_dev=input_allocate_device();
 64 
 65 
 66  /*   2)设置input_dev支持L、S,回车、3个按键事件*/
 67        set_bit(EV_KEY, myusb_mouse_dev->evbit);
 68        set_bit(EV_REP, myusb_mouse_dev->evbit);        //支持重复按功能
 69        set_bit(KEY_L, myusb_mouse_dev->keybit);
 70        set_bit(KEY_S, myusb_mouse_dev->keybit);
 71        set_bit(KEY_ENTER, myusb_mouse_dev->keybit);
 72 
 73  /*   3)注册input_dev结构体*/
 74        input_register_device(myusb_mouse_dev);
 75 
 76 
 77  /*   4)设置USB数据传输 */
 78  /*->4.1)通过usb_rcvintpipe()创建一个端点管道*/
 79        pipe=usb_rcvintpipe(dev,endpoint->bEndpointAddress);
 80 
 81   /*->4.2)通过usb_buffer_alloc()申请USB缓冲区*/
 82        myusb_mouse_size=endpoint->wMaxPacketSize;
 83        myusb_mouse_buf=usb_buffer_alloc(dev,myusb_mouse_size,GFP_ATOMIC,&myusb_mouse_phyc);
 84 
 85   /*->4.3)通过usb_alloc_urb()和usb_fill_int_urb()申请并初始化urb结构体 */
 86        myusb_mouse_urb=usb_alloc_urb(0,GFP_KERNEL);
 87        usb_fill_int_urb (myusb_mouse_urb,                       //urb结构体
 88                                  dev,                           //usb设备
 89                                  pipe,                          //端点管道
 90                                  myusb_mouse_buf,               //缓存区地址
 91                                  myusb_mouse_size,              //数据长度
 92                                  myusb_mouse_irq,               //中断函数
 93                                  0,
 94                                  endpoint->bInterval);          //中断间隔时间
 95 
 96 
 97   /*->4.4) 因为我们2440支持DMA,所以要告诉urb结构体,使用DMA缓冲区地址*/
 98         myusb_mouse_urb->transfer_dma   =myusb_mouse_phyc;             //设置DMA地址
 99         myusb_mouse_urb->transfer_flags   =URB_NO_TRANSFER_DMA_MAP;     //设置使用DMA地址
100 
101   /*->4.5)使用usb_submit_urb()提交urb*/
102         usb_submit_urb(myusb_mouse_urb, GFP_KERNEL);
103        return 0;
104 }
105 
106 static void myusb_mouse_disconnect(struct usb_interface *intf)
107 {
108     struct usb_device *dev = interface_to_usbdev(intf);                  //设备
109 
110     usb_kill_urb(myusb_mouse_urb);
111     usb_free_urb(myusb_mouse_urb);
112     usb_buffer_free(dev, myusb_mouse_size, myusb_mouse_buf,myusb_mouse_phyc);
113 
114     input_unregister_device(myusb_mouse_dev);         //注销内核中的input_dev
115     input_free_device(myusb_mouse_dev);             //释放input_dev
116 }
117 
118 static struct usb_device_id myusb_mouse_id_table [] = {
119        { USB_INTERFACE_INFO(
120               USB_INTERFACE_CLASS_HID,                 //接口类:hid类
121               USB_INTERFACE_SUBCLASS_BOOT,             //子类:启动设备类
122               USB_INTERFACE_PROTOCOL_MOUSE) },      //USB协议:鼠标协议
123 };
124 
125 
126 static struct usb_driver myusb_mouse_drv = {
127        .name            = "myusb_mouse",
128        .probe           = myusb_mouse_probe,
129        .disconnect     = myusb_mouse_disconnect,
130        .id_table  = myusb_mouse_id_table,
131 };
132 
133 module_usb_driver(usb_mouse_driver);

参考博文:https://www.cnblogs.com/lifexy/p/7641602.html

posted @ 2020-07-14 21:36  Action_er  阅读(878)  评论(0编辑  收藏  举报