Created
August 29, 2022 05:02
-
-
Save pr0xy-t/c3a719bdfb184442989c3a84285562c9 to your computer and use it in GitHub Desktop.
Revisions
-
pr0xy-t created this gist
Aug 29, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,239 @@ #include<linux/kernel.h> #include<linux/slab.h> #include<linux/module.h> #include<linux/init.h> #include<linux/usb.h> #include<linux/usb/input.h> #include<asm/unaligned.h> #include<linux/limits.h> #define SPEED_RAITIO 10 static const struct usb_device_id devices[] = { { .idVendor = 0x056e, .idProduct = 0x011a, .bInterfaceNumber = 0, .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT | USB_DEVICE_ID_MATCH_INT_NUMBER }, {} }; static void report_handler(u8 *buf, struct input_dev *input) { input_report_key(input, BTN_LEFT, buf[0] & 0x01); input_report_key(input, BTN_RIGHT, buf[0]& 0x02); input_report_key(input, BTN_MIDDLE, buf[0]& 0x04); input_report_key(input, BTN_SIDE, buf[0]& 0x08); input_report_key(input, BTN_EXTRA, buf[0]& 0x10); if(buf[2] & 0x0f){ // move left input_report_rel(input, REL_X, (s8)(buf[1])); }else{ // move right input_report_rel(input, REL_X, buf[1]); } if(buf[3] == 0xff){ // move up input_report_rel(input, REL_Y, (s8)(0x100 - ((0x100 - buf[2])>>4) )); }else{ // move down input_report_rel(input, REL_Y, (buf[2]>>4)); } if(buf[4] == 0xff){ // wheel down input_report_rel(input, REL_WHEEL, (s8)(buf[4] * SPEED_RAITIO) ); }else if(buf[4] == 0x01){ // wheel up input_report_rel(input, REL_WHEEL, buf[4] * SPEED_RAITIO); } input_sync(input); } static void urb_complete(struct urb *urb) { switch (urb->status) { case 0: report_handler(urb->transfer_buffer, urb->context); usb_submit_urb(urb, GFP_ATOMIC); return; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: printk("[speed_mouse] urb shutting down with %d\n", urb->status); return; default: printk("[speed_mouse] urb status %d received\n", urb->status); usb_submit_urb(urb, GFP_ATOMIC); return; } } static int input_open(struct input_dev *input) { struct urb *urb = input_get_drvdata(input); return usb_submit_urb(urb, GFP_KERNEL); } static void input_close(struct input_dev *input) { struct urb *urb = input_get_drvdata(input); usb_kill_urb(urb); } static void setup_input_dev(struct input_dev *input, struct usb_interface *intf, char *phys) { input->name = "Scroll speed xN for Elecom mouse"; input->phys = phys; input->open = input_open; input->close = input_close; input->dev.parent = &intf->dev; usb_to_input_id(interface_to_usbdev(intf), &input->id); input_set_capability(input, EV_KEY, BTN_LEFT); input_set_capability(input, EV_KEY, BTN_RIGHT); input_set_capability(input, EV_KEY, BTN_MIDDLE); input_set_capability(input, EV_KEY, BTN_SIDE); input_set_capability(input, EV_KEY, BTN_EXTRA); input_set_capability(input, EV_REL, REL_X); input_set_capability(input, EV_REL, REL_Y); input_set_capability(input, EV_REL, REL_WHEEL); } static int dev_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct usb_endpoint_descriptor *epd = &intf->cur_altsetting->endpoint[0].desc; unsigned int pipe = usb_rcvintpipe(dev, epd->bEndpointAddress); struct urb *urb; void *buf; dma_addr_t dma; int res; struct input_dev *input; char *phys; printk("[speed_mouse] probe\n"); printk("[speed_mouse] idVendor=0x%04x\n", dev->descriptor.idVendor); printk("[speed_mouse] idProduct=0x%04x\n", dev->descriptor.idProduct); printk("[speed_mouse] bInterfaceNumber=%d\n", intf->cur_altsetting->desc.bInterfaceNumber); printk("[speed_mouse] bEndpointAddress=0x%02x\n", epd->bEndpointAddress); printk("[speed_mouse] wMaxPacketSize=%d\n", epd->wMaxPacketSize); printk("[speed_mouse] bInternal=%d\n", epd->bInterval); urb = usb_alloc_urb(0, GFP_KERNEL); if(urb == NULL){ printk("[speed_mouse] usb_alloc_urb() failed\n"); res = -ENOMEM; goto failed0; } usb_set_intfdata(intf, urb); buf = usb_alloc_coherent(dev, epd->wMaxPacketSize, GFP_KERNEL, &dma); if(buf == NULL){ printk("[speed_mouse] usb_alloc_coherent() failed\n"); res = -ENOMEM; goto failed1; } usb_fill_int_urb(urb, dev, pipe, buf, epd->wMaxPacketSize, urb_complete, NULL, epd->bInterval); urb->transfer_dma = dma; urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; input = devm_input_allocate_device(&intf->dev); if (input == NULL) { printk("[speed_mouse] devm_input_allocate_device() failed.\n"); res = -ENOMEM; goto failed2; } input_set_drvdata(input, urb); phys = kmalloc(PATH_MAX, GFP_KERNEL); if (phys == NULL) { printk("[speed_mouse] kmalloc() failed\n"); res = -ENOMEM; goto failed2; } usb_make_path(dev, phys, PATH_MAX); strlcat(phys, "/input0", PATH_MAX); setup_input_dev(input, intf, phys); urb->context = input; res = input_register_device(input); if (res) { printk("[speed_mouse] input_register_device() failed\n"); goto failed3; } return 0; failed3: kfree(phys); failed2: usb_free_coherent(dev, epd->wMaxPacketSize, buf, dma); failed1: usb_free_urb(urb); failed0: usb_set_intfdata(intf, NULL); return res; } static void dev_disconnect(struct usb_interface *intf) { struct urb *urb = usb_get_intfdata(intf); if (urb) { usb_kill_urb(urb); usb_free_coherent( urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); usb_free_urb(urb); } printk("[speed_mouse] disconnect\n"); } static struct usb_driver driver = { .name = "Scroll speed xN for Elecom mouse", .id_table = devices, .probe = dev_probe, .disconnect = dev_disconnect, }; static int __init mod_init(void) { int ret; printk("[speed_mouse] init\n"); ret = usb_register(&driver); if(ret){ printk("[speed_mouse] usb_register() failed\n"); return ret; } return 0; } static void __exit mod_exit(void) { printk("[speed_mouse] exit\n"); usb_deregister(&driver); } module_init(mod_init); module_exit(mod_exit); MODULE_DEVICE_TABLE(usb ,devices); MODULE_LICENSE("GPL"); MODULE_AUTHOR("pr0xy"); MODULE_DESCRIPTION("Scroll speed xN for Elecom mouse");