114a21cd4SJiri Slaby /* 214a21cd4SJiri Slaby * HID driver for some a4tech "special" devices 314a21cd4SJiri Slaby * 414a21cd4SJiri Slaby * Copyright (c) 1999 Andreas Gal 514a21cd4SJiri Slaby * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 614a21cd4SJiri Slaby * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 714a21cd4SJiri Slaby * Copyright (c) 2006-2007 Jiri Kosina 814a21cd4SJiri Slaby * Copyright (c) 2007 Paul Walmsley 914a21cd4SJiri Slaby * Copyright (c) 2008 Jiri Slaby 1014a21cd4SJiri Slaby */ 1114a21cd4SJiri Slaby 1214a21cd4SJiri Slaby /* 1314a21cd4SJiri Slaby * This program is free software; you can redistribute it and/or modify it 1414a21cd4SJiri Slaby * under the terms of the GNU General Public License as published by the Free 1514a21cd4SJiri Slaby * Software Foundation; either version 2 of the License, or (at your option) 1614a21cd4SJiri Slaby * any later version. 1714a21cd4SJiri Slaby */ 1814a21cd4SJiri Slaby 1914a21cd4SJiri Slaby #include <linux/device.h> 2014a21cd4SJiri Slaby #include <linux/input.h> 2114a21cd4SJiri Slaby #include <linux/hid.h> 2214a21cd4SJiri Slaby #include <linux/module.h> 23*5a0e3ad6STejun Heo #include <linux/slab.h> 2414a21cd4SJiri Slaby 2514a21cd4SJiri Slaby #include "hid-ids.h" 2614a21cd4SJiri Slaby 2714a21cd4SJiri Slaby #define A4_2WHEEL_MOUSE_HACK_7 0x01 2814a21cd4SJiri Slaby #define A4_2WHEEL_MOUSE_HACK_B8 0x02 2914a21cd4SJiri Slaby 3014a21cd4SJiri Slaby struct a4tech_sc { 3114a21cd4SJiri Slaby unsigned long quirks; 3214a21cd4SJiri Slaby unsigned int hw_wheel; 3314a21cd4SJiri Slaby __s32 delayed_value; 3414a21cd4SJiri Slaby }; 3514a21cd4SJiri Slaby 3614a21cd4SJiri Slaby static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi, 3714a21cd4SJiri Slaby struct hid_field *field, struct hid_usage *usage, 3814a21cd4SJiri Slaby unsigned long **bit, int *max) 3914a21cd4SJiri Slaby { 4014a21cd4SJiri Slaby struct a4tech_sc *a4 = hid_get_drvdata(hdev); 4114a21cd4SJiri Slaby 4214a21cd4SJiri Slaby if (usage->type == EV_REL && usage->code == REL_WHEEL) 4314a21cd4SJiri Slaby set_bit(REL_HWHEEL, *bit); 4414a21cd4SJiri Slaby 4514a21cd4SJiri Slaby if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) 4614a21cd4SJiri Slaby return -1; 4714a21cd4SJiri Slaby 4814a21cd4SJiri Slaby return 0; 4914a21cd4SJiri Slaby } 5014a21cd4SJiri Slaby 5114a21cd4SJiri Slaby static int a4_event(struct hid_device *hdev, struct hid_field *field, 5214a21cd4SJiri Slaby struct hid_usage *usage, __s32 value) 5314a21cd4SJiri Slaby { 5414a21cd4SJiri Slaby struct a4tech_sc *a4 = hid_get_drvdata(hdev); 5514a21cd4SJiri Slaby struct input_dev *input; 5614a21cd4SJiri Slaby 5714a21cd4SJiri Slaby if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || 5814a21cd4SJiri Slaby !usage->type) 5914a21cd4SJiri Slaby return 0; 6014a21cd4SJiri Slaby 6114a21cd4SJiri Slaby input = field->hidinput->input; 6214a21cd4SJiri Slaby 6314a21cd4SJiri Slaby if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) { 6414a21cd4SJiri Slaby if (usage->type == EV_REL && usage->code == REL_WHEEL) { 6514a21cd4SJiri Slaby a4->delayed_value = value; 6614a21cd4SJiri Slaby return 1; 6714a21cd4SJiri Slaby } 6814a21cd4SJiri Slaby 6914a21cd4SJiri Slaby if (usage->hid == 0x000100b8) { 7014a21cd4SJiri Slaby input_event(input, EV_REL, value ? REL_HWHEEL : 7114a21cd4SJiri Slaby REL_WHEEL, a4->delayed_value); 7214a21cd4SJiri Slaby return 1; 7314a21cd4SJiri Slaby } 7414a21cd4SJiri Slaby } 7514a21cd4SJiri Slaby 7614a21cd4SJiri Slaby if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) { 7714a21cd4SJiri Slaby a4->hw_wheel = !!value; 7814a21cd4SJiri Slaby return 1; 7914a21cd4SJiri Slaby } 8014a21cd4SJiri Slaby 8114a21cd4SJiri Slaby if (usage->code == REL_WHEEL && a4->hw_wheel) { 8214a21cd4SJiri Slaby input_event(input, usage->type, REL_HWHEEL, value); 8314a21cd4SJiri Slaby return 1; 8414a21cd4SJiri Slaby } 8514a21cd4SJiri Slaby 8614a21cd4SJiri Slaby return 0; 8714a21cd4SJiri Slaby } 8814a21cd4SJiri Slaby 8914a21cd4SJiri Slaby static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id) 9014a21cd4SJiri Slaby { 9114a21cd4SJiri Slaby struct a4tech_sc *a4; 9214a21cd4SJiri Slaby int ret; 9314a21cd4SJiri Slaby 9414a21cd4SJiri Slaby a4 = kzalloc(sizeof(*a4), GFP_KERNEL); 9514a21cd4SJiri Slaby if (a4 == NULL) { 9614a21cd4SJiri Slaby dev_err(&hdev->dev, "can't alloc device descriptor\n"); 9714a21cd4SJiri Slaby ret = -ENOMEM; 9814a21cd4SJiri Slaby goto err_free; 9914a21cd4SJiri Slaby } 10014a21cd4SJiri Slaby 10114a21cd4SJiri Slaby a4->quirks = id->driver_data; 10214a21cd4SJiri Slaby 10314a21cd4SJiri Slaby hid_set_drvdata(hdev, a4); 10414a21cd4SJiri Slaby 10514a21cd4SJiri Slaby ret = hid_parse(hdev); 10614a21cd4SJiri Slaby if (ret) { 10714a21cd4SJiri Slaby dev_err(&hdev->dev, "parse failed\n"); 10814a21cd4SJiri Slaby goto err_free; 10914a21cd4SJiri Slaby } 11014a21cd4SJiri Slaby 11193c10132SJiri Slaby ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 11214a21cd4SJiri Slaby if (ret) { 11314a21cd4SJiri Slaby dev_err(&hdev->dev, "hw start failed\n"); 11414a21cd4SJiri Slaby goto err_free; 11514a21cd4SJiri Slaby } 11614a21cd4SJiri Slaby 11714a21cd4SJiri Slaby return 0; 11814a21cd4SJiri Slaby err_free: 11914a21cd4SJiri Slaby kfree(a4); 12014a21cd4SJiri Slaby return ret; 12114a21cd4SJiri Slaby } 12214a21cd4SJiri Slaby 12314a21cd4SJiri Slaby static void a4_remove(struct hid_device *hdev) 12414a21cd4SJiri Slaby { 12514a21cd4SJiri Slaby struct a4tech_sc *a4 = hid_get_drvdata(hdev); 12614a21cd4SJiri Slaby 12714a21cd4SJiri Slaby hid_hw_stop(hdev); 12814a21cd4SJiri Slaby kfree(a4); 12914a21cd4SJiri Slaby } 13014a21cd4SJiri Slaby 13114a21cd4SJiri Slaby static const struct hid_device_id a4_devices[] = { 13214a21cd4SJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU), 13314a21cd4SJiri Slaby .driver_data = A4_2WHEEL_MOUSE_HACK_7 }, 13414a21cd4SJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D), 13514a21cd4SJiri Slaby .driver_data = A4_2WHEEL_MOUSE_HACK_B8 }, 13614a21cd4SJiri Slaby { } 13714a21cd4SJiri Slaby }; 13814a21cd4SJiri Slaby MODULE_DEVICE_TABLE(hid, a4_devices); 13914a21cd4SJiri Slaby 14014a21cd4SJiri Slaby static struct hid_driver a4_driver = { 14114a21cd4SJiri Slaby .name = "a4tech", 14214a21cd4SJiri Slaby .id_table = a4_devices, 14314a21cd4SJiri Slaby .input_mapped = a4_input_mapped, 14414a21cd4SJiri Slaby .event = a4_event, 14514a21cd4SJiri Slaby .probe = a4_probe, 14614a21cd4SJiri Slaby .remove = a4_remove, 14714a21cd4SJiri Slaby }; 14814a21cd4SJiri Slaby 149a24f423bSPeter Huewe static int __init a4_init(void) 15014a21cd4SJiri Slaby { 15114a21cd4SJiri Slaby return hid_register_driver(&a4_driver); 15214a21cd4SJiri Slaby } 15314a21cd4SJiri Slaby 154a24f423bSPeter Huewe static void __exit a4_exit(void) 15514a21cd4SJiri Slaby { 15614a21cd4SJiri Slaby hid_unregister_driver(&a4_driver); 15714a21cd4SJiri Slaby } 15814a21cd4SJiri Slaby 15914a21cd4SJiri Slaby module_init(a4_init); 16014a21cd4SJiri Slaby module_exit(a4_exit); 16114a21cd4SJiri Slaby MODULE_LICENSE("GPL"); 162