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