168 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * HID driver for some a4tech "special" devices4 *5 * Copyright (c) 1999 Andreas Gal6 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>7 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc8 * Copyright (c) 2006-2007 Jiri Kosina9 * Copyright (c) 2008 Jiri Slaby10 */11 12/*13 */14 15#include <linux/device.h>16#include <linux/input.h>17#include <linux/hid.h>18#include <linux/module.h>19#include <linux/slab.h>20 21#include "hid-ids.h"22 23#define A4_2WHEEL_MOUSE_HACK_7 0x0124#define A4_2WHEEL_MOUSE_HACK_B8 0x0225 26#define A4_WHEEL_ORIENTATION (HID_UP_GENDESK | 0x000000b8)27 28struct a4tech_sc {29 unsigned long quirks;30 unsigned int hw_wheel;31 __s32 delayed_value;32};33 34static int a4_input_mapping(struct hid_device *hdev, struct hid_input *hi,35 struct hid_field *field, struct hid_usage *usage,36 unsigned long **bit, int *max)37{38 struct a4tech_sc *a4 = hid_get_drvdata(hdev);39 40 if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8 &&41 usage->hid == A4_WHEEL_ORIENTATION) {42 /*43 * We do not want to have this usage mapped to anything as it's44 * nonstandard and doesn't really behave like an HID report.45 * It's only selecting the orientation (vertical/horizontal) of46 * the previous mouse wheel report. The input_events will be47 * generated once both reports are recorded in a4_event().48 */49 return -1;50 }51 52 return 0;53 54}55 56static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,57 struct hid_field *field, struct hid_usage *usage,58 unsigned long **bit, int *max)59{60 struct a4tech_sc *a4 = hid_get_drvdata(hdev);61 62 if (usage->type == EV_REL && usage->code == REL_WHEEL_HI_RES) {63 set_bit(REL_HWHEEL, *bit);64 set_bit(REL_HWHEEL_HI_RES, *bit);65 }66 67 if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007)68 return -1;69 70 return 0;71}72 73static int a4_event(struct hid_device *hdev, struct hid_field *field,74 struct hid_usage *usage, __s32 value)75{76 struct a4tech_sc *a4 = hid_get_drvdata(hdev);77 struct input_dev *input;78 79 if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput)80 return 0;81 82 input = field->hidinput->input;83 84 if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) {85 if (usage->type == EV_REL && usage->code == REL_WHEEL_HI_RES) {86 a4->delayed_value = value;87 return 1;88 }89 90 if (usage->hid == A4_WHEEL_ORIENTATION) {91 input_event(input, EV_REL, value ? REL_HWHEEL :92 REL_WHEEL, a4->delayed_value);93 input_event(input, EV_REL, value ? REL_HWHEEL_HI_RES :94 REL_WHEEL_HI_RES, a4->delayed_value * 120);95 return 1;96 }97 }98 99 if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) {100 a4->hw_wheel = !!value;101 return 1;102 }103 104 if (usage->code == REL_WHEEL_HI_RES && a4->hw_wheel) {105 input_event(input, usage->type, REL_HWHEEL, value);106 input_event(input, usage->type, REL_HWHEEL_HI_RES, value * 120);107 return 1;108 }109 110 return 0;111}112 113static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)114{115 struct a4tech_sc *a4;116 int ret;117 118 a4 = devm_kzalloc(&hdev->dev, sizeof(*a4), GFP_KERNEL);119 if (a4 == NULL) {120 hid_err(hdev, "can't alloc device descriptor\n");121 return -ENOMEM;122 }123 124 a4->quirks = id->driver_data;125 126 hid_set_drvdata(hdev, a4);127 128 ret = hid_parse(hdev);129 if (ret) {130 hid_err(hdev, "parse failed\n");131 return ret;132 }133 134 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);135 if (ret) {136 hid_err(hdev, "hw start failed\n");137 return ret;138 }139 140 return 0;141}142 143static const struct hid_device_id a4_devices[] = {144 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU),145 .driver_data = A4_2WHEEL_MOUSE_HACK_7 },146 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D),147 .driver_data = A4_2WHEEL_MOUSE_HACK_B8 },148 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649),149 .driver_data = A4_2WHEEL_MOUSE_HACK_B8 },150 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_NB_95),151 .driver_data = A4_2WHEEL_MOUSE_HACK_B8 },152 { }153};154MODULE_DEVICE_TABLE(hid, a4_devices);155 156static struct hid_driver a4_driver = {157 .name = "a4tech",158 .id_table = a4_devices,159 .input_mapping = a4_input_mapping,160 .input_mapped = a4_input_mapped,161 .event = a4_event,162 .probe = a4_probe,163};164module_hid_driver(a4_driver);165 166MODULE_DESCRIPTION("HID driver for some a4tech \"special\" devices");167MODULE_LICENSE("GPL");168