diff options
author | Ralf Ertzinger <rockbox@camperquake.de> | 2013-06-22 10:08:23 +0100 |
---|---|---|
committer | Frank Gevaerts <frank@gevaerts.be> | 2013-11-10 18:41:24 +0100 |
commit | b170c73f922e3457b923b4e7fcbec794a8885c77 (patch) | |
tree | 89fbdbd8c25af5101a29a1ede3b896332a4e205c /apps/iap/iap-lingo0.c | |
parent | 500b137308a6ee5c2aba873734a8956d70472f56 (diff) | |
download | rockbox-b170c73f922e3457b923b4e7fcbec794a8885c77.tar.gz rockbox-b170c73f922e3457b923b4e7fcbec794a8885c77.zip |
Updated IAP commands.
Originally written and uploaded by Lalufu (Ralf Ertzinger) in Feb 2012.
They have been condensed into a single patch and some further additions
by Andy Potter.
Currently includes Authentication V2 support from iPod to Accessory,
RF/BlueTooth transmitter support, selecting a playlist and selecting a
track from the current playlist. Does not support uploading Album Art
or podcasts. Has been tested on the following iPods,
4th Gen Grayscale, 4th Gen Color/Photo, Mini 2nd Gen, Nano 1st Gen and
Video 5.5Gen.
Change-Id: Ie8fc098361844132f0228ecbe3c48da948726f5e
Co-Authored by: Andy Potter <liveboxandy@gmail.com>
Reviewed-on: http://gerrit.rockbox.org/533
Reviewed-by: Frank Gevaerts <frank@gevaerts.be>
Diffstat (limited to 'apps/iap/iap-lingo0.c')
-rw-r--r-- | apps/iap/iap-lingo0.c | 1035 |
1 files changed, 1035 insertions, 0 deletions
diff --git a/apps/iap/iap-lingo0.c b/apps/iap/iap-lingo0.c new file mode 100644 index 0000000000..9e0355cb3f --- /dev/null +++ b/apps/iap/iap-lingo0.c | |||
@@ -0,0 +1,1035 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Alan Korr & Nick Robinson | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "iap-core.h" | ||
21 | #include "iap-lingo.h" | ||
22 | #include "kernel.h" | ||
23 | #include "system.h" | ||
24 | |||
25 | /* | ||
26 | * This macro is meant to be used inside an IAP mode message handler. | ||
27 | * It is passed the expected minimum length of the message buffer. | ||
28 | * If the buffer does not have the required lenght an ACK | ||
29 | * packet with a Bad Parameter error is generated. | ||
30 | */ | ||
31 | #define CHECKLEN(x) do { \ | ||
32 | if (len < (x)) { \ | ||
33 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); \ | ||
34 | return; \ | ||
35 | }} while(0) | ||
36 | |||
37 | /* Check for authenticated state, and return an ACK Not | ||
38 | * Authenticated on failure. | ||
39 | */ | ||
40 | #define CHECKAUTH do { \ | ||
41 | if (!DEVICE_AUTHENTICATED) { \ | ||
42 | cmd_ack(cmd, IAP_ACK_NO_AUTHEN); \ | ||
43 | return; \ | ||
44 | }} while(0) | ||
45 | |||
46 | static void cmd_ack(const unsigned char cmd, const unsigned char status) | ||
47 | { | ||
48 | IAP_TX_INIT(0x00, 0x02); | ||
49 | IAP_TX_PUT(status); | ||
50 | IAP_TX_PUT(cmd); | ||
51 | iap_send_tx(); | ||
52 | } | ||
53 | |||
54 | #define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK) | ||
55 | |||
56 | static void cmd_pending(const unsigned char cmd, const uint32_t msdelay) | ||
57 | { | ||
58 | IAP_TX_INIT(0x00, 0x02); | ||
59 | IAP_TX_PUT(0x06); | ||
60 | IAP_TX_PUT(cmd); | ||
61 | IAP_TX_PUT_U32(msdelay); | ||
62 | iap_send_tx(); | ||
63 | } | ||
64 | |||
65 | void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf) | ||
66 | { | ||
67 | unsigned int cmd = buf[1]; | ||
68 | |||
69 | /* We expect at least two bytes in the buffer, one for the | ||
70 | * lingo, one for the command | ||
71 | */ | ||
72 | CHECKLEN(2); | ||
73 | |||
74 | switch (cmd) { | ||
75 | /* RequestIdentify (0x00) | ||
76 | * | ||
77 | * Sent from the iPod to the device | ||
78 | */ | ||
79 | |||
80 | /* Identify (0x01) | ||
81 | * This command is deprecated. | ||
82 | * | ||
83 | * It is used by a device to inform the iPod of the devices | ||
84 | * presence and of the lingo the device supports. | ||
85 | * | ||
86 | * Also, it is used to negotiate power for RF transmitters | ||
87 | * | ||
88 | * Packet format (offset in buf[]: Description) | ||
89 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
90 | * 0x01: Command, always 0x01 | ||
91 | * 0x02: Lingo supported by the device | ||
92 | * | ||
93 | * Some RF transmitters use an extended version of this | ||
94 | * command: | ||
95 | * | ||
96 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
97 | * 0x01: Command, always 0x01 | ||
98 | * 0x02: Lingo supported by the device, always 0x05 (RF Transmitter) | ||
99 | * 0x03: Reserved, always 0x00 | ||
100 | * 0x04: Number of valid bits in the following fields | ||
101 | * 0x05-N: Datafields holding the number of bits specified in 0x04 | ||
102 | * | ||
103 | * Returns: (none) | ||
104 | * | ||
105 | * TODO: | ||
106 | * BeginHighPower/EndHighPower should be send in the periodic handler, | ||
107 | * depending on the current play status | ||
108 | */ | ||
109 | case 0x01: | ||
110 | { | ||
111 | unsigned char lingo = buf[2]; | ||
112 | |||
113 | /* This is sufficient even for Lingo 0x05, as we are | ||
114 | * not actually reading from the extended bits for now | ||
115 | */ | ||
116 | CHECKLEN(3); | ||
117 | |||
118 | /* Issuing this command exits any extended interface states | ||
119 | * and resets authentication | ||
120 | */ | ||
121 | iap_interface_state_change(IST_STANDARD); | ||
122 | iap_reset_device(&device); | ||
123 | |||
124 | switch (lingo) { | ||
125 | case 0x04: | ||
126 | { | ||
127 | /* A single lingo device negotiating the | ||
128 | * extended interface lingo. This causes an interface | ||
129 | * state change. | ||
130 | */ | ||
131 | iap_interface_state_change(IST_EXTENDED); | ||
132 | break; | ||
133 | } | ||
134 | |||
135 | case 0x05: | ||
136 | { | ||
137 | /* FM transmitter sends this: */ | ||
138 | /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */ | ||
139 | sleep(HZ/3); | ||
140 | /* RF Transmitter: Begin transmission */ | ||
141 | IAP_TX_INIT(0x05, 0x02); | ||
142 | |||
143 | iap_send_tx(); | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | if (lingo < 32) { | ||
149 | /* All devices that Identify get access to Lingoes 0x00 and 0x02 */ | ||
150 | device.lingoes = BIT_N(0x00) | BIT_N(0x02); | ||
151 | |||
152 | device.lingoes |= BIT_N(lingo); | ||
153 | |||
154 | /* Devices that Identify with Lingo 0x04 also gain access | ||
155 | * to Lingo 0x03 | ||
156 | */ | ||
157 | if (lingo == 0x04) | ||
158 | device.lingoes |= BIT_N(0x03); | ||
159 | } else { | ||
160 | device.lingoes = 0; | ||
161 | } | ||
162 | break; | ||
163 | } | ||
164 | |||
165 | /* ACK (0x02) | ||
166 | * | ||
167 | * Sent from the iPod to the device | ||
168 | */ | ||
169 | |||
170 | /* RequestRemoteUIMode (0x03) | ||
171 | * | ||
172 | * Request the current Extended Interface Mode state | ||
173 | * This command may be used only if the accessory requests Lingo 0x04 | ||
174 | * during its identification process. | ||
175 | * | ||
176 | * Packet format (offset in buf[]: Description) | ||
177 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
178 | * 0x01: Command, always 0x03 | ||
179 | * | ||
180 | * Returns on success: | ||
181 | * ReturnRemoteUIMode | ||
182 | * | ||
183 | * Packet format (offset in data[]: Description) | ||
184 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
185 | * 0x01: Command, always 0x04 | ||
186 | * 0x02: Current Extended Interface Mode (zero: false, non-zero: true) | ||
187 | * | ||
188 | * Returns on failure: | ||
189 | * IAP_ACK_BAD_PARAM | ||
190 | */ | ||
191 | case 0x03: | ||
192 | { | ||
193 | if (!DEVICE_LINGO_SUPPORTED(0x04)) { | ||
194 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
195 | break; | ||
196 | } | ||
197 | |||
198 | IAP_TX_INIT(0x00, 0x04); | ||
199 | if (interface_state == IST_EXTENDED) | ||
200 | IAP_TX_PUT(0x01); | ||
201 | else | ||
202 | IAP_TX_PUT(0x00); | ||
203 | |||
204 | iap_send_tx(); | ||
205 | break; | ||
206 | } | ||
207 | |||
208 | /* ReturnRemoteUIMode (0x04) | ||
209 | * | ||
210 | * Sent from the iPod to the device | ||
211 | */ | ||
212 | |||
213 | /* EnterRemoteUIMode (0x05) | ||
214 | * | ||
215 | * Request Extended Interface Mode | ||
216 | * This command may be used only if the accessory requests Lingo 0x04 | ||
217 | * during its identification process. | ||
218 | * | ||
219 | * Packet format (offset in buf[]: Description) | ||
220 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
221 | * 0x01: Command, always 0x05 | ||
222 | * | ||
223 | * Returns on success: | ||
224 | * IAP_ACK_PENDING | ||
225 | * IAP_ACK_OK | ||
226 | * | ||
227 | * Returns on failure: | ||
228 | * IAP_ACK_BAD_PARAM | ||
229 | */ | ||
230 | case 0x05: | ||
231 | { | ||
232 | if (!DEVICE_LINGO_SUPPORTED(0x04)) { | ||
233 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
234 | break; | ||
235 | } | ||
236 | |||
237 | cmd_pending(cmd, 1000); | ||
238 | iap_interface_state_change(IST_EXTENDED); | ||
239 | cmd_ok(cmd); | ||
240 | break; | ||
241 | } | ||
242 | |||
243 | /* ExitRemoteUIMode (0x06) | ||
244 | * | ||
245 | * Leave Extended Interface Mode | ||
246 | * This command may be used only if the accessory requests Lingo 0x04 | ||
247 | * during its identification process. | ||
248 | * | ||
249 | * Packet format (offset in buf[]: Description) | ||
250 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
251 | * 0x01: Command, always 0x06 | ||
252 | * | ||
253 | * Returns on success: | ||
254 | * IAP_ACK_PENDING | ||
255 | * IAP_ACK_OK | ||
256 | * | ||
257 | * Returns on failure: | ||
258 | * IAP_ACK_BAD_PARAM | ||
259 | */ | ||
260 | case 0x06: | ||
261 | { | ||
262 | if (!DEVICE_LINGO_SUPPORTED(0x04)) { | ||
263 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
264 | break; | ||
265 | } | ||
266 | |||
267 | cmd_pending(cmd, 1000); | ||
268 | iap_interface_state_change(IST_STANDARD); | ||
269 | cmd_ok(cmd); | ||
270 | break; | ||
271 | } | ||
272 | |||
273 | /* RequestiPodName (0x07) | ||
274 | * | ||
275 | * Retrieves the name of the iPod | ||
276 | * | ||
277 | * Packet format (offset in buf[]: Description) | ||
278 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
279 | * 0x01: Command, always 0x07 | ||
280 | * | ||
281 | * Returns: | ||
282 | * ReturniPodName | ||
283 | * | ||
284 | * Packet format (offset in data[]: Description) | ||
285 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
286 | * 0x01: Command, always 0x08 | ||
287 | * 0x02-0xNN: iPod name as NULL-terminated UTF8 string | ||
288 | */ | ||
289 | case 0x07: | ||
290 | { | ||
291 | IAP_TX_INIT(0x00, 0x08); | ||
292 | IAP_TX_PUT_STRING("ROCKBOX"); | ||
293 | |||
294 | iap_send_tx(); | ||
295 | break; | ||
296 | } | ||
297 | |||
298 | /* ReturniPodName (0x08) | ||
299 | * | ||
300 | * Sent from the iPod to the device | ||
301 | */ | ||
302 | |||
303 | /* RequestiPodSoftwareVersion (0x09) | ||
304 | * | ||
305 | * Returns the major, minor and revision numbers of the iPod | ||
306 | * software version. This not any Lingo protocol version. | ||
307 | * | ||
308 | * Packet format (offset in buf[]: Description) | ||
309 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
310 | * 0x01: Command, always 0x09 | ||
311 | * | ||
312 | * Returns: | ||
313 | * ReturniPodSoftwareVersion | ||
314 | * | ||
315 | * Packet format (offset in data[]: Description) | ||
316 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
317 | * 0x01: Command, always 0x0A | ||
318 | * 0x02: iPod major software version | ||
319 | * 0x03: iPod minor software version | ||
320 | * 0x04: iPod revision software version | ||
321 | */ | ||
322 | case 0x09: | ||
323 | { | ||
324 | IAP_TX_INIT(0x00, 0x0A); | ||
325 | IAP_TX_PUT(IAP_IPOD_FIRMWARE_MAJOR); | ||
326 | IAP_TX_PUT(IAP_IPOD_FIRMWARE_MINOR); | ||
327 | IAP_TX_PUT(IAP_IPOD_FIRMWARE_REV); | ||
328 | |||
329 | iap_send_tx(); | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | /* ReturniPodSoftwareVersion (0x0A) | ||
334 | * | ||
335 | * Sent from the iPod to the device | ||
336 | */ | ||
337 | |||
338 | /* RequestiPodSerialNum (0x0B) | ||
339 | * | ||
340 | * Returns the iPod serial number | ||
341 | * | ||
342 | * Packet format (offset in buf[]: Description) | ||
343 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
344 | * 0x01: Command, always 0x0B | ||
345 | * | ||
346 | * Returns: | ||
347 | * ReturniPodSerialNumber | ||
348 | * | ||
349 | * Packet format (offset in data[]: Description) | ||
350 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
351 | * 0x01: Command, always 0x0C | ||
352 | * 0x02-0xNN: Serial number as NULL-terminated UTF8 string | ||
353 | */ | ||
354 | case 0x0B: | ||
355 | { | ||
356 | IAP_TX_INIT(0x00, 0x0C); | ||
357 | IAP_TX_PUT_STRING("0123456789"); | ||
358 | |||
359 | iap_send_tx(); | ||
360 | break; | ||
361 | } | ||
362 | |||
363 | /* ReturniPodSerialNum (0x0C) | ||
364 | * | ||
365 | * Sent from the iPod to the device | ||
366 | */ | ||
367 | |||
368 | /* RequestiPodModelNum (0x0D) | ||
369 | * | ||
370 | * Returns the model number as a 32bit unsigned integer and | ||
371 | * as a string. | ||
372 | * | ||
373 | * Packet format (offset in buf[]: Description) | ||
374 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
375 | * 0x01: Command, always 0x0D | ||
376 | * | ||
377 | * Returns: | ||
378 | * ReturniPodModelNum | ||
379 | * | ||
380 | * Packet format (offset in data[]: Description) | ||
381 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
382 | * 0x01: Command, always 0x0E | ||
383 | * 0x02-0x05: Model number as 32bit integer | ||
384 | * 0x06-0xNN: Model number as NULL-terminated UTF8 string | ||
385 | */ | ||
386 | case 0x0D: | ||
387 | { | ||
388 | IAP_TX_INIT(0x00, 0x0E); | ||
389 | IAP_TX_PUT_U32(IAP_IPOD_MODEL); | ||
390 | IAP_TX_PUT_STRING("ROCKBOX"); | ||
391 | |||
392 | iap_send_tx(); | ||
393 | break; | ||
394 | } | ||
395 | |||
396 | /* ReturniPodSerialNum (0x0E) | ||
397 | * | ||
398 | * Sent from the iPod to the device | ||
399 | */ | ||
400 | |||
401 | /* RequestLingoProtocolVersion (0x0F) | ||
402 | * | ||
403 | * Packet format (offset in buf[]: Description) | ||
404 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
405 | * 0x01: Command, always 0x0F | ||
406 | * 0x02: Lingo for which to request version information | ||
407 | * | ||
408 | * Returns on success: | ||
409 | * ReturnLingoProtocolVersion | ||
410 | * | ||
411 | * Packet format (offset in data[]: Description) | ||
412 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
413 | * 0x01: Command, always 0x10 | ||
414 | * 0x02: Lingo for which version information is returned | ||
415 | * 0x03: Major protocol version for the given lingo | ||
416 | * 0x04: Minor protocol version for the given lingo | ||
417 | * | ||
418 | * Returns on failure: | ||
419 | * IAP_ACK_BAD_PARAM | ||
420 | */ | ||
421 | case 0x0F: | ||
422 | { | ||
423 | unsigned char lingo = buf[2]; | ||
424 | |||
425 | CHECKLEN(3); | ||
426 | |||
427 | /* Supported lingos and versions are read from the lingo_versions | ||
428 | * array | ||
429 | */ | ||
430 | if (LINGO_SUPPORTED(lingo)) { | ||
431 | IAP_TX_INIT(0x00, 0x10); | ||
432 | IAP_TX_PUT(lingo); | ||
433 | IAP_TX_PUT(LINGO_MAJOR(lingo)); | ||
434 | IAP_TX_PUT(LINGO_MINOR(lingo)); | ||
435 | |||
436 | iap_send_tx(); | ||
437 | } else { | ||
438 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
439 | } | ||
440 | break; | ||
441 | } | ||
442 | |||
443 | /* ReturnLingoProtocolVersion (0x10) | ||
444 | * | ||
445 | * Sent from the iPod to the device | ||
446 | */ | ||
447 | |||
448 | /* IdentifyDeviceLingoes (0x13); | ||
449 | * | ||
450 | * Used by a device to inform the iPod of the devices | ||
451 | * presence and of the lingoes the device supports. | ||
452 | * | ||
453 | * Packet format (offset in buf[]: Description) | ||
454 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
455 | * 0x01: Command, always 0x13 | ||
456 | * 0x02-0x05: Device lingoes spoken | ||
457 | * 0x06-0x09: Device options | ||
458 | * 0x0A-0x0D: Device ID. Only important for authentication | ||
459 | * | ||
460 | * Returns on success: | ||
461 | * IAP_ACK_OK | ||
462 | * | ||
463 | * Returns on failure: | ||
464 | * IAP_ACK_CMD_FAILED | ||
465 | */ | ||
466 | case 0x13: | ||
467 | { | ||
468 | uint32_t lingoes = get_u32(&buf[2]); | ||
469 | uint32_t options = get_u32(&buf[6]); | ||
470 | uint32_t deviceid = get_u32(&buf[0x0A]); | ||
471 | bool seen_unsupported = false; | ||
472 | unsigned char i; | ||
473 | |||
474 | CHECKLEN(14); | ||
475 | |||
476 | /* Issuing this command exits any extended interface states */ | ||
477 | iap_interface_state_change(IST_STANDARD); | ||
478 | |||
479 | /* Loop through the lingoes advertised by the device. | ||
480 | * If it tries to use a lingo we do not support, return | ||
481 | * a Command Failed ACK. | ||
482 | */ | ||
483 | for(i=0; i<32; i++) { | ||
484 | if (lingoes & BIT_N(i)) { | ||
485 | /* Bit set by device */ | ||
486 | if (!LINGO_SUPPORTED(i)) { | ||
487 | seen_unsupported = true; | ||
488 | } | ||
489 | } | ||
490 | } | ||
491 | |||
492 | /* Bit 0 _must_ be set by the device */ | ||
493 | if (!(lingoes & 1)) { | ||
494 | seen_unsupported = true; | ||
495 | } | ||
496 | |||
497 | /* Specifying a deviceid without requesting authentication is | ||
498 | * an error | ||
499 | */ | ||
500 | if (deviceid && !(options & 0x03)) | ||
501 | seen_unsupported = true; | ||
502 | |||
503 | /* Specifying authentication without a deviceid is an error */ | ||
504 | if (!deviceid && (options & 0x03)) | ||
505 | seen_unsupported = true; | ||
506 | |||
507 | device.lingoes = 0; | ||
508 | if (seen_unsupported) { | ||
509 | cmd_ack(cmd, IAP_ACK_CMD_FAILED); | ||
510 | break; | ||
511 | } | ||
512 | iap_reset_device(&device); | ||
513 | device.lingoes = lingoes; | ||
514 | |||
515 | /* Devices using IdentifyDeviceLingoes get power off notifications */ | ||
516 | device.do_power_notify = true; | ||
517 | |||
518 | /* If a new authentication is requested, start the auth | ||
519 | * process. | ||
520 | * The periodic handler will take care of sending out the | ||
521 | * GetDevAuthenticationInfo packet | ||
522 | * | ||
523 | * If no authentication is requested, schedule the start of | ||
524 | * GetAccessoryInfo | ||
525 | */ | ||
526 | if (deviceid && (options & 0x03) && !DEVICE_AUTH_RUNNING) { | ||
527 | device.auth.state = AUST_INIT; | ||
528 | } else { | ||
529 | device.accinfo = ACCST_INIT; | ||
530 | } | ||
531 | |||
532 | cmd_ok(cmd); | ||
533 | |||
534 | /* Bit 5: RF Transmitter lingo */ | ||
535 | if (lingoes & (1 << 5)) | ||
536 | { | ||
537 | /* FM transmitter sends this: */ | ||
538 | /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/ | ||
539 | |||
540 | /* GetAccessoryInfo */ | ||
541 | unsigned char data2[] = {0x00, 0x27, 0x00}; | ||
542 | iap_send_pkt(data2, sizeof(data2)); | ||
543 | /* RF Transmitter: Begin transmission */ | ||
544 | unsigned char data3[] = {0x05, 0x02}; | ||
545 | iap_send_pkt(data3, sizeof(data3)); | ||
546 | } | ||
547 | |||
548 | |||
549 | #if 0 | ||
550 | /* Bit 7: RF Tuner lingo */ | ||
551 | if (lingoes & (1 << 7)) | ||
552 | { | ||
553 | /* ipod fm remote sends this: */ | ||
554 | /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */ | ||
555 | radio_present = 1; | ||
556 | /* GetDevAuthenticationInfo */ | ||
557 | unsigned char data4[] = {0x00, 0x14}; | ||
558 | iap_send_pkt(data4, sizeof(data4)); | ||
559 | } | ||
560 | #endif | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | /* GetDevAuthenticationInfo (0x14) | ||
565 | * | ||
566 | * Sent from the iPod to the device | ||
567 | */ | ||
568 | |||
569 | /* RetDevAuthenticationInfo (0x15) | ||
570 | * | ||
571 | * Send certificate information from the device to the iPod. | ||
572 | * The certificate may come in multiple parts and has | ||
573 | * to be reassembled. | ||
574 | * | ||
575 | * Packet format (offset in buf[]: Description) | ||
576 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
577 | * 0x01: Command, always 0x15 | ||
578 | * 0x02: Authentication major version | ||
579 | * 0x03: Authentication minor version | ||
580 | * 0x04: Certificate current section index | ||
581 | * 0x05: Certificate maximum section index | ||
582 | * 0x06-0xNN: Certificate data | ||
583 | * | ||
584 | * Returns on success: | ||
585 | * IAP_ACK_OK for intermediate sections | ||
586 | * AckDevAuthenticationInfo for the last section | ||
587 | * | ||
588 | * Returns on failure: | ||
589 | * IAP_ACK_BAD_PARAMETER | ||
590 | * AckDevAuthenticationInfo for version mismatches | ||
591 | * | ||
592 | */ | ||
593 | case 0x15: | ||
594 | { | ||
595 | /* There are two formats of this packet. One with only | ||
596 | * the version information bytes (for Auth version 1.0) | ||
597 | * and the long form shown above | ||
598 | */ | ||
599 | CHECKLEN(4); | ||
600 | |||
601 | if (!DEVICE_AUTH_RUNNING) { | ||
602 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
603 | break; | ||
604 | } | ||
605 | |||
606 | /* We only support version 2.0 */ | ||
607 | if ((buf[2] != 2) || (buf[3] != 0)) { | ||
608 | /* Version mismatches are signalled by AckDevAuthenticationInfo | ||
609 | * with the status set to Authentication Information unsupported | ||
610 | */ | ||
611 | iap_reset_auth(&(device.auth)); | ||
612 | |||
613 | IAP_TX_INIT(0x00, 0x16); | ||
614 | IAP_TX_PUT(0x08); | ||
615 | |||
616 | iap_send_tx(); | ||
617 | break; | ||
618 | } | ||
619 | |||
620 | /* There must be at least one byte of certificate data | ||
621 | * in the packet | ||
622 | */ | ||
623 | CHECKLEN(7); | ||
624 | |||
625 | switch (device.auth.state) | ||
626 | { | ||
627 | /* This is the first packet. Note the maximum section number | ||
628 | * so we can check it later. | ||
629 | */ | ||
630 | case AUST_CERTREQ: | ||
631 | { | ||
632 | device.auth.max_section = buf[5]; | ||
633 | device.auth.state = AUST_CERTBEG; | ||
634 | |||
635 | /* Intentional fall-through */ | ||
636 | } | ||
637 | /* All following packets */ | ||
638 | case AUST_CERTBEG: | ||
639 | { | ||
640 | /* Check if this is the expected section */ | ||
641 | if (buf[4] != device.auth.next_section) { | ||
642 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
643 | break; | ||
644 | } | ||
645 | |||
646 | /* Is this the last section? */ | ||
647 | if (device.auth.next_section == device.auth.max_section) { | ||
648 | /* If we could really do authentication we'd have to | ||
649 | * check the certificate here. Since we can't, just acknowledge | ||
650 | * the packet with an "everything OK" AckDevAuthenticationInfo | ||
651 | * | ||
652 | * Also, start GetAccessoryInfo process | ||
653 | */ | ||
654 | IAP_TX_INIT(0x00, 0x16); | ||
655 | IAP_TX_PUT(0x00); | ||
656 | |||
657 | iap_send_tx(); | ||
658 | device.auth.state = AUST_CERTDONE; | ||
659 | device.accinfo = ACCST_INIT; | ||
660 | } else { | ||
661 | device.auth.next_section++; | ||
662 | cmd_ok(cmd); | ||
663 | } | ||
664 | break; | ||
665 | } | ||
666 | |||
667 | default: | ||
668 | { | ||
669 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
670 | break; | ||
671 | } | ||
672 | } | ||
673 | |||
674 | break; | ||
675 | } | ||
676 | |||
677 | /* AckDevAuthenticationInfo (0x16) | ||
678 | * | ||
679 | * Sent from the iPod to the device | ||
680 | */ | ||
681 | |||
682 | /* GetDevAuthenticationSignature (0x17) | ||
683 | * | ||
684 | * Sent from the iPod to the device | ||
685 | */ | ||
686 | |||
687 | /* RetDevAuthenticationSignature (0x18) | ||
688 | * | ||
689 | * Return a calculated signature based on the device certificate | ||
690 | * and the challenge sent with GetDevAuthenticationSignature | ||
691 | * | ||
692 | * Packet format (offset in buf[]: Description) | ||
693 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
694 | * 0x01: Command, always 0x17 | ||
695 | * 0x02-0xNN: Certificate data | ||
696 | * | ||
697 | * Returns on success: | ||
698 | * AckDevAuthenticationStatus | ||
699 | * | ||
700 | * Packet format (offset in data[]: Description) | ||
701 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
702 | * 0x01: Command, always 0x19 | ||
703 | * 0x02: Status (0x00: OK) | ||
704 | * | ||
705 | * Returns on failure: | ||
706 | * IAP_ACK_BAD_PARAM | ||
707 | * | ||
708 | * TODO: | ||
709 | * There is a timeout of 75 seconds between GetDevAuthenticationSignature | ||
710 | * and RetDevAuthenticationSignature for Auth 2.0. This is currently not | ||
711 | * checked. | ||
712 | */ | ||
713 | case 0x18: | ||
714 | { | ||
715 | if (device.auth.state != AUST_CHASENT) { | ||
716 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
717 | break; | ||
718 | } | ||
719 | |||
720 | /* Here we could check the signature. Since we can't, just | ||
721 | * acknowledge and go to authenticated status | ||
722 | */ | ||
723 | IAP_TX_INIT(0x00, 0x19); | ||
724 | IAP_TX_PUT(0x00); | ||
725 | |||
726 | iap_send_tx(); | ||
727 | device.auth.state = AUST_AUTH; | ||
728 | break; | ||
729 | } | ||
730 | |||
731 | /* AckDevAuthenticationStatus (0x19) | ||
732 | * | ||
733 | * Sent from the iPod to the device | ||
734 | */ | ||
735 | |||
736 | /* GetiPodAuthenticationInfo (0x1A) | ||
737 | * | ||
738 | * Obtain authentication information from the iPod. | ||
739 | * This cannot be implemented without posessing an Apple signed | ||
740 | * certificate and the corresponding private key. | ||
741 | * | ||
742 | * Packet format (offset in buf[]: Description) | ||
743 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
744 | * 0x01: Command, always 0x1A | ||
745 | * | ||
746 | * This command requires authentication | ||
747 | * | ||
748 | * Returns: | ||
749 | * IAP_ACK_CMD_FAILED | ||
750 | */ | ||
751 | case 0x1A: | ||
752 | { | ||
753 | CHECKAUTH; | ||
754 | |||
755 | cmd_ack(cmd, IAP_ACK_CMD_FAILED); | ||
756 | break; | ||
757 | } | ||
758 | |||
759 | /* RetiPodAuthenticationInfo (0x1B) | ||
760 | * | ||
761 | * Sent from the iPod to the device | ||
762 | */ | ||
763 | |||
764 | /* AckiPodAuthenticationInfo (0x1C) | ||
765 | * | ||
766 | * Confirm authentication information from the iPod. | ||
767 | * This cannot be implemented without posessing an Apple signed | ||
768 | * certificate and the corresponding private key. | ||
769 | * | ||
770 | * Packet format (offset in buf[]: Description) | ||
771 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
772 | * 0x01: Command, always 0x1C | ||
773 | * 0x02: Authentication state (0x00: OK) | ||
774 | * | ||
775 | * This command requires authentication | ||
776 | * | ||
777 | * Returns: (none) | ||
778 | */ | ||
779 | case 0x1C: | ||
780 | { | ||
781 | CHECKAUTH; | ||
782 | |||
783 | break; | ||
784 | } | ||
785 | |||
786 | /* GetiPodAuthenticationSignature (0x1D) | ||
787 | * | ||
788 | * Send challenge information to the iPod. | ||
789 | * This cannot be implemented without posessing an Apple signed | ||
790 | * certificate and the corresponding private key. | ||
791 | * | ||
792 | * Packet format (offset in buf[]: Description) | ||
793 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
794 | * 0x01: Command, always 0x1D | ||
795 | * 0x02-0x15: Challenge | ||
796 | * | ||
797 | * This command requires authentication | ||
798 | * | ||
799 | * Returns: | ||
800 | * IAP_ACK_CMD_FAILED | ||
801 | */ | ||
802 | case 0x1D: | ||
803 | { | ||
804 | CHECKAUTH; | ||
805 | |||
806 | cmd_ack(cmd, IAP_ACK_CMD_FAILED); | ||
807 | break; | ||
808 | } | ||
809 | |||
810 | /* RetiPodAuthenticationSignature (0x1E) | ||
811 | * | ||
812 | * Sent from the iPod to the device | ||
813 | */ | ||
814 | |||
815 | /* AckiPodAuthenticationStatus (0x1F) | ||
816 | * | ||
817 | * Confirm chellenge information from the iPod. | ||
818 | * This cannot be implemented without posessing an Apple signed | ||
819 | * certificate and the corresponding private key. | ||
820 | * | ||
821 | * Packet format (offset in buf[]: Description) | ||
822 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
823 | * 0x01: Command, always 0x1C | ||
824 | * 0x02: Challenge state (0x00: OK) | ||
825 | * | ||
826 | * This command requires authentication | ||
827 | * | ||
828 | * Returns: (none) | ||
829 | */ | ||
830 | case 0x1F: | ||
831 | { | ||
832 | CHECKAUTH; | ||
833 | |||
834 | break; | ||
835 | } | ||
836 | |||
837 | /* NotifyiPodStateChange (0x23) | ||
838 | * | ||
839 | * Sent from the iPod to the device | ||
840 | */ | ||
841 | |||
842 | /* GetIpodOptions (0x24) | ||
843 | * | ||
844 | * Request supported features of the iPod | ||
845 | * | ||
846 | * Packet format (offset in buf[]: Description) | ||
847 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
848 | * 0x01: Command, always 0x24 | ||
849 | * | ||
850 | * Retuns: | ||
851 | * RetiPodOptions | ||
852 | * | ||
853 | * Packet format (offset in data[]: Description) | ||
854 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
855 | * 0x01: Command, always 0x25 | ||
856 | * 0x02-0x09: Options as a bitfield | ||
857 | */ | ||
858 | case 0x24: | ||
859 | { | ||
860 | /* There are only two features that can be communicated via this | ||
861 | * function, video support and the ability to control line-out usage. | ||
862 | * Rockbox supports neither | ||
863 | */ | ||
864 | IAP_TX_INIT(0x00, 0x25); | ||
865 | IAP_TX_PUT_U32(0x00); | ||
866 | IAP_TX_PUT_U32(0x00); | ||
867 | |||
868 | iap_send_tx(); | ||
869 | break; | ||
870 | } | ||
871 | |||
872 | /* RetiPodOptions (0x25) | ||
873 | * | ||
874 | * Sent from the iPod to the device | ||
875 | */ | ||
876 | |||
877 | /* GetAccessoryInfo (0x27) | ||
878 | * | ||
879 | * Sent from the iPod to the device | ||
880 | */ | ||
881 | |||
882 | /* RetAccessoryInfo (0x28) | ||
883 | * | ||
884 | * Send information about the device | ||
885 | * | ||
886 | * Packet format (offset in buf[]: Description) | ||
887 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
888 | * 0x01: Command, always 0x28 | ||
889 | * 0x02: Accessory info type | ||
890 | * 0x03-0xNN: Accessory information (depends on 0x02) | ||
891 | * | ||
892 | * Returns: (none) | ||
893 | * | ||
894 | * TODO: Actually do something with the information received here. | ||
895 | * Some devices actually expect us to request the data they | ||
896 | * offer, so completely ignoring this does not work, either. | ||
897 | */ | ||
898 | case 0x28: | ||
899 | { | ||
900 | CHECKLEN(3); | ||
901 | |||
902 | switch (buf[0x02]) | ||
903 | { | ||
904 | /* Info capabilities */ | ||
905 | case 0x00: | ||
906 | { | ||
907 | CHECKLEN(7); | ||
908 | |||
909 | device.capabilities = get_u32(&buf[0x03]); | ||
910 | /* Type 0x00 was already queried, that's where this information comes from */ | ||
911 | device.capabilities_queried = 0x01; | ||
912 | device.capabilities &= ~0x01; | ||
913 | break; | ||
914 | } | ||
915 | |||
916 | /* For now, ignore all other information */ | ||
917 | default: | ||
918 | { | ||
919 | break; | ||
920 | } | ||
921 | } | ||
922 | |||
923 | /* If there are any unqueried capabilities left, do so */ | ||
924 | if (device.capabilities) | ||
925 | device.accinfo = ACCST_DATA; | ||
926 | |||
927 | break; | ||
928 | } | ||
929 | |||
930 | /* GetiPodPreferences (0x29) | ||
931 | * | ||
932 | * Retrieve information about the current state of the | ||
933 | * iPod. | ||
934 | * | ||
935 | * Packet format (offset in buf[]: Description) | ||
936 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
937 | * 0x01: Command, always 0x29 | ||
938 | * 0x02: Information class requested | ||
939 | * | ||
940 | * This command requires authentication | ||
941 | * | ||
942 | * Returns on success: | ||
943 | * RetiPodPreferences | ||
944 | * | ||
945 | * Packet format (offset in data[]: Description) | ||
946 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
947 | * 0x01: Command, always 0x2A | ||
948 | * 0x02: Information class provided | ||
949 | * 0x03: Information | ||
950 | * | ||
951 | * Returns on failure: | ||
952 | * IAP_ACK_BAD_PARAM | ||
953 | */ | ||
954 | case 0x29: | ||
955 | { | ||
956 | CHECKLEN(3); | ||
957 | CHECKAUTH; | ||
958 | |||
959 | IAP_TX_INIT(0x00, 0x2A); | ||
960 | /* The only information really supported is 0x03, Line-out usage. | ||
961 | * All others are video related | ||
962 | */ | ||
963 | if (buf[2] == 0x03) { | ||
964 | IAP_TX_PUT(0x03); | ||
965 | IAP_TX_PUT(0x01); /* Line-out enabled */ | ||
966 | |||
967 | iap_send_tx(); | ||
968 | } else { | ||
969 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
970 | } | ||
971 | |||
972 | break; | ||
973 | } | ||
974 | |||
975 | /* RetiPodPreference (0x2A) | ||
976 | * | ||
977 | * Sent from the iPod to the device | ||
978 | */ | ||
979 | |||
980 | /* SetiPodPreferences (0x2B) | ||
981 | * | ||
982 | * Set preferences on the iPod | ||
983 | * | ||
984 | * Packet format (offset in buf[]: Description) | ||
985 | * 0x00: Lingo ID: General Lingo, always 0x00 | ||
986 | * 0x01: Command, always 0x29 | ||
987 | * 0x02: Prefecence class requested | ||
988 | * 0x03: Preference setting | ||
989 | * 0x04: Restore on exit | ||
990 | * | ||
991 | * This command requires authentication | ||
992 | * | ||
993 | * Returns on success: | ||
994 | * IAP_ACK_OK | ||
995 | * | ||
996 | * Returns on failure: | ||
997 | * IAP_ACK_BAD_PARAM | ||
998 | * IAP_ACK_CMD_FAILED | ||
999 | */ | ||
1000 | case 0x2B: | ||
1001 | { | ||
1002 | CHECKLEN(5); | ||
1003 | CHECKAUTH; | ||
1004 | |||
1005 | /* The only information really supported is 0x03, Line-out usage. | ||
1006 | * All others are video related | ||
1007 | */ | ||
1008 | if (buf[2] == 0x03) { | ||
1009 | /* If line-out disabled is requested, reply with IAP_ACK_CMD_FAILED, | ||
1010 | * otherwise with IAP_ACK_CMD_OK | ||
1011 | */ | ||
1012 | if (buf[3] == 0x00) { | ||
1013 | cmd_ack(cmd, IAP_ACK_CMD_FAILED); | ||
1014 | } else { | ||
1015 | cmd_ok(cmd); | ||
1016 | } | ||
1017 | } else { | ||
1018 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
1019 | } | ||
1020 | |||
1021 | break; | ||
1022 | } | ||
1023 | |||
1024 | /* The default response is IAP_ACK_BAD_PARAM */ | ||
1025 | default: | ||
1026 | { | ||
1027 | #ifdef LOGF_ENABLE | ||
1028 | logf("iap: Unsupported Mode00 Command"); | ||
1029 | #else | ||
1030 | cmd_ack(cmd, IAP_ACK_BAD_PARAM); | ||
1031 | #endif | ||
1032 | break; | ||
1033 | } | ||
1034 | } | ||
1035 | } | ||