编写USB鼠标驱动程序,并测试

学习目标:编写USB鼠标驱动程序,并测试(将USB鼠标的左键当作L按键,将USB鼠标的右键当作S按键,中键当作回车按键).


一、怎么写USB设备驱动程序?步骤如下:

1. 首先先定义全局变量usb_driver结构体,并在入口函数中通过usb_register()函数进行注册

2. 分别写usb_driver结构体的成员函数:myusb_mouseprobe、myusb_mousedisconnect、myusb_mouseid_table

--> 2.1 usb_driver的probe函数

  1) 分配一个input_dev结构体

  2) 设置input_dev结构体,使它支持L、S、回车3个按键事件;

  3) 注册input_dev结构体

  4) 硬件相关的操作,即设置USB数据传输3要素和urb结构体:

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

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

   ->4.3) 申请urb结构体,并利用usb_fill_int_urb()初始化,用来传输数据

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

   ->4.5) 使用usb_submit_urb()提交urb.

--> 2.2 编写probe函数调用的鼠标中断函数

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

  2)使用usb_submit_urb()提交urb

--> 2.3 usb_driver的disconnect函数中

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

  2) 释放urb结构体

  3 )释放USB缓存区

  4)注销并释放input_device结构体

3. 出口函数通过usb_deregister ()函数注销usb_driver结构体

二、程序源码

  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 *uk_dev;        //input_dev
  9 static char *usb_buf;                   //虚拟地址缓存区
 10 static dma_addr_t usb_buf_phys;         //DMA缓存区
 11 static int len;                         //数据包长度
 12 static struct urb *uk_urb;              //urb数据传输所用结构体
 13 
 14 static struct usb_device_id myusb_mouseid_table [] = {
 15     { USB_INTERFACE_INFO(
 16                             USB_INTERFACE_CLASS_HID,         //接口类:hid类
 17                             USB_INTERFACE_SUBCLASS_BOOT,     //子类:启动设备类
 18                             USB_INTERFACE_PROTOCOL_MOUSE) }, // USB协议:鼠标协议
 19 };
 20 
 21 static void myusb_mouseirq(struct urb *urb)
 22 {
 23     static unsigned char pre_val;
 25     /* USB鼠标数据含义* data[0]:   bit0-左键, 1-按下, 0-松开
 26      *                           bit1-右键, 1-按下, 0-松开
 27      *                           bit2-中键, 1-按下, 0-松开  29      */
 30     if ((pre_val & (1<<0)) != (usb_buf[0] & (1<<0)))
 31     {
 32         /* 左键发生了变化 */
 33         input_event(uk_dev, EV_KEY, KEY_L, (usb_buf[0] & (1<<0)) ? 1 : 0);
 34         input_sync(uk_dev);
 35     }
 37     if ((pre_val & (1<<1)) != (usb_buf[0] & (1<<1)))
 38     {
 39         /* 右键发生了变化 */
 40         input_event(uk_dev, EV_KEY, KEY_S, (usb_buf[0] & (1<<1)) ? 1 : 0);
 41         input_sync(uk_dev);
 42     }
 44     if ((pre_val & (1<<2)) != (usb_buf[0] & (1<<2)))
 45     {
 46         /* 中键发生了变化 */
 47         input_event(uk_dev, EV_KEY, KEY_ENTER, (usb_buf[0] & (1<<2)) ? 1 : 0);
 48         input_sync(uk_dev);
 49     }
 51     pre_val = usb_buf[0];
 53     /* 重新提交urb */
 54     usb_submit_urb(uk_urb, GFP_KERNEL);
 55 }
 57 static int myusb_mouseprobe(struct usb_interface *intf, const struct usb_device_id *id)
 58 {
 59     struct usb_device *dev = interface_to_usbdev(intf); // 设备,通过usb_ interface接口获取usb_device设备,为后面设置USB数据传输用
 60     struct usb_host_interface *interface;               // 当前接口
 61     struct usb_endpoint_descriptor *endpoint;
 62     int pipe;                                            // 端点管道
 63     
 64     interface = intf->cur_altsetting;
 65     endpoint = &interface->endpoint[0].desc;            // 当前接口下的端点描述符
 66 
 67     /* a. 分配一个input_dev */
 68     uk_dev = input_allocate_device(); 
 70     /* b. 设置 */
 71     /* b.1 能产生哪类事件 */
 72     set_bit(EV_KEY, uk_dev->evbit);
 73     set_bit(EV_REP, uk_dev->evbit);
 74     
 75     /* b.2 能产生哪些事件 */
 76     set_bit(KEY_L, uk_dev->keybit);
 77     set_bit(KEY_S, uk_dev->keybit);
 78     set_bit(KEY_ENTER, uk_dev->keybit);
 79     
 80     /* c. 注册 */
 81     input_register_device(uk_dev);
 82     
 83     /* d. 硬件相关操作 */
 84     /* 数据传输3要素: 源,目的,长度 */
 85     /* 源: USB设备的某个端点 */
 86     pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 87 
 88     /* 长度: */
 89     len = endpoint->wMaxPacketSize;
 90 
 91     /* 目的: */
 92     usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);
 93 
 94     /* 使用"3要素" */
 95     /* 分配usb request block */
 96     uk_urb = usb_alloc_urb(0, GFP_KERNEL);//usb传输素具的urb结构体
 97     /* 使用"3要素设置urb" */
 98     usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, myusb_mouseirq, NULL, endpoint->bInterval);
 99     uk_urb->transfer_dma = usb_buf_phys;   //设置DMA地址
100     uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; //设置使用DMA地址
101 
102     /* 使用URB */
103     usb_submit_urb(uk_urb, GFP_KERNEL);
104     
105     return 0;
106 }
108 static void myusb_mousedisconnect(struct usb_interface *intf)
109 {
110     struct usb_device *dev = interface_to_usbdev(intf);
112     //printk("disconnect usbmouse!\n");
113     usb_kill_urb(uk_urb);
114     usb_free_urb(uk_urb);
115 
116     usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
117     input_unregister_device(uk_dev);
118     input_free_device(uk_dev);
119 }
121 /* 1. 分配/设置usb_driver */
122 static struct usb_driver myusb_mousedriver = {
123     .name        = "myusb_mouse",
124     .probe        = myusb_mouseprobe,
125     .disconnect    = myusb_mousedisconnect,
126     .id_table    = myusb_mouseid_table,
127 };
130 static int myusb_mouseinit(void)
131 {
132     /* 2. 注册 */
133     usb_register(&myusb_mousedriver);
134     return 0;
135 }
137 static void myusb_mouseexit(void)
138 {
139     usb_deregister(&myusb_mousedriver);    
140 }
142 module_init(myusb_mouseinit);
143 module_exit(myusb_mouseexit);
145 MODULE_LICENSE("GPL");

猜你喜欢

转载自www.cnblogs.com/lxl-lennie/p/10189188.html