summaryrefslogtreecommitdiff
path: root/apps/iap
diff options
context:
space:
mode:
Diffstat (limited to 'apps/iap')
-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
9 files changed, 834 insertions, 178 deletions
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}