usb hid驱动 - usb鼠标

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);

 

你可能感兴趣的:(USB)