Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/hid/hid-a4tech.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* HID driver for some a4tech "special" devices
4
*
5
* Copyright (c) 1999 Andreas Gal
6
* Copyright (c) 2000-2005 Vojtech Pavlik <[email protected]>
7
* Copyright (c) 2005 Michael Haboustak <[email protected]> for Concept2, Inc
8
* Copyright (c) 2006-2007 Jiri Kosina
9
* Copyright (c) 2008 Jiri Slaby
10
*/
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 0x01
24
#define A4_2WHEEL_MOUSE_HACK_B8 0x02
25
26
#define A4_WHEEL_ORIENTATION (HID_UP_GENDESK | 0x000000b8)
27
28
struct a4tech_sc {
29
unsigned long quirks;
30
unsigned int hw_wheel;
31
__s32 delayed_value;
32
};
33
34
static 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's
44
* nonstandard and doesn't really behave like an HID report.
45
* It's only selecting the orientation (vertical/horizontal) of
46
* the previous mouse wheel report. The input_events will be
47
* generated once both reports are recorded in a4_event().
48
*/
49
return -1;
50
}
51
52
return 0;
53
54
}
55
56
static 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
73
static 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
113
static 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
143
static 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
};
154
MODULE_DEVICE_TABLE(hid, a4_devices);
155
156
static 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
};
164
module_hid_driver(a4_driver);
165
166
MODULE_DESCRIPTION("HID driver for some a4tech \"special\" devices");
167
MODULE_LICENSE("GPL");
168
169