USB 驱动(监测鼠标左键的动作)
(基于 Linux 3.4.2 内核)
可分为以下几个步骤来完成这个驱动:
1. 分配设置一个 usb_driver 结构体 2. 注册这个 usb_driver (如果设备的 id_table 与驱动匹配的话会调用驱动程序的 probe 函数) 3. 在 probe 函数中分配 urb 4. 配置 urb 5. 调用 usb_submit_urb 启用 urb 6. 在 urb 中断函数内处理状态 7. 重新提交 urb
usb_driver 的配置与注册
/* 驱动的 id_table */ static struct usb_device_id usb_mouse_id_table [] = { { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_MOUSE) }, { } }; /* 分配设置 usb_driver */ static struct usb_driver mouse_monitor = { .name = "MouseMonitor", .probe = mouse_monitor_probe, .disconnect = mouse_monitor_disconnect, .id_table = usb_mouse_id_table, }; /* 注册 usb_driver */ static int mouse_monitor_init(void) { usb_register(&mouse_monitor); return 0; }
probe 函数
static int mouse_monitor_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; static struct usb_device *dev; dma_addr_t usb_buf_phy; int pipe; int buffer_length; /* 得到 usb_device */ dev = interface_to_usbdev(intf); /* 得到当前的接口描述符与端点描述符 */ interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; /* 获取到设备数据长度 */ buffer_length = __le16_to_cpu(endpoint->wMaxPacketSize); len = buffer_length; /* 获取到通信的管道 */ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); /* 分配一段连贯的内存 */ usb_buf = usb_alloc_coherent(dev, buffer_length, GFP_ATOMIC, &usb_buf_phy); /* 分配 urb */ MouseUrb = usb_alloc_urb(0, GFP_KERNEL); /* 配置 urb */ usb_fill_int_urb(MouseUrb, dev, pipe, usb_buf, (buffer_length > 8 ? 8 : buffer_length), usb_complete, NULL, endpoint->bInterval); MouseUrb->transfer_dma = usb_buf_phy; MouseUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* 提交调用 urb */ usb_submit_urb(MouseUrb, GFP_KERNEL); return 0; }
urb 传输完成函数
static void usb_complete(struct urb *urb) { static unsigned char presta; #if 0 int i; for (i = 0; i < len; i++) printk("%02x ", usb_buf[i]); printk("\n"); #endif if(presta != (usb_buf[1] & 0x01)){ if(presta) printk("BTN_LEFT is released. \n"); else printk("BTN_LEFT is pressed. \n"); } /* 保存状态 */ presta = usb_buf[1] & 0x01; /* 重新提交 urb */ usb_submit_urb(MouseUrb, GFP_KERNEL); }
usb_complete 函数中注释掉的程序为测试使用,通过输出的数据找到鼠标左键对应的 usb_buf 与 bit 位。
测试驱动
make menuconfig 去掉原来的 USB 鼠标驱动 -> Device Drivers -> HID Devices <> USB Human Interface Device (full HID) support
编译当前驱动,传入开发板并安装。
按下松开鼠标左键,现象如下: