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(unsigned long data)
177{
178 struct appleir *appleir = (struct appleir *)data;
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 void 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
280static int appleir_input_mapping(struct hid_device *hid,
281 struct hid_input *hi, struct hid_field *field,
282 struct hid_usage *usage, unsigned long **bit, int *max)
283{
284 return -1;
285}
286
287static int appleir_probe(struct hid_device *hid, const struct hid_device_id *id)
288{
289 int ret;
290 struct appleir *appleir;
291
292 appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
293 if (!appleir) {
294 ret = -ENOMEM;
295 goto allocfail;
296 }
297
298 appleir->hid = hid;
299
300 spin_lock_init(&appleir->lock);
301 setup_timer(&appleir->key_up_timer,
302 key_up_tick, (unsigned long) appleir);
303
304 hid_set_drvdata(hid, appleir);
305
306 ret = hid_parse(hid);
307 if (ret) {
308 hid_err(hid, "parse failed\n");
309 goto fail;
310 }
311
312 ret = hid_hw_start(hid, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE);
313 if (ret) {
314 hid_err(hid, "hw start failed\n");
315 goto fail;
316 }
317
318 return 0;
319fail:
320 kfree(appleir);
321allocfail:
322 return ret;
323}
324
325static void appleir_remove(struct hid_device *hid)
326{
327 struct appleir *appleir = hid_get_drvdata(hid);
328 hid_hw_stop(hid);
329 del_timer_sync(&appleir->key_up_timer);
330 kfree(appleir);
331}
332
333static const struct hid_device_id appleir_devices[] = {
334 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
335 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
336 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
337 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
338 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
339 { }
340};
341MODULE_DEVICE_TABLE(hid, appleir_devices);
342
343static struct hid_driver appleir_driver = {
344 .name = "appleir",
345 .id_table = appleir_devices,
346 .raw_event = appleir_raw_event,
347 .input_configured = appleir_input_configured,
348 .probe = appleir_probe,
349 .remove = appleir_remove,
350 .input_mapping = appleir_input_mapping,
351};
352module_hid_driver(appleir_driver);
353