usb鼠标符合usb hid协议,
一般是单一功能(即一个usb 接口)
该接口下有一个默认的双向控制端点, 以及1个中断 in端点
bulk in端点读取数据定义: (具体定义需参考hid report描述符, https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/)
通常大部分usb鼠标数据描述如下:
BYTE1 --
|--bit7: 1 表示 Y 坐标的变化量超出-256~255的范围,0表示没有溢出
|--bit6: 1 表示 X 坐标的变化量超出-256~255的范围,0表示没有溢出
|--bit5: Y 坐标变化的符号位,1表示负数,即鼠标向下移动
|--bit4: X 坐标变化的符号位,1表示负数,即鼠标向左移动
|--bit3: 恒为1
|--bit2: 1表示中键按下
|--bit1: 1表示右键按下
|--bit0: 1表示左键按下
BYTE2 -- X坐标变化量,与byte的bit4组成9位符号数,负数表示向左移,正数表右移。用补码表示变化量
BYTE3 -- Y坐标变化量,与byte的bit5组成9位符号数,负数表示向下移,正数表上移。用补码表示变化量
BYTE4 -- 滚轮变化。
usb mouse驱动实现如下:
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/input.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("River");struct usbmouse_dev {struct input_dev *input;struct usb_device *usbdev;struct urb* urb;unsigned char *data;
};static struct usbmouse_dev *usbmouse = NULL;const struct usb_device_id usbmouse_ids[] = {{USB_DEVICE(0x0C45, 0x7c25)}, /* my usbmouse */{},
};static int usbmouse_info_open(struct input_dev *dev) {int status;struct usbmouse_dev *usbmouse = input_get_drvdata(dev);printk(KERN_INFO "usbmouse info open\n");status = usb_submit_urb(usbmouse->urb, GFP_KERNEL);if (status < 0) {printk(KERN_ERR "usb_submit_urb failed\n");goto submit_fail;}return 0;submit_fail:return status;
}static void usbmouse_info_close(struct input_dev *dev) {struct usbmouse_dev *usbmouse = input_get_drvdata(dev);printk(KERN_INFO "usbmouse info close\n");usb_kill_urb(usbmouse->urb);return;
}static void usbmouse_info_irq(struct urb *urb) {struct usbmouse_dev *usbmouse = urb->context;unsigned char *data = usbmouse->data;struct input_dev *dev = usbmouse->input;int status = 0;switch (urb->status) {case 0: /* success */break;case -ECONNRESET: /* unlink */case -ENOENT:case -ESHUTDOWN:return;/* -EPIPE: should clear the halt */default: /* error */goto resubmit;}/** byte 0, bits[0...2] (btn_left, btn_right, btn_middle)* byte 0, bits[4...7] (Device Specific)* byte 1, bits[0...7] (X dispalcement)* byte 2, bits[0...7] (Y dispalcement)* byte 3...n (Device Specific)*/input_report_key(dev, BTN_LEFT, data[0] & 0x1);input_report_key(dev, BTN_RIGHT, data[0] & 0x2);input_report_key(dev, BTN_MIDDLE, data[0] & 0x4);input_report_rel(dev, REL_X, data[1]);input_report_rel(dev, REL_Y, data[2]);/* report sync event */input_sync(dev);resubmit:status = usb_submit_urb(urb, GFP_KERNEL);if (status < 0) {printk(KERN_ERR "usb_submit_urb failed...\n");}
}static int usbmouse_info_probe(struct usb_interface *intf,const struct usb_device_id *id) {int ret = 0;struct usb_interface_descriptor *cur_desc;struct usb_endpoint_descriptor *ep0_desc;struct input_dev *input;struct urb *urb;struct usb_device *usbdev = interface_to_usbdev(intf);int pipe0, maxp;dev_info(&intf->dev, "usb mouse plug in!\n");printk(KERN_INFO "usb mouse detect! vid(0x%x), pid(0x%x)\n",id->idVendor, id->idProduct);cur_desc = &intf->cur_altsetting->desc;ep0_desc = &intf->cur_altsetting->endpoint->desc;if (!ep0_desc || !cur_desc) {printk(KERN_ERR "descriptor error...\n");ret = -EFAULT;goto desc_err;}#if 0printk(KERN_INFO "intf_desc: length(%d), desc_type(%d)\n"" intf_num(%d), alt_setting(%d)\n"" ep_num(%d), intf_class(%d)\n"" intf_subclass(%d), intf_protocol(%d)\n"" i_intf(%d)\n",cur_desc->bLength, cur_desc->bDescriptorType,cur_desc->bInterfaceNumber, cur_desc->bAlternateSetting,cur_desc->bNumEndpoints, cur_desc->bInterfaceClass,cur_desc->bInterfaceSubClass, cur_desc->bInterfaceProtocol,cur_desc->iInterface);
#endifusbmouse = kzalloc(sizeof(struct usbmouse_dev), GFP_KERNEL);if (!usbmouse) {printk(KERN_ERR "usbmouse_dev malloc failed\n");ret = -ENOMEM;goto malloc_fail1;}/* prepare urb */urb = usb_alloc_urb(0, GFP_KERNEL);if (!urb) {printk(KERN_ERR "usb allocate urb failed\n");ret = -EFAULT;goto urb_fail;}usbmouse->urb = urb;usbmouse->data = kzalloc(8, GFP_KERNEL);if (!usbmouse->data) {printk(KERN_ERR "alloc usb mouse data failed...\n");ret = -ENOMEM;goto malloc_fail2;}pipe0 = usb_rcvintpipe(usbdev, ep0_desc->bEndpointAddress);maxp = usb_maxpacket(usbdev, pipe0, 0);/* fill interrupt urb */usb_fill_int_urb(urb, usbdev, pipe0,usbmouse->data, maxp>8?8:maxp,usbmouse_info_irq, usbmouse, ep0_desc->bInterval);/* allocate an input dev */input = input_allocate_device();/* set bit mask *//* support EV_KEY & EV_REL event */input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);/* the usbmouse has left, right & middle button */input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);/* relative x & y */input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);/* the usbmouse has other key? */
#if 0input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |BIT_MASK(BTN_EXTRA);
#endifif (!input) {printk(KERN_ERR "input dev malloc failed\n");ret = -ENOMEM;goto malloc_fail3;}usbmouse->input = input;input_set_drvdata(input, usbmouse);input->open = usbmouse_info_open;input->close = usbmouse_info_close;/* register in input device subsystem */ret = input_register_device(input);if (ret < 0) {printk(KERN_ERR "input_register_device failed\n");goto reg_input_fail;}return 0;reg_input_fail:input_unregister_device(input);usbmouse->input = NULL;malloc_fail3:
malloc_fail2:kfree(usbmouse->data);urb_fail:kfree(usbmouse);malloc_fail1:
desc_err:return ret;
}static void usbmouse_info_remove(struct usb_interface *intf) {dev_info(&intf->dev, "usb mouse plug out!\n");if (usbmouse && usbmouse->input) {input_unregister_device(usbmouse->input);usbmouse->input = NULL;kfree(usbmouse);usbmouse = NULL;}return;
}static struct usb_driver usbmouse_info_driver = {.name = "usbmouse_info",.probe = usbmouse_info_probe,.disconnect = usbmouse_info_remove,.id_table = usbmouse_ids,
};static int __init usbmouse_info_init(void) {int ret = 0;ret = usb_register(&usbmouse_info_driver);if (ret < 0) {printk(KERN_ERR "usb_register failed\n");return ret;}printk(KERN_INFO "usbmouse_info_init succeed\n");return 0;
}static void __exit usbmouse_info_exit(void) {usb_deregister(&usbmouse_info_driver);printk(KERN_INFO "usbmouse_info_exit succeed\n");return;
}module_init(usbmouse_info_init);
module_exit(usbmouse_info_exit);