1 /* 2 * HID driver for some a4tech "special" devices 3 * 4 * Copyright (c) 1999 Andreas Gal 5 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 6 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 7 * Copyright (c) 2006-2007 Jiri Kosina 8 * Copyright (c) 2007 Paul Walmsley 9 * Copyright (c) 2008 Jiri Slaby 10 */ 11 12 /* 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU General Public License as published by the Free 15 * Software Foundation; either version 2 of the License, or (at your option) 16 * any later version. 17 */ 18 19 #include <linux/device.h> 20 #include <linux/input.h> 21 #include <linux/hid.h> 22 #include <linux/module.h> 23 24 #include "hid-ids.h" 25 26 #define A4_2WHEEL_MOUSE_HACK_7 0x01 27 #define A4_2WHEEL_MOUSE_HACK_B8 0x02 28 29 struct a4tech_sc { 30 unsigned long quirks; 31 unsigned int hw_wheel; 32 __s32 delayed_value; 33 }; 34 35 static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi, 36 struct hid_field *field, struct hid_usage *usage, 37 unsigned long **bit, int *max) 38 { 39 struct a4tech_sc *a4 = hid_get_drvdata(hdev); 40 41 if (usage->type == EV_REL && usage->code == REL_WHEEL) 42 set_bit(REL_HWHEEL, *bit); 43 44 if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) 45 return -1; 46 47 return 0; 48 } 49 50 static int a4_event(struct hid_device *hdev, struct hid_field *field, 51 struct hid_usage *usage, __s32 value) 52 { 53 struct a4tech_sc *a4 = hid_get_drvdata(hdev); 54 struct input_dev *input; 55 56 if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || 57 !usage->type) 58 return 0; 59 60 input = field->hidinput->input; 61 62 if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) { 63 if (usage->type == EV_REL && usage->code == REL_WHEEL) { 64 a4->delayed_value = value; 65 return 1; 66 } 67 68 if (usage->hid == 0x000100b8) { 69 input_event(input, EV_REL, value ? REL_HWHEEL : 70 REL_WHEEL, a4->delayed_value); 71 return 1; 72 } 73 } 74 75 if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) { 76 a4->hw_wheel = !!value; 77 return 1; 78 } 79 80 if (usage->code == REL_WHEEL && a4->hw_wheel) { 81 input_event(input, usage->type, REL_HWHEEL, value); 82 return 1; 83 } 84 85 return 0; 86 } 87 88 static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id) 89 { 90 struct a4tech_sc *a4; 91 int ret; 92 93 a4 = kzalloc(sizeof(*a4), GFP_KERNEL); 94 if (a4 == NULL) { 95 dev_err(&hdev->dev, "can't alloc device descriptor\n"); 96 ret = -ENOMEM; 97 goto err_free; 98 } 99 100 a4->quirks = id->driver_data; 101 102 hid_set_drvdata(hdev, a4); 103 104 ret = hid_parse(hdev); 105 if (ret) { 106 dev_err(&hdev->dev, "parse failed\n"); 107 goto err_free; 108 } 109 110 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 111 if (ret) { 112 dev_err(&hdev->dev, "hw start failed\n"); 113 goto err_free; 114 } 115 116 return 0; 117 err_free: 118 kfree(a4); 119 return ret; 120 } 121 122 static void a4_remove(struct hid_device *hdev) 123 { 124 struct a4tech_sc *a4 = hid_get_drvdata(hdev); 125 126 hid_hw_stop(hdev); 127 kfree(a4); 128 } 129 130 static const struct hid_device_id a4_devices[] = { 131 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU), 132 .driver_data = A4_2WHEEL_MOUSE_HACK_7 }, 133 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D), 134 .driver_data = A4_2WHEEL_MOUSE_HACK_B8 }, 135 { } 136 }; 137 MODULE_DEVICE_TABLE(hid, a4_devices); 138 139 static struct hid_driver a4_driver = { 140 .name = "a4tech", 141 .id_table = a4_devices, 142 .input_mapped = a4_input_mapped, 143 .event = a4_event, 144 .probe = a4_probe, 145 .remove = a4_remove, 146 }; 147 148 static int a4_init(void) 149 { 150 return hid_register_driver(&a4_driver); 151 } 152 153 static void a4_exit(void) 154 { 155 hid_unregister_driver(&a4_driver); 156 } 157 158 module_init(a4_init); 159 module_exit(a4_exit); 160 MODULE_LICENSE("GPL"); 161 162 HID_COMPAT_LOAD_DRIVER(a4tech); 163