shifter.c (4847B)
1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/usb.h> 4 #include <linux/hid.h> 5 #include <linux/input.h> 6 #include <linux/slab.h> 7 #include <linux/interrupt.h> 8 9 #define DEVICE_VENDOR_ID 0x1020 10 #define DEVICE_PRODUCT_ID 0x8863 11 #define DEVICE_NAME "ODOR-TRUCKSHIFT" 12 13 static struct usb_device_id usb_device_table[] = { 14 { USB_DEVICE(DEVICE_VENDOR_ID, DEVICE_PRODUCT_ID) }, 15 {} 16 }; 17 MODULE_DEVICE_TABLE(usb, usb_device_table); 18 19 struct truckshifter { 20 struct usb_device *udev; 21 struct input_dev *input_device; 22 unsigned char *input_buffer; 23 }; 24 25 static void parse_hid_report(struct truckshifter *truckshifter, unsigned char *data) { 26 unsigned char button_data = data[0]; 27 28 if (button_data & 0x01) { 29 input_event(truckshifter->input_device, EV_KEY, BTN_A, 1); 30 } else { 31 input_event(truckshifter->input_device, EV_KEY, BTN_A, 0); 32 } 33 34 if (button_data & 0x02) { 35 input_event(truckshifter->input_device, EV_KEY, BTN_B, 1); 36 } else { 37 input_event(truckshifter->input_device, EV_KEY, BTN_B, 0); 38 } 39 40 if (button_data & 0x04) { 41 input_event(truckshifter->input_device, EV_KEY, BTN_X, 1); 42 } else { 43 input_event(truckshifter->input_device, EV_KEY, BTN_X, 0); 44 } 45 46 input_sync(truckshifter->input_device); 47 } 48 49 static void read_hid_report(struct urb *urb) { 50 struct truckshifter *truckshifter = urb->context; 51 52 if (urb->status) { 53 printk(KERN_ERR "USB HID report error: %d\n", urb->status); 54 return; 55 } 56 57 parse_hid_report(truckshifter, urb->transfer_buffer); 58 59 int retval = usb_submit_urb(urb, GFP_KERNEL); 60 if (retval) { 61 printk(KERN_ERR "Failed to resubmit URB\n"); 62 } 63 } 64 65 static int start_reading_hid_report(struct truckshifter *truckshifter) { 66 struct usb_interface *interface = truckshifter->udev->actconfig->interface[0]; 67 struct usb_endpoint_descriptor *endpoint; 68 struct urb *urb; 69 int pipe; 70 int max_packet_size; 71 72 endpoint = &interface->cur_altsetting->endpoint[0].desc; 73 pipe = usb_rcvintpipe(truckshifter->udev, endpoint->bEndpointAddress); 74 max_packet_size = usb_endpoint_maxp(endpoint); 75 76 urb = usb_alloc_urb(0, GFP_KERNEL); 77 if (!urb) { 78 printk(KERN_ERR "Failed to allocate URB\n"); 79 return -ENOMEM; 80 } 81 82 truckshifter->input_buffer = kmalloc(max_packet_size, GFP_KERNEL); 83 if (!truckshifter->input_buffer) { 84 printk(KERN_ERR "Failed to allocate buffer\n"); 85 usb_free_urb(urb); 86 return -ENOMEM; 87 } 88 89 usb_fill_int_urb(urb, truckshifter->udev, pipe, truckshifter->input_buffer, max_packet_size, 90 read_hid_report, truckshifter, endpoint->bInterval); 91 92 return usb_submit_urb(urb, GFP_KERNEL); 93 } 94 95 static int usb_driver_probe(struct usb_interface *interface, const struct usb_device_id *id) { 96 struct truckshifter *truckshifter; 97 struct usb_device *dev = interface_to_usbdev(interface); 98 struct input_dev *input_device; 99 int retval; 100 101 truckshifter = kzalloc(sizeof(struct truckshifter), GFP_KERNEL); 102 if (!truckshifter) { 103 printk(KERN_ERR "Failed to allocate memory for HID device\n"); 104 return -ENOMEM; 105 } 106 107 truckshifter->udev = dev; 108 109 input_device = input_allocate_device(); 110 if (!input_device) { 111 printk(KERN_ERR "Failed to allocate input device\n"); 112 kfree(truckshifter); 113 return -ENOMEM; 114 } 115 116 truckshifter->input_device = input_device; 117 118 input_device->name = DEVICE_NAME; 119 input_device->evbit[0] = BIT_MASK(EV_KEY); 120 input_device->keybit[BIT_WORD(BTN_A)] |= BIT_MASK(BTN_A); 121 input_device->keybit[BIT_WORD(BTN_B)] |= BIT_MASK(BTN_B); 122 input_device->keybit[BIT_WORD(BTN_X)] |= BIT_MASK(BTN_X); 123 124 retval = input_register_device(input_device); 125 if (retval) { 126 printk(KERN_ERR "Failed to register "DEVICE_NAME" \n"); 127 input_free_device(input_device); 128 kfree(truckshifter); 129 return retval; 130 } 131 132 retval = start_reading_hid_report(truckshifter); 133 if (retval) { 134 printk(KERN_ERR "Failed to start reading HID report\n"); 135 input_unregister_device(input_device); 136 kfree(truckshifter); 137 return retval; 138 } 139 140 usb_set_intfdata(interface, truckshifter); 141 142 printk(KERN_INFO DEVICE_NAME" connected\n"); 143 return 0; 144 } 145 146 static void usb_driver_disconnect(struct usb_interface *interface) { 147 struct truckshifter *hid_device = usb_get_intfdata(interface); 148 149 if (hid_device) { 150 if (hid_device->input_buffer) 151 kfree(hid_device->input_buffer); 152 input_unregister_device(hid_device->input_device); 153 kfree(hid_device); 154 } 155 156 printk(KERN_INFO DEVICE_NAME" disconnected\n"); 157 } 158 159 static struct usb_driver custom_hid_driver = { 160 .name = DEVICE_NAME, 161 .id_table = usb_device_table, 162 .probe = usb_driver_probe, 163 .disconnect = usb_driver_disconnect, 164 }; 165 166 static int __init usb_driver_init(void) { 167 return usb_register(&custom_hid_driver); 168 } 169 170 static void __exit usb_driver_exit(void) { 171 usb_deregister(&custom_hid_driver); 172 } 173 174 module_init(usb_driver_init); 175 module_exit(usb_driver_exit); 176 177 MODULE_LICENSE("GPL"); 178 MODULE_AUTHOR("Jake Koroman <jakekoroman@proton.me>"); 179 MODULE_DESCRIPTION("Driver for the Labtec ODDOR-TRUCKSHIFT usb truck shifter");