summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorLiveboxAndy <liveboxandy@gmail.com>2018-08-04 18:02:21 +0100
committerSolomon Peachy <pizza@shaftnet.org>2020-07-09 18:02:07 +0000
commit77f8c9c9f12f1a520467868047574fe0af7a1556 (patch)
tree2ae699fbdeca5aed4e28a1d5bc69915d5f6f5838 /apps
parentdcdf2713f610cb3cfaa615ab9b8d4b9412e7a8b6 (diff)
downloadrockbox-77f8c9c9f12f1a520467868047574fe0af7a1556.tar.gz
rockbox-77f8c9c9f12f1a520467868047574fe0af7a1556.zip
Update to allow the Apple Radio Remote to function on iPod Video 5G.
This was broken when the major update to iap was comitted. ia-lingo7.c created and various iap related files modified. On 4G, 6G and Nano 1/2Gen iPods the remote will function even though the radio won't. Tested on 4G Greyscale, 4G Color, 4G Photo, 4G Mini 1st Gen, 4G Mini 2Gen, Nano 1G, Nano 2G, Video 5G, Video 5.5G Change-Id: Ia74e3d07d9ab5edc6da8eafa96801ede722be331
Diffstat (limited to 'apps')
-rw-r--r--apps/SOURCES4
-rw-r--r--apps/iap/iap-core.c115
-rw-r--r--apps/iap/iap-core.h19
-rw-r--r--apps/iap/iap-lingo.h3
-rw-r--r--apps/iap/iap-lingo0.c263
-rw-r--r--apps/iap/iap-lingo1.c1
-rw-r--r--apps/iap/iap-lingo2.c34
-rw-r--r--apps/iap/iap-lingo3.c75
-rw-r--r--apps/iap/iap-lingo4.c11
-rw-r--r--apps/iap/iap-lingo7.c491
10 files changed, 837 insertions, 179 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 99b0832286..107431d464 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -70,8 +70,10 @@ iap/iap-lingo1.c
70iap/iap-lingo2.c 70iap/iap-lingo2.c
71iap/iap-lingo3.c 71iap/iap-lingo3.c
72iap/iap-lingo4.c 72iap/iap-lingo4.c
73#if CONFIG_TUNER
74iap/iap-lingo7.c
75#endif
73#endif 76#endif
74
75screen_access.c 77screen_access.c
76#ifdef HAVE_BUTTONBAR 78#ifdef HAVE_BUTTONBAR
77gui/buttonbar.c 79gui/buttonbar.c
diff --git a/apps/iap/iap-core.c b/apps/iap/iap-core.c
index f8373bab83..885ba2c188 100644
--- a/apps/iap/iap-core.c
+++ b/apps/iap/iap-core.c
@@ -45,7 +45,9 @@
45#include "usb.h" 45#include "usb.h"
46 46
47#include "tuner.h" 47#include "tuner.h"
48#if CONFIG_TUNER
48#include "ipod_remote_tuner.h" 49#include "ipod_remote_tuner.h"
50#endif
49 51
50 52
51/* MS_TO_TICKS converts a milisecond time period into the 53/* MS_TO_TICKS converts a milisecond time period into the
@@ -164,7 +166,13 @@ unsigned char lingo_versions[32][2] = {
164 {1, 5}, /* Display remote lingo, 0x03 */ 166 {1, 5}, /* Display remote lingo, 0x03 */
165 {1, 12}, /* Extended Interface lingo, 0x04 */ 167 {1, 12}, /* Extended Interface lingo, 0x04 */
166 {1, 1}, /* RF/BT Transmitter lingo, 0x05 */ 168 {1, 1}, /* RF/BT Transmitter lingo, 0x05 */
167 {} /* All others are unsupported */ 169 {0, 0}, /* USB Host lingo, 0x06, disabled */
170#if CONFIG_TUNER
171 {1, 0}, /* RF Receiver lingo, 0x07 */
172#else
173 {0, 0}, /* RF Receiver lingo, 0x07 disabled */
174#endif
175 {} /* every other lingo, disabled */
168}; 176};
169 177
170/* states of the iap de-framing state machine */ 178/* states of the iap de-framing state machine */
@@ -308,6 +316,17 @@ static int iap_task(struct timeout *tmo)
308 return MS_TO_TICKS(100); 316 return MS_TO_TICKS(100);
309} 317}
310 318
319
320void iap_set_remote_volume(void)
321{
322 IAP_TX_INIT(0x03, 0x0D);
323 IAP_TX_PUT(0x04);
324 IAP_TX_PUT(0x00);
325 IAP_TX_PUT(0xFF & (int)((global_settings.volume + 90) * 2.65625));
326 iap_send_tx();
327}
328
329
311/* This thread is waiting for events posted to iap_queue and calls 330/* This thread is waiting for events posted to iap_queue and calls
312 * the appropriate subroutines in response 331 * the appropriate subroutines in response
313 */ 332 */
@@ -859,11 +878,15 @@ void iap_periodic(void)
859 878
860 /* Volume change notifications are sent every 100ms */ 879 /* Volume change notifications are sent every 100ms */
861 if (device.notifications & (BIT_N(4) | BIT_N(16))) { 880 if (device.notifications & (BIT_N(4) | BIT_N(16))) {
862 /* Currently we do not track volume changes, so this is 881 /* Currently we do not track volume changes for BIT_N(16),
863 * never sent.
864 * 882 *
865 * TODO: Fix volume tracking
866 */ 883 */
884 IAP_TX_INIT(0x03, 0x09);
885 IAP_TX_PUT(0x04);
886 IAP_TX_PUT(0x00);
887 IAP_TX_PUT(0xFF &(int)((global_settings.volume + 90) * 2.65625));
888 device.changed_notifications |= BIT_N(4);
889 iap_send_tx();
867 } 890 }
868 891
869 /* All other events are sent every 500ms */ 892 /* All other events are sent every 500ms */
@@ -972,9 +995,15 @@ void iap_periodic(void)
972 unsigned char play_status; 995 unsigned char play_status;
973 996
974 play_status = audio_status(); 997 play_status = audio_status();
975
976 if (device.play_status != play_status) 998 if (device.play_status != play_status)
977 { 999 {
1000 /* If play_status = PAUSE/STOP we should mute else
1001 * we should unmute
1002 * 0 = Stopped
1003 * 1 = Playing
1004 * 2 = Pause
1005 * 3 = Play/Pause
1006 */
978 IAP_TX_INIT(0x03, 0x09); 1007 IAP_TX_INIT(0x03, 0x09);
979 IAP_TX_PUT(0x03); 1008 IAP_TX_PUT(0x03);
980 if (play_status & AUDIO_STATUS_PLAY) { 1009 if (play_status & AUDIO_STATUS_PLAY) {
@@ -994,6 +1023,23 @@ void iap_periodic(void)
994 iap_send_tx(); 1023 iap_send_tx();
995 1024
996 device.play_status = play_status; 1025 device.play_status = play_status;
1026 if (play_status != 1) {
1027 /* Not Playing */
1028 audio_pause();
1029#if CONFIG_TUNER
1030 if (radio_present==1) {
1031 tuner_set(RADIO_MUTE,1);
1032 }
1033#endif
1034 } else {
1035 /* Playing */
1036 audio_resume();
1037#if CONFIG_TUNER
1038 if (radio_present==1) {
1039 tuner_set(RADIO_MUTE,0);
1040 }
1041#endif
1042 }
997 } 1043 }
998 } 1044 }
999 1045
@@ -1212,43 +1258,6 @@ static void iap_handlepkt_mode5(const unsigned int len, const unsigned char *buf
1212 } 1258 }
1213} 1259}
1214 1260
1215#if 0
1216static void iap_handlepkt_mode7(const unsigned int len, const unsigned char *buf)
1217{
1218 unsigned int cmd = buf[1];
1219 switch (cmd)
1220 {
1221 /* RetTunerCaps */
1222 case 0x02:
1223 {
1224 /* do nothing */
1225
1226 /* GetAccessoryInfo */
1227 unsigned char data[] = {0x00, 0x27, 0x00};
1228 iap_send_pkt(data, sizeof(data));
1229 break;
1230 }
1231
1232 /* RetTunerFreq */
1233 case 0x0A:
1234 /* fall through */
1235 /* TunerSeekDone */
1236 case 0x13:
1237 {
1238 rmt_tuner_freq(len, buf);
1239 break;
1240 }
1241
1242 /* RdsReadyNotify, RDS station name 0x21 1E 00 + ASCII text*/
1243 case 0x21:
1244 {
1245 rmt_tuner_rds_data(len, buf);
1246 break;
1247 }
1248 }
1249}
1250#endif
1251
1252void iap_handlepkt(void) 1261void iap_handlepkt(void)
1253{ 1262{
1254 int level; 1263 int level;
@@ -1271,17 +1280,21 @@ void iap_handlepkt(void)
1271 logf("R: %s", hexstring(iap_rxstart+2, (length))); 1280 logf("R: %s", hexstring(iap_rxstart+2, (length)));
1272#endif 1281#endif
1273 1282
1274 unsigned char mode = *(iap_rxstart+2); 1283 if (length != 0) {
1275 switch (mode) { 1284 unsigned char mode = *(iap_rxstart+2);
1276 case 0: iap_handlepkt_mode0(length, iap_rxstart+2); break; 1285 switch (mode) {
1286 case 0: iap_handlepkt_mode0(length, iap_rxstart+2); break;
1277#ifdef HAVE_LINE_REC 1287#ifdef HAVE_LINE_REC
1278 case 1: iap_handlepkt_mode1(length, iap_rxstart+2); break; 1288 case 1: iap_handlepkt_mode1(length, iap_rxstart+2); break;
1279#endif 1289#endif
1280 case 2: iap_handlepkt_mode2(length, iap_rxstart+2); break; 1290 case 2: iap_handlepkt_mode2(length, iap_rxstart+2); break;
1281 case 3: iap_handlepkt_mode3(length, iap_rxstart+2); break; 1291 case 3: iap_handlepkt_mode3(length, iap_rxstart+2); break;
1282 case 4: iap_handlepkt_mode4(length, iap_rxstart+2); break; 1292 case 4: iap_handlepkt_mode4(length, iap_rxstart+2); break;
1283 case 5: iap_handlepkt_mode5(length, iap_rxstart+2); break; 1293 case 5: iap_handlepkt_mode5(length, iap_rxstart+2); break;
1284 /* case 7: iap_handlepkt_mode7(length, iap_rxstart+2); break; */ 1294#if CONFIG_TUNER
1295 case 7: iap_handlepkt_mode7(length, iap_rxstart+2); break;
1296#endif
1297 }
1285 } 1298 }
1286 1299
1287 /* Remove the handled packet from the RX buffer 1300 /* Remove the handled packet from the RX buffer
diff --git a/apps/iap/iap-core.h b/apps/iap/iap-core.h
index 61b72d4ca2..b558e1cc0f 100644
--- a/apps/iap/iap-core.h
+++ b/apps/iap/iap-core.h
@@ -34,6 +34,7 @@
34 34
35/* The Model ID of the iPod we emulate. Currently a 160GB classic */ 35/* The Model ID of the iPod we emulate. Currently a 160GB classic */
36#define IAP_IPOD_MODEL (0x00130200U) 36#define IAP_IPOD_MODEL (0x00130200U)
37#define IAP_IPOD_VARIANT "MC293"
37 38
38/* The firmware version we emulate. Currently 2.0.3 */ 39/* The firmware version we emulate. Currently 2.0.3 */
39#define IAP_IPOD_FIRMWARE_MAJOR (2) 40#define IAP_IPOD_FIRMWARE_MAJOR (2)
@@ -73,14 +74,15 @@ enum interface_state {
73 74
74/* States of the authentication state machine */ 75/* States of the authentication state machine */
75enum authen_state { 76enum authen_state {
76 AUST_NONE, /* Initial state, no message sent */ 77 AUST_NONE, /* Initial state, no message sent */
77 AUST_INIT, /* Remote side has requested authentication */ 78 AUST_INIT, /* Remote side has requested authentication */
78 AUST_CERTREQ, /* Remote certificate requested */ 79 AUST_CERTREQ, /* Remote certificate requested */
79 AUST_CERTBEG, /* Certificate is being received */ 80 AUST_CERTBEG, /* Certificate is being received */
80 AUST_CERTDONE, /* Certificate received */ 81 AUST_CERTALLRECEIVED, /* Certificate all Received */
81 AUST_CHASENT, /* Challenge sent */ 82 AUST_CERTDONE, /* Certificate all Done */
82 AUST_CHADONE, /* Challenge response received */ 83 AUST_CHASENT, /* Challenge sent */
83 AUST_AUTH, /* Authentication complete */ 84 AUST_CHADONE, /* Challenge response received */
85 AUST_AUTH, /* Authentication complete */
84}; 86};
85 87
86/* State of authentication */ 88/* State of authentication */
@@ -237,6 +239,7 @@ void iap_repeat_next(void);
237void iap_fill_power_state(void); 239void iap_fill_power_state(void);
238 240
239void iap_send_tx(void); 241void iap_send_tx(void);
242void iap_set_remote_volume(void);
240 243
241extern enum interface_state interface_state; 244extern enum interface_state interface_state;
242void iap_interface_state_change(const enum interface_state new); 245void iap_interface_state_change(const enum interface_state new);
diff --git a/apps/iap/iap-lingo.h b/apps/iap/iap-lingo.h
index 888490c26a..982a62173f 100644
--- a/apps/iap/iap-lingo.h
+++ b/apps/iap/iap-lingo.h
@@ -24,3 +24,6 @@ void iap_handlepkt_mode1(const unsigned int len, const unsigned char *buf);
24void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf); 24void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf);
25void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf); 25void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf);
26void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf); 26void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf);
27#if CONFIG_TUNER
28void iap_handlepkt_mode7(const unsigned int len, const unsigned char *buf);
29#endif
diff --git a/apps/iap/iap-lingo0.c b/apps/iap/iap-lingo0.c
index e69b42beae..a0c74ce053 100644
--- a/apps/iap/iap-lingo0.c
+++ b/apps/iap/iap-lingo0.c
@@ -21,6 +21,10 @@
21#include "iap-lingo.h" 21#include "iap-lingo.h"
22#include "kernel.h" 22#include "kernel.h"
23#include "system.h" 23#include "system.h"
24#include "tuner.h"
25#if CONFIG_TUNER
26#include "ipod_remote_tuner.h"
27#endif
24 28
25/* 29/*
26 * This macro is meant to be used inside an IAP mode message handler. 30 * This macro is meant to be used inside an IAP mode message handler.
@@ -45,10 +49,13 @@
45 49
46static void cmd_ack(const unsigned char cmd, const unsigned char status) 50static void cmd_ack(const unsigned char cmd, const unsigned char status)
47{ 51{
48 IAP_TX_INIT(0x00, 0x02); 52 if (cmd != 0){
49 IAP_TX_PUT(status); 53 IAP_TX_INIT(0x00, 0x02);
50 IAP_TX_PUT(cmd); 54 IAP_TX_PUT(status);
51 iap_send_tx(); 55 IAP_TX_PUT(cmd);
56
57 iap_send_tx();
58 }
52} 59}
53 60
54#define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK) 61#define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK)
@@ -59,6 +66,7 @@ static void cmd_pending(const unsigned char cmd, const uint32_t msdelay)
59 IAP_TX_PUT(0x06); 66 IAP_TX_PUT(0x06);
60 IAP_TX_PUT(cmd); 67 IAP_TX_PUT(cmd);
61 IAP_TX_PUT_U32(msdelay); 68 IAP_TX_PUT_U32(msdelay);
69
62 iap_send_tx(); 70 iap_send_tx();
63} 71}
64 72
@@ -387,7 +395,7 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
387 { 395 {
388 IAP_TX_INIT(0x00, 0x0E); 396 IAP_TX_INIT(0x00, 0x0E);
389 IAP_TX_PUT_U32(IAP_IPOD_MODEL); 397 IAP_TX_PUT_U32(IAP_IPOD_MODEL);
390 IAP_TX_PUT_STRING("ROCKBOX"); 398 IAP_TX_PUT_STRING(IAP_IPOD_VARIANT);
391 399
392 iap_send_tx(); 400 iap_send_tx();
393 break; 401 break;
@@ -476,6 +484,59 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
476 /* Issuing this command exits any extended interface states */ 484 /* Issuing this command exits any extended interface states */
477 iap_interface_state_change(IST_STANDARD); 485 iap_interface_state_change(IST_STANDARD);
478 486
487 /*
488 * Actions by remote listed Apple Firmware Rockbox Firmware
489 * Apple remote on Radio pause/play - Mutes Mutes
490 * vol up/down - Vol Up/Dn Vol Up/Dn
491 * FF/FR - Station Up/Dn Station Up/Dn
492 * iPod Pause/Play - Mutes Mutes
493 * Vol up/down - Vol Up/Dn Vol Up/Dn
494 * FF/FR - Station Up/Dn Station Up/Dn
495 * Remote pause/play - Pause/Play Pause/Play
496 * vol up/down - Vol Up/Dn Vol Up/Dn
497 * FF/FR - Next/Prev Track Next/Prev Track
498 * iPod Pause/Play - Pause/Play Pause/Play
499 * Vol up/down - Vol Up/Dn Vol Up/Dn
500 * FF/FR - Next/Prev Track Next/Prev Track
501 *
502 * The following bytes are returned by the accessories listed
503 * FF 55 0E 00 13 00 00 00 3D 00 00 00 04 00 00 00 00 9E robi DAB Radio Remote
504 * FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??) FM Transmitter
505 * FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 Apple Radio Remote
506 *
507 * Bytes 9-12 = Options 11111100 0000 00 00
508 * 54321098 7654 32 10
509 * 00000004 = 00000000 00000000 00000000 0000 01 00 Bits 2
510 * 00000004 = 00000000 00000000 00000000 0000 01 00 Bits 2
511 * 0000000E = 00000000 00000000 00000000 0000 01 10 Bits 12
512 *
513 * Bit 0: Authentication 00 = No Authentication
514 * 01 = Defer Auth until required (V1)
515 * Bit 1: 10 = Authenticate Immediately (V2)
516 * 11 = Reserved
517 * Bit 2: Power Requirements 00 = Low Power Only 10 = Reserved
518 * Bit 3: 01 = Int High Power 11 = Reserved
519 *
520 * Bytes 13-16 = Device ID
521 * 00000000
522 * 00000000
523 * 00000003
524 *
525 * Bytes 5-8 = lingoes spoken 11111100 00000000
526 * 54321098 76543210
527 * 0000003D = 00000000 00000000 00000000 00111101 Bits 2345
528 * 00000035 = 00000000 00000000 00000000 00110101 Bits 245
529 * 0000008D = 00000000 00000000 00000000 10001101 Bits 237
530 *
531 *
532 * Bit 0: Must be set by all devices. See above
533 * Bit 1: Microphone Lingo
534 * Bit 2: Simple Remote
535 * Bit 3: Display Remote
536 * Bit 4: Extended Remote
537 * Bit 5: RF Transmitter lingo
538 */
539
479 /* Loop through the lingoes advertised by the device. 540 /* Loop through the lingoes advertised by the device.
480 * If it tries to use a lingo we do not support, return 541 * If it tries to use a lingo we do not support, return
481 * a Command Failed ACK. 542 * a Command Failed ACK.
@@ -531,33 +592,49 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
531 592
532 cmd_ok(cmd); 593 cmd_ok(cmd);
533 594
595 /* Bit 0: Must be set by all devices. See above*/
596 /* Bit 1: Microphone Lingo */
597 /* Bit 2: Simple Remote */
598 /* Bit 3: Display Remote */
599 /* Bit 4: Extended Remote */
534 /* Bit 5: RF Transmitter lingo */ 600 /* Bit 5: RF Transmitter lingo */
535 if (lingoes & (1 << 5)) 601 if (lingoes & (1 << 5))
536 { 602 {
537 /* FM transmitter sends this: */ 603 /* FM transmitter sends this: */
538 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/ 604 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
539 605 /* 0x00000035 = 00000000 00000000 00000000 00110101 */
606 /* 1<<5 1 */
540 /* GetAccessoryInfo */ 607 /* GetAccessoryInfo */
541 unsigned char data2[] = {0x00, 0x27, 0x00}; 608 IAP_TX_INIT(0x00, 0x27);
542 iap_send_pkt(data2, sizeof(data2)); 609 IAP_TX_PUT(0x00);
543 /* RF Transmitter: Begin transmission */
544 unsigned char data3[] = {0x05, 0x02};
545 iap_send_pkt(data3, sizeof(data3));
546 }
547 610
611 iap_send_tx();
548 612
549#if 0 613 /* RF Transmitter: Begin transmission */
614 IAP_TX_INIT(0x05, 0x02);
615
616 iap_send_tx();
617 }
618 /* Bit 6: USB Host Control */
550 /* Bit 7: RF Tuner lingo */ 619 /* Bit 7: RF Tuner lingo */
620#if CONFIG_TUNER
551 if (lingoes & (1 << 7)) 621 if (lingoes & (1 << 7))
552 { 622 {
553 /* ipod fm remote sends this: */ 623 /* ipod fm radio remote sends this: */
554 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */ 624 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 */
625 /* 0x0000008D = 00000000 00000000 00000000 00011101 */
626 /* 1<<7 */
555 radio_present = 1; 627 radio_present = 1;
556 /* GetDevAuthenticationInfo */
557 unsigned char data4[] = {0x00, 0x14};
558 iap_send_pkt(data4, sizeof(data4));
559 } 628 }
560#endif 629#endif
630 /* Bit 8: Accessory Equalizer Lingo */
631 /* Bit 9: Reserved */
632 /* Bit 10: Digial Audio Lingo */
633 /* Bit 11: Reserved */
634 /* Bit 12: Storage Lingo */
635 /* Bit 13: Reserved */
636 /* .................*/
637 /* Bit 31: Reserved */
561 break; 638 break;
562 } 639 }
563 640
@@ -594,7 +671,8 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
594 { 671 {
595 /* There are two formats of this packet. One with only 672 /* There are two formats of this packet. One with only
596 * the version information bytes (for Auth version 1.0) 673 * the version information bytes (for Auth version 1.0)
597 * and the long form shown above 674 * and the long form shown above but it must be at least 4
675 * bytes long
598 */ 676 */
599 CHECKLEN(4); 677 CHECKLEN(4);
600 678
@@ -605,25 +683,8 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
605 683
606 device.auth.version = (buf[2] << 8) | buf[3]; 684 device.auth.version = (buf[2] << 8) | buf[3];
607 685
608 /* We support authentication versions 1.0 and 2.0 */ 686 /* We only support authentication versions 1.0 and 2.0 */
609 if (device.auth.version == 0x100) { 687 if ((device.auth.version != 0x100) && (device.auth.version != 0x200)) {
610 /* If we could really do authentication we'd have to
611 * check the certificate here. Since we can't, just acknowledge
612 * the packet with an "everything OK" AckDevAuthenticationInfo
613 *
614 * Skip GetAccessoryInfo process, this command together with
615 * authentication level 2 were added in iAP release 24, it is
616 * not be supported by devices authenticating at level 1.
617 */
618 IAP_TX_INIT(0x00, 0x16);
619 IAP_TX_PUT(0x00);
620
621 iap_send_tx();
622 device.auth.state = AUST_CERTDONE;
623 break;
624 }
625
626 if (device.auth.version != 0x200) {
627 /* Version mismatches are signalled by AckDevAuthenticationInfo 688 /* Version mismatches are signalled by AckDevAuthenticationInfo
628 * with the status set to Authentication Information unsupported 689 * with the status set to Authentication Information unsupported
629 */ 690 */
@@ -635,61 +696,77 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
635 iap_send_tx(); 696 iap_send_tx();
636 break; 697 break;
637 } 698 }
638 699 if (device.auth.version == 0x100) {
639 /* There must be at least one byte of certificate data 700 /* If we could really do authentication we'd have to
640 * in the packet 701 * check the certificate here. Since we can't, just acknowledge
641 */ 702 * the packet later with an "everything OK" AckDevAuthenticationInfo
642 CHECKLEN(7); 703 * and change device.auth.state to AuthenticateState_CertificateDone
643
644 switch (device.auth.state)
645 {
646 /* This is the first packet. Note the maximum section number
647 * so we can check it later.
648 */ 704 */
649 case AUST_CERTREQ: 705 device.auth.state = AUST_CERTALLRECEIVED;
706 } else {
707 /* Version 2.00 requires at least one byte of certificate data
708 * in the packet
709 */
710 CHECKLEN(7);
711 switch (device.auth.state)
650 { 712 {
651 device.auth.max_section = buf[5]; 713 /* This is the first packet. Note the maximum section number
652 device.auth.state = AUST_CERTBEG; 714 * so we can check it later.
715 */
716 case AUST_CERTREQ:
717 {
718 device.auth.max_section = buf[5];
719 device.auth.state = AUST_CERTBEG;
653 720
654 /* Intentional fall-through */ 721 /* Intentional fall-through */
655 } 722 }
656 /* All following packets */ 723 /* All following packets */
657 case AUST_CERTBEG: 724 case AUST_CERTBEG:
658 { 725 {
659 /* Check if this is the expected section */ 726 /* Check if this is the expected section */
660 if (buf[4] != device.auth.next_section) { 727 if (buf[4] != device.auth.next_section) {
661 cmd_ack(cmd, IAP_ACK_BAD_PARAM); 728 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
729 break;
730 }
731
732 /* Is this the last section? */
733 if (device.auth.next_section == device.auth.max_section) {
734 /* If we could really do authentication we'd have to
735 * check the certificate here. Since we can't, just acknowledge
736 * the packet later with an "everything OK" AckDevAuthenticationInfo
737 * and change device.auth.state to AuthenticateState_CertificateDone
738 */
739 device.auth.state = AUST_CERTALLRECEIVED;
740 } else {
741 device.auth.next_section++;
742 cmd_ok(cmd);
743 }
662 break; 744 break;
663 } 745 }
664 746 default:
665 /* Is this the last section? */ 747 {
666 if (device.auth.next_section == device.auth.max_section) { 748 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
667 /* If we could really do authentication we'd have to 749 break;
668 * check the certificate here. Since we can't, just acknowledge
669 * the packet with an "everything OK" AckDevAuthenticationInfo
670 *
671 * Also, start GetAccessoryInfo process
672 */
673 IAP_TX_INIT(0x00, 0x16);
674 IAP_TX_PUT(0x00);
675
676 iap_send_tx();
677 device.auth.state = AUST_CERTDONE;
678 device.accinfo = ACCST_INIT;
679 } else {
680 device.auth.next_section++;
681 cmd_ok(cmd);
682 } 750 }
683 break;
684 }
685
686 default:
687 {
688 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
689 break;
690 } 751 }
691 } 752 }
753 if (device.auth.state == AUST_CERTALLRECEIVED) {
754 /* We've received all the certificate data so just
755 *Acknowledge everything OK
756 */
757 IAP_TX_INIT(0x00, 0x16);
758 IAP_TX_PUT(0x00);
759
760 iap_send_tx();
761
762 /* GetAccessoryInfo*/
763 IAP_TX_INIT(0x00, 0x27);
764 IAP_TX_PUT(0x00);
765
766 iap_send_tx();
692 767
768 device.auth.state = AUST_CERTDONE;
769 }
693 break; 770 break;
694 } 771 }
695 772
@@ -744,6 +821,17 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
744 821
745 iap_send_tx(); 822 iap_send_tx();
746 device.auth.state = AUST_AUTH; 823 device.auth.state = AUST_AUTH;
824#if CONFIG_TUNER
825 if (radio_present == 1)
826 {
827 /* GetTunerCaps */
828 IAP_TX_INIT(0x07, 0x01);
829
830 iap_send_tx();
831 }
832#endif
833 iap_set_remote_volume();
834
747 break; 835 break;
748 } 836 }
749 837
@@ -926,7 +1014,9 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
926 CHECKLEN(7); 1014 CHECKLEN(7);
927 1015
928 device.capabilities = get_u32(&buf[0x03]); 1016 device.capabilities = get_u32(&buf[0x03]);
929 /* Type 0x00 was already queried, that's where this information comes from */ 1017 /* Type 0x00 was already queried, that's where this
1018 * information comes from
1019 */
930 device.capabilities_queried = 0x01; 1020 device.capabilities_queried = 0x01;
931 device.capabilities &= ~0x01; 1021 device.capabilities &= ~0x01;
932 break; 1022 break;
@@ -1045,9 +1135,8 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
1045 { 1135 {
1046#ifdef LOGF_ENABLE 1136#ifdef LOGF_ENABLE
1047 logf("iap: Unsupported Mode00 Command"); 1137 logf("iap: Unsupported Mode00 Command");
1048#else
1049 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1050#endif 1138#endif
1139 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1051 break; 1140 break;
1052 } 1141 }
1053 } 1142 }
diff --git a/apps/iap/iap-lingo1.c b/apps/iap/iap-lingo1.c
index 5702500f23..56c52d81ae 100644
--- a/apps/iap/iap-lingo1.c
+++ b/apps/iap/iap-lingo1.c
@@ -212,6 +212,7 @@ void iap_handlepkt_mode1(const unsigned int len, const unsigned char *buf)
212#ifdef LOGF_ENABLE 212#ifdef LOGF_ENABLE
213 logf("iap: Unsupported Mode1 Command"); 213 logf("iap: Unsupported Mode1 Command");
214#endif 214#endif
215 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
215 break; 216 break;
216 } 217 }
217 } 218 }
diff --git a/apps/iap/iap-lingo2.c b/apps/iap/iap-lingo2.c
index d4c2f18c2f..946e51222d 100644
--- a/apps/iap/iap-lingo2.c
+++ b/apps/iap/iap-lingo2.c
@@ -30,6 +30,10 @@
30#include "button.h" 30#include "button.h"
31#include "audio.h" 31#include "audio.h"
32#include "settings.h" 32#include "settings.h"
33#include "tuner.h"
34#if CONFIG_TUNER
35#include "ipod_remote_tuner.h"
36#endif
33 37
34/* 38/*
35 * This macro is meant to be used inside an IAP mode message handler. 39 * This macro is meant to be used inside an IAP mode message handler.
@@ -57,6 +61,9 @@ static void cmd_ack(const unsigned char cmd, const unsigned char status)
57void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf) 61void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
58{ 62{
59 static bool poweron_pressed = false; 63 static bool poweron_pressed = false;
64#if CONFIG_TUNER
65 static bool remote_mute = false;
66#endif
60 unsigned int cmd = buf[1]; 67 unsigned int cmd = buf[1];
61 68
62 /* We expect at least three bytes in the buffer, one for the 69 /* We expect at least three bytes in the buffer, one for the
@@ -95,7 +102,21 @@ void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
95 if(buf[2] != 0) 102 if(buf[2] != 0)
96 { 103 {
97 if(buf[2] & 1) 104 if(buf[2] & 1)
105 {
98 REMOTE_BUTTON(BUTTON_RC_PLAY); 106 REMOTE_BUTTON(BUTTON_RC_PLAY);
107#if CONFIG_TUNER
108 if (radio_present == 1) {
109 if (remote_mute == 0) {
110 /* Not Muted so radio on*/
111 tuner_set(RADIO_MUTE,0);
112 } else {
113 /* Muted so radio off*/
114 tuner_set(RADIO_MUTE,1);
115 }
116 remote_mute = !remote_mute;
117 }
118#endif
119 }
99 if(buf[2] & 2) 120 if(buf[2] & 2)
100 REMOTE_BUTTON(BUTTON_RC_VOL_UP); 121 REMOTE_BUTTON(BUTTON_RC_VOL_UP);
101 if(buf[2] & 4) 122 if(buf[2] & 4)
@@ -111,11 +132,21 @@ void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
111 { 132 {
112 if (audio_status() != AUDIO_STATUS_PLAY) 133 if (audio_status() != AUDIO_STATUS_PLAY)
113 REMOTE_BUTTON(BUTTON_RC_PLAY); 134 REMOTE_BUTTON(BUTTON_RC_PLAY);
135#if CONFIG_TUNER
136 if (radio_present == 1) {
137 tuner_set(RADIO_MUTE,0);
138 }
139#endif
114 } 140 }
115 if(buf[3] & 2) /* pause */ 141 if(buf[3] & 2) /* pause */
116 { 142 {
117 if (audio_status() == AUDIO_STATUS_PLAY) 143 if (audio_status() == AUDIO_STATUS_PLAY)
118 REMOTE_BUTTON(BUTTON_RC_PLAY); 144 REMOTE_BUTTON(BUTTON_RC_PLAY);
145#if CONFIG_TUNER
146 if (radio_present == 1) {
147 tuner_set(RADIO_MUTE,1);
148 }
149#endif
119 } 150 }
120 if(buf[3] & 128) /* Shuffle */ 151 if(buf[3] & 128) /* Shuffle */
121 { 152 {
@@ -295,9 +326,8 @@ void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
295 { 326 {
296#ifdef LOGF_ENABLE 327#ifdef LOGF_ENABLE
297 logf("iap: Unsupported Mode02 Command"); 328 logf("iap: Unsupported Mode02 Command");
298#else
299 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
300#endif 329#endif
330 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
301 break; 331 break;
302 } 332 }
303 } 333 }
diff --git a/apps/iap/iap-lingo3.c b/apps/iap/iap-lingo3.c
index 0ed3df118e..c7801fbce0 100644
--- a/apps/iap/iap-lingo3.c
+++ b/apps/iap/iap-lingo3.c
@@ -38,6 +38,9 @@
38#include "settings.h" 38#include "settings.h"
39#include "metadata.h" 39#include "metadata.h"
40#include "playback.h" 40#include "playback.h"
41#if CONFIG_TUNER
42#include "ipod_remote_tuner.h"
43#endif
41 44
42/* 45/*
43 * This macro is meant to be used inside an IAP mode message handler. 46 * This macro is meant to be used inside an IAP mode message handler.
@@ -262,7 +265,7 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf)
262 device.play_status = audio_status(); 265 device.play_status = audio_status();
263 /* TODO: Fix this */ 266 /* TODO: Fix this */
264 device.mute = false; 267 device.mute = false;
265 device.volume = 0x80; 268 device.volume = global_settings.volume;
266 device.power_state = charger_input_state; 269 device.power_state = charger_input_state;
267 device.battery_level = battery_level(); 270 device.battery_level = battery_level();
268 /* TODO: Fix this */ 271 /* TODO: Fix this */
@@ -299,8 +302,8 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf)
299 302
300 /* GetRemoteEventStatus (0x0A) 303 /* GetRemoteEventStatus (0x0A)
301 * 304 *
302 * Request the events changed since the last call to GetREmoteEventStatus 305 * Request the events changed since the last call to
303 * or SetRemoteEventNotification 306 * GetREmoteEventStatus or SetRemoteEventNotification
304 * 307 *
305 * Packet format (offset in buf[]: Description) 308 * Packet format (offset in buf[]: Description)
306 * 0x00: Lingo ID: Display Remote Lingo, always 0x03 309 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
@@ -434,15 +437,18 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf)
434 */ 437 */
435 case 0x04: 438 case 0x04:
436 { 439 {
437 /* Figuring out what the current volume is 440 if (device.mute == false) {
438 * seems to be tricky. 441 /* Mute status False*/
439 * TODO: Fix. 442 IAP_TX_PUT(0x00);
440 */ 443 /* Volume */
444 IAP_TX_PUT(0xFF & (int)((global_settings.volume + 90) * 2.65625));
441 445
442 /* Mute status */ 446 } else {
443 IAP_TX_PUT(0x00); 447 /* Mute status True*/
444 /* Volume */ 448 IAP_TX_PUT(0x01);
445 IAP_TX_PUT(0x80); 449 /* Volume should be 0 if muted */
450 IAP_TX_PUT(0x00);
451 }
446 452
447 iap_send_tx(); 453 iap_send_tx();
448 break; 454 break;
@@ -620,15 +626,24 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf)
620 */ 626 */
621 case 0x10: 627 case 0x10:
622 { 628 {
623 /* TODO: See volume above */ 629 if (device.mute == false) {
624 IAP_TX_PUT(0x00); 630 /* Mute status False*/
625 IAP_TX_PUT(0x80); 631 IAP_TX_PUT(0x00);
626 IAP_TX_PUT(0x80); 632 /* Volume */
633 IAP_TX_PUT(0xFF & (int)((global_settings.volume + 90) * 2.65625));
634 IAP_TX_PUT(0xFF & (int)((global_settings.volume + 90) * 2.65625));
635
636 } else {
637 /* Mute status True*/
638 IAP_TX_PUT(0x01);
639 /* Volume should be 0 if muted */
640 IAP_TX_PUT(0x00);
641 IAP_TX_PUT(0x00);
642 }
627 643
628 iap_send_tx(); 644 iap_send_tx();
629 break; 645 break;
630 } 646 }
631
632 default: 647 default:
633 { 648 {
634 cmd_ack(cmd, IAP_ACK_BAD_PARAM); 649 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
@@ -746,14 +761,18 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf)
746 break; 761 break;
747 } 762 }
748 763
749 /* Volume/Mute
750 * Data length: 2
751 * TODO: Fix this
752 */
753 case 0x04: 764 case 0x04:
754 { 765 {
755 CHECKLEN(5); 766 CHECKLEN(5);
756 cmd_ack(cmd, IAP_ACK_CMD_FAILED); 767 if (buf[0x03]==0x00){
768 /* Not Muted */
769 global_settings.volume = (int) (buf[0x04]/2.65625)-90;
770 device.mute = false;
771 }
772 else {
773 device.mute = true;
774 }
775 cmd_ok(cmd);
757 break; 776 break;
758 } 777 }
759 778
@@ -919,7 +938,16 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf)
919 case 0x10: 938 case 0x10:
920 { 939 {
921 CHECKLEN(7); 940 CHECKLEN(7);
922 cmd_ack(cmd, IAP_ACK_CMD_FAILED); 941 if (buf[0x03]==0x00){
942 /* Not Muted */
943 global_settings.volume = (int) (buf[0x04]/2.65625)-90;
944 device.mute = false;
945 }
946 else {
947 device.mute = true;
948 }
949
950 cmd_ok(cmd);
923 break; 951 break;
924 } 952 }
925 953
@@ -1499,9 +1527,8 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf)
1499 { 1527 {
1500#ifdef LOGF_ENABLE 1528#ifdef LOGF_ENABLE
1501 logf("iap: Unsupported Mode03 Command"); 1529 logf("iap: Unsupported Mode03 Command");
1502#else
1503 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1504#endif 1530#endif
1531 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1505 break; 1532 break;
1506 } 1533 }
1507 } 1534 }
diff --git a/apps/iap/iap-lingo4.c b/apps/iap/iap-lingo4.c
index 903cef9378..b601501b3d 100644
--- a/apps/iap/iap-lingo4.c
+++ b/apps/iap/iap-lingo4.c
@@ -109,9 +109,8 @@ static void seek_to_playlist(unsigned long index)
109 ft_play_playlist(selected_playlist, 109 ft_play_playlist(selected_playlist,
110 global_settings.playlist_catalog_dir, 110 global_settings.playlist_catalog_dir,
111 strrchr(selected_playlist, '/') + 1); 111 strrchr(selected_playlist, '/') + 1);
112
113} 112}
114 113
115static unsigned long nbr_total_playlists(void) 114static unsigned long nbr_total_playlists(void)
116{ 115{
117 DIR* dp; 116 DIR* dp;
@@ -161,7 +160,7 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf)
161 switch (cmd) 160 switch (cmd)
162 { 161 {
163 case 0x0001: /* CmdAck. See above cmd_ack() */ 162 case 0x0001: /* CmdAck. See above cmd_ack() */
164 /* 163 /*
165 * The following is the description for the Apple Firmware 164 * The following is the description for the Apple Firmware
166 * The iPod sends this telegram to acknowledge the receipt of a 165 * The iPod sends this telegram to acknowledge the receipt of a
167 * command and return the command status. The command ID field 166 * command and return the command status. The command ID field
@@ -1457,7 +1456,7 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf)
1457 case 0x05: /* Tracks */ 1456 case 0x05: /* Tracks */
1458 case 0x02: /* Artists */ 1457 case 0x02: /* Artists */
1459 case 0x03: /* Albums */ 1458 case 0x03: /* Albums */
1460 case 0x04: /* Genre */ 1459 case 0x04: /* Genre */
1461 case 0x06: /* Composer */ 1460 case 0x06: /* Composer */
1462 playlist_get_track_info(NULL, start_index + counter, 1461 playlist_get_track_info(NULL, start_index + counter,
1463 &track); 1462 &track);
@@ -2019,8 +2018,8 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf)
2019 playlist_randomise(NULL, current_tick, true); 2018 playlist_randomise(NULL, current_tick, true);
2020 } 2019 }
2021 else 2020 else
2022 { 2021 {
2023 playlist_sort(NULL, true); 2022 playlist_sort(NULL, true);
2024 } 2023 }
2025 audio_skip(index - playlist_next(0)); 2024 audio_skip(index - playlist_next(0));
2026 if (!paused) 2025 if (!paused)
diff --git a/apps/iap/iap-lingo7.c b/apps/iap/iap-lingo7.c
new file mode 100644
index 0000000000..467a81cc76
--- /dev/null
+++ b/apps/iap/iap-lingo7.c
@@ -0,0 +1,491 @@
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#include "iap-core.h"
20#include "iap-lingo.h"
21#include "kernel.h"
22#include "system.h"
23#include "tuner.h"
24#if CONFIG_TUNER
25#include "ipod_remote_tuner.h"
26#endif
27
28/*
29 * This macro is meant to be used inside an IAP mode message handler.
30 * It is passed the expected minimum length of the message inbufferfer.
31 * If the inbufferfer does not have the required lenght an ACK
32 * packet with a Bad Parameter error is generated.
33 */
34#define CHECKLEN(x) do { \
35 if (len < (x)) { \
36 cmd_ack(cmd, IAP_ACK_BAD_PARAM); \
37 return; \
38 }} while(0)
39
40/* Check for authenticated state, and return an ACK Not
41 * Authenticated on failure.
42 */
43#define CHECKAUTH do { \
44 if (!DEVICE_AUTHENTICATED) { \
45 cmd_ack(cmd, IAP_ACK_NO_AUTHEN); \
46 return; \
47 }} while(0)
48
49
50static void cmd_ack(const unsigned char cmd, const unsigned char status)
51{
52 IAP_TX_INIT(0x07, 0x00);
53 IAP_TX_PUT(status);
54 IAP_TX_PUT(cmd);
55
56 iap_send_tx();
57}
58
59#define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK)
60
61void iap_handlepkt_mode7(const unsigned int len, const unsigned char *inbuffer)
62{
63 /* Note that some of the Lingo Mode 7 commands are handled by
64 * ../firmware/drivers/tuner/ipod_remote_tuner.c as some of the
65 * commands are sourced with the remote as the master with the ipod acting
66 * as the slave.
67 */
68 unsigned char cmd = inbuffer[1];
69 unsigned char statusnotifymaskbyte = 0;
70
71 /* We expect at least two bytes in the inbuffer, one for the
72 * lingo and one for the command
73 */
74 CHECKLEN(2);
75
76 /* Lingo 0x07 must have been negotiated */
77 if (!DEVICE_LINGO_SUPPORTED(0x07)) {
78 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
79 return;
80 }
81
82 switch (cmd)
83 {
84 /* case 00 ToIpod Ack 2/6 bytes*/
85 case 0x00:
86 {
87 /* 0x00 OK
88 * 0x01 Unknown Track Category
89 * 0x02 Command Failed. Command is valid but did not succeed
90 * 0x03 Out Of Resources
91 * 0x04 Bad Parameter
92 * 0x05 Unknown Track ID
93 * 0x06 Command Pending.
94 * 0x07 Not Authenticated
95 *
96 * byte 1 is ID of command being acknowledged
97 * bytes 2-5 only if status byte is pending. timeout in ms.
98 */
99 break;
100 }
101
102 /* case 0x01 ToAccessory GetTunerCaps
103 * This is sent by iap-lingo0.c through case 0x15 after device
104 * has been authenticated FF55020701F6
105 */
106
107 /* case 02 ToIpod RetTunerCaps 8 bytes */
108 case 0x02:
109 {
110 /* Capabilities are stored as bits in first 4 bytes,
111 * inbuffer[2] byte is bits 31:24
112 * inbuffer[3] byte is bits 23:16
113 * inbuffer[4] byte is bits 15:08
114 * inbuffer[5] byte is bits 07:00
115 * inbuffer[6] and inbuffer[7] are all reserved bits
116 * Bit 0 = AM Band 520-1710 Khz
117 * Bit 1 = FM Europe/US 87.5 - 108.0 Mhz
118 * Bit 2 = FM Japan 76.0 - 90.0 Mhz
119 * Bit 3 = FM Wide 76.0 - 108.0 Mhz
120 * Bit 4 = HD Radio Capable
121 * Bit 5:7 Reserved
122 * Bit 8 = Tuner Power On/Off Control Capable
123 * Bit 9 = Status Change Notification Capable
124 * Bit 10:15 Reserved
125 * Bit 17:16 Minimum FM Resolution ID Bits
126 * 00 = 200Khz, 01 = 100Khz, 10 = 50Khz, 11 = reserved
127 * Bit 18 = Tuner Seek Up/Down Capable
128 * Bit 19 = Tuner Seek RSSI Threshold. Only if 18=1
129 * Bit 20 = Force Monophonic mode capable
130 * Bit 21 = Stero Blend Capable
131 * Bit 22 = FM Tuner deemphasis select capable
132 * Bit 23 = AM Tuner Resolution 9Khz (0=10Khz Only) capable
133 * Bit 24 = Radio Data System (RDS/RBDS) data capable
134 * Bit 25 = Tuner Channel RSSI indicator capable
135 * Bit 26 = Stero Source Indicator capable
136 * Bit 27 = RDS/RBDS Raw mode capable
137 * Bit 31:28 Reserved
138 *
139 * ipod Tuner returns 07 5E 07 0E 10 4B
140 * Bytes 6,7 Reserved
141 * ???????? ????????
142 * ???????? ????????
143 * 00010000 01001011
144 *
145 * Byte 5 - 0E
146 * 00000000
147 * 76543210
148 * 00001110
149 * AM
150 * FM Europe/US
151 * FM Japan
152 * FM Wide
153 *
154 * Byte 4 - 07
155 * 11111100
156 * 54321098
157 * 00000111
158 * Tuner Power On/Off
159 * Status Change Notification
160 * ?? Should be reserved
161 *
162 * Byte 3 - 5E
163 * 22221111
164 * 32109876
165 * 01011110
166 * Tuner Seek Up/Down
167 * Tuner Seek RSSI Threshold
168 * Force Mono Mode Capable
169 * Stereo Blend Capable
170 * FM Tuner deemphasis select capable
171 *
172 * Byte 2 - 07
173 * 33222222
174 * 10987654
175 * 00000111
176 * RDS/RBDS Capable
177 * Tuner Channel RSSI Indicator
178 * Stereo Source
179 *
180 * Just need to see what we can use this data for
181 * Make a selection for the tuner mode to select
182 * Preference is
183 * 1st - 76 to 108 FM
184 * 2nd - 87.5 to 108 Fm
185 * 3rd - 76 to 90 Fm
186 * 4th - AM
187 *
188 */
189
190 if ((inbuffer[4] & 0x03) >0) {
191 statusnotifymaskbyte = 0;
192 if ((inbuffer[4] >> 0) & 0x01) {
193 /* Supports Tuner Power On/Off, so set ON */
194 statusnotifymaskbyte = 1;
195 }
196 if ((inbuffer[4] >> 1) & 0x01) {
197 /* Supports Status Change Notification so set ON */
198 /* Apple 5/6/7G firmware does NOT enable this bit */
199 /* statusnotifymaskbyte += 2; */
200 }
201 IAP_TX_INIT(0x07, 0x05);
202 IAP_TX_PUT(statusnotifymaskbyte);
203 iap_send_tx();
204 }
205 if ((inbuffer[5] >> 1) & 0x01) {
206 /* Supports FM Europe/US Tuner 87.5 - 108.0 Mhz */
207 /* Apple firmware sends this before setting region */
208 IAP_TX_INIT(0x07, 0x0E);
209 IAP_TX_PUT(0x00);
210 iap_send_tx();
211 /* Apple firmware then sends region */
212 IAP_TX_INIT(0x07, 0x08);
213 IAP_TX_PUT(0x02);
214 iap_send_tx();
215 } else if ((inbuffer[5] >> 3) & 0x01) {
216 /* Supports FM Wide Tuner 76 - 108.0 Mhz */
217 /* apple firmware send this before setting region */
218 IAP_TX_INIT(0x07, 0x0E);
219 IAP_TX_PUT(0x00);
220 iap_send_tx();
221 /* Apple firmware then send region */
222 IAP_TX_INIT(0x07, 0x08);
223 IAP_TX_PUT(0x08);
224 iap_send_tx();
225 } else if ((inbuffer[5] >> 2) & 0x01) {
226 /* Supports FM Japan Tuner 76 - 90.0 Mhz */
227 /* apple firmware send this before setting region */
228 IAP_TX_INIT(0x07, 0x0E);
229 IAP_TX_PUT(0x41);
230 iap_send_tx();
231 /* Apple firmware then send region */
232 IAP_TX_INIT(0x07, 0x08);
233 IAP_TX_PUT(0x04);
234 iap_send_tx();
235 } else if ((inbuffer[5] >> 0) & 0x01) {
236 /* Supports AM Tuner */
237 IAP_TX_INIT(0x07, 0x08);
238 IAP_TX_PUT(0x01);
239 iap_send_tx();
240 }
241
242 if ((inbuffer[2] & 0x03) > 0) {
243 statusnotifymaskbyte = 0;
244 if ((inbuffer[2] >> 0) & 0x01) {
245 /* Supports RDS/RBDS Capable so set
246 *StatusChangeNotify for RDS/RBDS Data
247 */
248 statusnotifymaskbyte = 1;
249 }
250 if ((inbuffer[2] >> 1) & 0x01) {
251 /* Supports Tuner Channel RSSi Indicator Capable so set */
252 /* StatusChangeNotify for RSSI */
253 /* Apple 5G firmware does NOT enable this bit so we wont */
254 /* statusnotifymaskbyte += 2; */
255 }
256 IAP_TX_INIT(0x07, 0x18);
257 IAP_TX_PUT(statusnotifymaskbyte);
258 iap_send_tx();
259 }
260
261 if ((inbuffer[4] >> 2) & 0x01) {
262 /* Reserved */
263 }
264 if ((inbuffer[4] >> 3) & 0x01) {
265 /* Reserved */
266 }
267 if ((inbuffer[3] >> 1) & 0x01) {
268 /* Tuner Seek Up/Down` */
269 }
270 if ((inbuffer[3] >> 2) & 0x01) {
271 /* Tuner Seek RSSI Threshold */
272 }
273 if ((inbuffer[3] >> 3) & 0x01) {
274 /* Force Mono Mode */
275 }
276 if ((inbuffer[3] >> 4) & 0x01) {
277 /* Stereo Blend */
278 }
279 if ((inbuffer[3] >> 6) & 0x01) {
280 /* FM Tuner deemphasis */
281 }
282 if ((inbuffer[2] >> 2) & 0x01) {
283 /* Stereo Source */
284 }
285 break;
286 }
287 /* case 03 ToAccessory GetTunerCtrl 2 bytes */
288
289 /* case 04 ToIpod RetTunerCtrl 3 bytes
290 * Bit 0 power is on (1) or Off (0)
291 * Bit 1 StatusChangeNotify is enabled (1) or disabled (0)
292 * Bit 3 RDS/RBDS Raw mode enabled
293 *
294 * Should/Can we do something with these?
295 */
296
297 /* case 05 ToAccessory SetTunerCtrl 3 bytes
298 * Bits as per 0x04 above
299 * Bit 0/1 set through Lingo7 Cmd02 */
300
301 /* case 06 ToAccessory GetTunerBand 2 bytes */
302
303 /* case 07 ToIpod RetTunerBand 3 bytes
304 * Returns current band for Tuner. See 0x08 below
305 *
306 * Should/Can we do something with these?
307 */
308
309 /* case 08 ToAccessory SetTuneBand
310 * Set Bit 0 for AM
311 * Set Bit 1 for FM Europe/U S 87.5-108Mhz
312 * Set Bit 2 for FM JApan 76.0-90.0Mhz
313 * Set Bit 3 for FM Wide 76.0-108Mhz
314 * Currently we send this after receiving capabilities
315 * on 0x02 above
316 */
317
318 /* case 09 ToAccessory GetTunerFreq 2 bytes */
319
320 /* case 0A ToIpod RetTunerFreq 7 bytes */
321 case 0x0A:
322 {
323 /* Returns Frequency set and RSSI Power Levels
324 * These are sent as is to rmt_tuner_freq() in
325 * ../firmware/drivers/tuner/ipod_remote_tuner.c */
326 rmt_tuner_freq(len, inbuffer);
327 break;
328 }
329
330 /* case 0B ToAccessory SetTunerFreq 6 bytes */
331
332 /* case 0C ToAccessory GetTunerMode 2 bytes */
333
334 /* case 0D ToIpod RetTunerMode 3 bytes
335 * Returns Tuner Mode Status in 8 bits as follows
336 * Bit 1:0 - FM Tuner Resolution
337 * Bit 2 Tuner is seeking up or down
338 * Bit 3 Tuner is seeking with RSSI min theshold enabled
339 * Bit 4 Force Mono Mode (1) or allow stereo (0)
340 * Bit 5 Stereo Blend enabled. Valid only if Bit 4 is 0
341 * Bit 6 FM Tuner Deemphasis 50uS (1) or 75uS (0)
342 * Bit 7 Reserved 0
343 */
344
345 /* case 0E ToAccessory SetTunerMode 3 bytes
346 * See 0x0D for Bit Descriptions
347 * Bits set by Cmd 02
348 */
349
350 /* case 0F ToAccessory GetTunerSeekRssi 2 bytes */
351
352 /* case 10 ToIpod RetTunerSeekRssi 3 bytes
353 * Returns RSSI Value for seek operations
354 * value is 0 (min) - 255 (max)
355 */
356
357 /* case 11 ToAccessory SetTunerSeekRssi 3 bytes */
358
359 /* case 12 ToAccessory TunerSeekStart 3 bytes */
360
361 /* case 13 ToIpod TunerSeekDone 7 bytes */
362 case 0x13:
363 {
364 rmt_tuner_freq(len, inbuffer);
365 break;
366 }
367
368 /* case 14 ToAccessory GetTunerStatus 2 bytes */
369
370 /* case 15 ToIpod RetTunerStatus 3 bytes */
371
372 /* case 16 ToAccessory GetStatusNotifyMask 2 bytes */
373
374 /* case 17 ToIpod RetStatusNotifyMask 3 bytes */
375
376 /* case 18 ToAccessory SetStatusNotifyMask 3 bytes
377 * This is set by Cmd 02
378 */
379
380 /* case 19 ToIpod StatusChangeNotify 3 bytes */
381 case 0x19:
382 {
383 /* Returns StatusChangeNotify bits to ipod.
384 * Bit 0 set for RDS/RBDS data ready
385 * Bit 1 set for Tuner RSSI level change
386 * Bit 2 for Stereo Indicator changed
387 * If any of these are set we will request the data
388 * need to look at using these
389 */
390 break;
391 }
392
393 /* case 1A ToAccessory GetRdsReadyStatus 2 bytes */
394
395 /* case 1B ToIpod RetRdsReadyStatus 6 bytes */
396 case 0x1B:
397 {
398 break;
399 }
400 /* case 1C ToAccessory GetRdsData 3 bytes */
401
402 /* case 1D ToIpod RetRdsData NN bytes */
403 case 0x1D:
404 {
405 rmt_tuner_rds_data(len, inbuffer);
406 break;
407 }
408
409 /* case 1E ToAccessory GetRdsNotifyMask 2 bytes*/
410
411 /* case 1F ToIpod RetRdsNotifyMask 6 Bytes*/
412 case 0x1F:
413 {
414 break;
415 }
416
417 /* case 20 ToAccessory SetRdsNotifyMask 6 bytes */
418
419 /* case 21 ToIpod RdsReadyNotify NN bytes */
420 case 0x21:
421 {
422 rmt_tuner_rds_data(len, inbuffer);
423 break;
424 }
425 /* case 22 Reserved */
426
427 /* case 23 Reserved */
428
429 /* case 24 Reserved */
430
431 /* case 25 ToAccessory GetHDProgramServiceCount 0 bytes */
432
433 /* case 26 ToIpod RetHDProgramServiceCount 1 bytes */
434 case 0x26:
435 {
436 break;
437 }
438
439 /* case 27 ToAccessory GetHDProgramService 0 bytes */
440
441 /* case 28 ToIpod RetHDProgramService 1 bytes */
442 case 0x28:
443 {
444 break;
445 }
446
447 /* case 29 ToAccessory SetHDProgramService 1 bytes */
448
449 /* case 2A ToAccessory GetHDDataReadyStatus 0 bytes */
450
451 /* case 2B ToIpod RetHDDataReadyStatus 4 bytes */
452 case 0x2B:
453 {
454 break;
455 }
456
457 /* case 2C ToAccessory GetHDData 1 bytes */
458
459 /* case 2D ToIpod RetHDData NN bytes */
460 case 0x2D:
461 {
462 break;
463 }
464
465 /* case 2E ToAccessory GetHDDataNotifyMask 0 bytes */
466
467 /* case 2F ToIpod RetHDDataNotifyMask 4 bytes */
468 case 0x2F:
469 {
470 break;
471 }
472
473 /* case 30 ToAccessory SetHDDataNotifyMask 4 bytes */
474
475 /* case 31 ToIpod HDDataReadyNotify NN bytes */
476 case 0x31:
477 {
478 break;
479 }
480
481 /* The default response is IAP_ACK_BAD_PARAM */
482 default:
483 {
484#ifdef LOGF_ENABLE
485 logf("iap: Unsupported Mode07 Command");
486#endif
487 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
488 break;
489 }
490 }
491}