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) 2008 Jiri Slaby 9 */ 10 11/* 12 * This program is free software; you can redistribute it and/or modify it 13 * under the terms of the GNU General Public License as published by the Free 14 * Software Foundation; either version 2 of the License, or (at your option) 15 * any later version. 16 */ 17 18#include <linux/device.h> 19#include <linux/input.h> 20#include <linux/hid.h> 21#include <linux/module.h> 22#include <linux/slab.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 29struct a4tech_sc { 30 unsigned long quirks; 31 unsigned int hw_wheel; 32 __s32 delayed_value; 33}; 34 35static 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 50static 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 88static 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 = devm_kzalloc(&hdev->dev, sizeof(*a4), GFP_KERNEL); 94 if (a4 == NULL) { 95 hid_err(hdev, "can't alloc device descriptor\n"); 96 return -ENOMEM; 97 } 98 99 a4->quirks = id->driver_data; 100 101 hid_set_drvdata(hdev, a4); 102 103 ret = hid_parse(hdev); 104 if (ret) { 105 hid_err(hdev, "parse failed\n"); 106 return ret; 107 } 108 109 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 110 if (ret) { 111 hid_err(hdev, "hw start failed\n"); 112 return ret; 113 } 114 115 return 0; 116} 117 118static const struct hid_device_id a4_devices[] = { 119 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU), 120 .driver_data = A4_2WHEEL_MOUSE_HACK_7 }, 121 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D), 122 .driver_data = A4_2WHEEL_MOUSE_HACK_B8 }, 123 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649), 124 .driver_data = A4_2WHEEL_MOUSE_HACK_B8 }, 125 { } 126}; 127MODULE_DEVICE_TABLE(hid, a4_devices); 128 129static struct hid_driver a4_driver = { 130 .name = "a4tech", 131 .id_table = a4_devices, 132 .input_mapped = a4_input_mapped, 133 .event = a4_event, 134 .probe = a4_probe, 135}; 136module_hid_driver(a4_driver); 137 138MODULE_LICENSE("GPL"); 139