Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/hid/hid-a4tech.c
15111 views
1
/*
2
* HID driver for some a4tech "special" devices
3
*
4
* Copyright (c) 1999 Andreas Gal
5
* Copyright (c) 2000-2005 Vojtech Pavlik <[email protected]>
6
* Copyright (c) 2005 Michael Haboustak <[email protected]> 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
#include <linux/slab.h>
24
25
#include "hid-ids.h"
26
27
#define A4_2WHEEL_MOUSE_HACK_7 0x01
28
#define A4_2WHEEL_MOUSE_HACK_B8 0x02
29
30
struct a4tech_sc {
31
unsigned long quirks;
32
unsigned int hw_wheel;
33
__s32 delayed_value;
34
};
35
36
static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
37
struct hid_field *field, struct hid_usage *usage,
38
unsigned long **bit, int *max)
39
{
40
struct a4tech_sc *a4 = hid_get_drvdata(hdev);
41
42
if (usage->type == EV_REL && usage->code == REL_WHEEL)
43
set_bit(REL_HWHEEL, *bit);
44
45
if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007)
46
return -1;
47
48
return 0;
49
}
50
51
static int a4_event(struct hid_device *hdev, struct hid_field *field,
52
struct hid_usage *usage, __s32 value)
53
{
54
struct a4tech_sc *a4 = hid_get_drvdata(hdev);
55
struct input_dev *input;
56
57
if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
58
!usage->type)
59
return 0;
60
61
input = field->hidinput->input;
62
63
if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) {
64
if (usage->type == EV_REL && usage->code == REL_WHEEL) {
65
a4->delayed_value = value;
66
return 1;
67
}
68
69
if (usage->hid == 0x000100b8) {
70
input_event(input, EV_REL, value ? REL_HWHEEL :
71
REL_WHEEL, a4->delayed_value);
72
return 1;
73
}
74
}
75
76
if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) {
77
a4->hw_wheel = !!value;
78
return 1;
79
}
80
81
if (usage->code == REL_WHEEL && a4->hw_wheel) {
82
input_event(input, usage->type, REL_HWHEEL, value);
83
return 1;
84
}
85
86
return 0;
87
}
88
89
static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
90
{
91
struct a4tech_sc *a4;
92
int ret;
93
94
a4 = kzalloc(sizeof(*a4), GFP_KERNEL);
95
if (a4 == NULL) {
96
hid_err(hdev, "can't alloc device descriptor\n");
97
ret = -ENOMEM;
98
goto err_free;
99
}
100
101
a4->quirks = id->driver_data;
102
103
hid_set_drvdata(hdev, a4);
104
105
ret = hid_parse(hdev);
106
if (ret) {
107
hid_err(hdev, "parse failed\n");
108
goto err_free;
109
}
110
111
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
112
if (ret) {
113
hid_err(hdev, "hw start failed\n");
114
goto err_free;
115
}
116
117
return 0;
118
err_free:
119
kfree(a4);
120
return ret;
121
}
122
123
static void a4_remove(struct hid_device *hdev)
124
{
125
struct a4tech_sc *a4 = hid_get_drvdata(hdev);
126
127
hid_hw_stop(hdev);
128
kfree(a4);
129
}
130
131
static const struct hid_device_id a4_devices[] = {
132
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU),
133
.driver_data = A4_2WHEEL_MOUSE_HACK_7 },
134
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D),
135
.driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
136
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649),
137
.driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
138
{ }
139
};
140
MODULE_DEVICE_TABLE(hid, a4_devices);
141
142
static struct hid_driver a4_driver = {
143
.name = "a4tech",
144
.id_table = a4_devices,
145
.input_mapped = a4_input_mapped,
146
.event = a4_event,
147
.probe = a4_probe,
148
.remove = a4_remove,
149
};
150
151
static int __init a4_init(void)
152
{
153
return hid_register_driver(&a4_driver);
154
}
155
156
static void __exit a4_exit(void)
157
{
158
hid_unregister_driver(&a4_driver);
159
}
160
161
module_init(a4_init);
162
module_exit(a4_exit);
163
MODULE_LICENSE("GPL");
164
165