学习目标:编写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");