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
#include
#include
#include
#include
#include
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 0
printk(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);
#endif
usbmouse = 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 0
input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
BIT_MASK(BTN_EXTRA);
#endif
if (!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);