1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/device.h>
27#include <linux/hid.h>
28#include <linux/module.h>
29#include "hid-ids.h"
30
31MODULE_AUTHOR("James McKenzie");
32MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
33MODULE_DESCRIPTION("HID Apple IR remote controls");
34MODULE_LICENSE("GPL");
35
36#define KEY_MASK 0x0F
37#define TWO_PACKETS_MASK 0x40
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95static const unsigned short appleir_key_table[] = {
96 KEY_RESERVED,
97 KEY_MENU,
98 KEY_PLAYPAUSE,
99 KEY_FORWARD,
100 KEY_BACK,
101 KEY_VOLUMEUP,
102 KEY_VOLUMEDOWN,
103 KEY_RESERVED,
104 KEY_RESERVED,
105 KEY_RESERVED,
106 KEY_RESERVED,
107 KEY_RESERVED,
108 KEY_RESERVED,
109 KEY_RESERVED,
110 KEY_ENTER,
111 KEY_PLAYPAUSE,
112 KEY_RESERVED,
113};
114
115struct appleir {
116 struct input_dev *input_dev;
117 struct hid_device *hid;
118 unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
119 struct timer_list key_up_timer;
120 spinlock_t lock;
121 int current_key;
122 int prev_key_idx;
123};
124
125static int get_key(int data)
126{
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 int key = (data >> 1) & KEY_MASK;
151
152 if ((data & TWO_PACKETS_MASK))
153
154 key = -key;
155
156 return key;
157}
158
159static void key_up(struct hid_device *hid, struct appleir *appleir, int key)
160{
161 input_report_key(appleir->input_dev, key, 0);
162 input_sync(appleir->input_dev);
163}
164
165static void key_down(struct hid_device *hid, struct appleir *appleir, int key)
166{
167 input_report_key(appleir->input_dev, key, 1);
168 input_sync(appleir->input_dev);
169}
170
171static void battery_flat(struct appleir *appleir)
172{
173 dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
174}
175
176static void key_up_tick(struct timer_list *t)
177{
178 struct appleir *appleir = from_timer(appleir, t, key_up_timer);
179 struct hid_device *hid = appleir->hid;
180 unsigned long flags;
181
182 spin_lock_irqsave(&appleir->lock, flags);
183 if (appleir->current_key) {
184 key_up(hid, appleir, appleir->current_key);
185 appleir->current_key = 0;
186 }
187 spin_unlock_irqrestore(&appleir->lock, flags);
188}
189
190static int appleir_raw_event(struct hid_device *hid, struct hid_report *report,
191 u8 *data, int len)
192{
193 struct appleir *appleir = hid_get_drvdata(hid);
194 static const u8 keydown[] = { 0x25, 0x87, 0xee };
195 static const u8 keyrepeat[] = { 0x26, };
196 static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
197 unsigned long flags;
198
199 if (len != 5)
200 goto out;
201
202 if (!memcmp(data, keydown, sizeof(keydown))) {
203 int index;
204
205 spin_lock_irqsave(&appleir->lock, flags);
206
207
208
209
210 if (appleir->current_key)
211 key_up(hid, appleir, appleir->current_key);
212
213
214 if (appleir->prev_key_idx > 0)
215 index = appleir->prev_key_idx;
216 else
217 index = get_key(data[4]);
218
219 if (index >= 0) {
220 appleir->current_key = appleir->keymap[index];
221
222 key_down(hid, appleir, appleir->current_key);
223
224
225
226
227
228 mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
229 appleir->prev_key_idx = 0;
230 } else
231
232 appleir->prev_key_idx = -index;
233 spin_unlock_irqrestore(&appleir->lock, flags);
234 goto out;
235 }
236
237 appleir->prev_key_idx = 0;
238
239 if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
240 key_down(hid, appleir, appleir->current_key);
241
242
243
244
245 mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
246 goto out;
247 }
248
249 if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
250 battery_flat(appleir);
251
252 }
253
254out:
255
256 return 0;
257}
258
259static int appleir_input_configured(struct hid_device *hid,
260 struct hid_input *hidinput)
261{
262 struct input_dev *input_dev = hidinput->input;
263 struct appleir *appleir = hid_get_drvdata(hid);
264 int i;
265
266 appleir->input_dev = input_dev;
267
268 input_dev->keycode = appleir->keymap;
269 input_dev->keycodesize = sizeof(unsigned short);
270 input_dev->keycodemax = ARRAY_SIZE(appleir->keymap);
271
272 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
273
274 memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap));
275 for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++)
276 set_bit(appleir->keymap[i], input_dev->keybit);
277 clear_bit(KEY_RESERVED, input_dev->keybit);
278
279 return 0;
280}
281
282static int appleir_input_mapping(struct hid_device *hid,
283 struct hid_input *hi, struct hid_field *field,
284 struct hid_usage *usage, unsigned long **bit, int *max)
285{
286 return -1;
287}
288
289static int appleir_probe(struct hid_device *hid, const struct hid_device_id *id)
290{
291 int ret;
292 struct appleir *appleir;
293
294 appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
295 if (!appleir) {
296 ret = -ENOMEM;
297 goto allocfail;
298 }
299
300 appleir->hid = hid;
301
302
303 hid->quirks |= HID_QUIRK_HIDINPUT_FORCE;
304
305 spin_lock_init(&appleir->lock);
306 timer_setup(&appleir->key_up_timer, key_up_tick, 0);
307
308 hid_set_drvdata(hid, appleir);
309
310 ret = hid_parse(hid);
311 if (ret) {
312 hid_err(hid, "parse failed\n");
313 goto fail;
314 }
315
316 ret = hid_hw_start(hid, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE);
317 if (ret) {
318 hid_err(hid, "hw start failed\n");
319 goto fail;
320 }
321
322 return 0;
323fail:
324 kfree(appleir);
325allocfail:
326 return ret;
327}
328
329static void appleir_remove(struct hid_device *hid)
330{
331 struct appleir *appleir = hid_get_drvdata(hid);
332 hid_hw_stop(hid);
333 del_timer_sync(&appleir->key_up_timer);
334 kfree(appleir);
335}
336
337static const struct hid_device_id appleir_devices[] = {
338 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
339 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
340 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
341 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
342 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
343 { }
344};
345MODULE_DEVICE_TABLE(hid, appleir_devices);
346
347static struct hid_driver appleir_driver = {
348 .name = "appleir",
349 .id_table = appleir_devices,
350 .raw_event = appleir_raw_event,
351 .input_configured = appleir_input_configured,
352 .probe = appleir_probe,
353 .remove = appleir_remove,
354 .input_mapping = appleir_input_mapping,
355};
356module_hid_driver(appleir_driver);
357