diff options
-rw-r--r-- | apps/SOURCES | 4 | ||||
-rw-r--r-- | apps/iap/iap-core.c | 115 | ||||
-rw-r--r-- | apps/iap/iap-core.h | 19 | ||||
-rw-r--r-- | apps/iap/iap-lingo.h | 3 | ||||
-rw-r--r-- | apps/iap/iap-lingo0.c | 263 | ||||
-rw-r--r-- | apps/iap/iap-lingo1.c | 1 | ||||
-rw-r--r-- | apps/iap/iap-lingo2.c | 34 | ||||
-rw-r--r-- | apps/iap/iap-lingo3.c | 75 | ||||
-rw-r--r-- | apps/iap/iap-lingo4.c | 11 | ||||
-rw-r--r-- | apps/iap/iap-lingo7.c | 491 | ||||
-rw-r--r-- | firmware/drivers/tuner/ipod_remote_tuner.c | 76 |
11 files changed, 896 insertions, 196 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 | |||
70 | iap/iap-lingo2.c | 70 | iap/iap-lingo2.c |
71 | iap/iap-lingo3.c | 71 | iap/iap-lingo3.c |
72 | iap/iap-lingo4.c | 72 | iap/iap-lingo4.c |
73 | #if CONFIG_TUNER | ||
74 | iap/iap-lingo7.c | ||
75 | #endif | ||
73 | #endif | 76 | #endif |
74 | |||
75 | screen_access.c | 77 | screen_access.c |
76 | #ifdef HAVE_BUTTONBAR | 78 | #ifdef HAVE_BUTTONBAR |
77 | gui/buttonbar.c | 79 | gui/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 | |||
320 | void 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 | ||
1216 | static 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 | |||
1252 | void iap_handlepkt(void) | 1261 | void 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 */ |
75 | enum authen_state { | 76 | enum 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); | |||
237 | void iap_fill_power_state(void); | 239 | void iap_fill_power_state(void); |
238 | 240 | ||
239 | void iap_send_tx(void); | 241 | void iap_send_tx(void); |
242 | void iap_set_remote_volume(void); | ||
240 | 243 | ||
241 | extern enum interface_state interface_state; | 244 | extern enum interface_state interface_state; |
242 | void iap_interface_state_change(const enum interface_state new); | 245 | void 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); | |||
24 | void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf); | 24 | void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf); |
25 | void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf); | 25 | void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf); |
26 | void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf); | 26 | void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf); |
27 | #if CONFIG_TUNER | ||
28 | void 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 | ||
46 | static void cmd_ack(const unsigned char cmd, const unsigned char status) | 50 | static 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) | |||
57 | void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf) | 61 | void 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 | ||
115 | static unsigned long nbr_total_playlists(void) | 114 | static 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 | |||
50 | static 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 | |||
61 | void 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 | } | ||
diff --git a/firmware/drivers/tuner/ipod_remote_tuner.c b/firmware/drivers/tuner/ipod_remote_tuner.c index 9595939f1d..5539b09721 100644 --- a/firmware/drivers/tuner/ipod_remote_tuner.c +++ b/firmware/drivers/tuner/ipod_remote_tuner.c | |||
@@ -69,7 +69,7 @@ static void rmt_tuner_set_freq(int curr_freq) | |||
69 | rds_reset(); | 69 | rds_reset(); |
70 | /* ex: 00 01 63 14 = 90.9MHz */ | 70 | /* ex: 00 01 63 14 = 90.9MHz */ |
71 | unsigned char data[] = {0x07, 0x0B, 0x00, 0x01, 0x63, 0x14}; | 71 | unsigned char data[] = {0x07, 0x0B, 0x00, 0x01, 0x63, 0x14}; |
72 | 72 | ||
73 | if (curr_freq != 0) | 73 | if (curr_freq != 0) |
74 | { | 74 | { |
75 | unsigned int khz = curr_freq / 1000; | 75 | unsigned int khz = curr_freq / 1000; |
@@ -93,20 +93,23 @@ static void rmt_tuner_sleep(int state) | |||
93 | old_region = -1; | 93 | old_region = -1; |
94 | tuner_frequency = 0; | 94 | tuner_frequency = 0; |
95 | radio_tuned = false; | 95 | radio_tuned = false; |
96 | 96 | ||
97 | /* tuner HW on */ | 97 | /* tuner HW on */ |
98 | const unsigned char data[] = {0x07, 0x05, 0x01}; | 98 | const unsigned char data[] = {0x07, 0x05, 0x01}; |
99 | iap_send_pkt(data, sizeof(data)); | 99 | iap_send_pkt(data, sizeof(data)); |
100 | /* set rds on */ | ||
101 | const unsigned char data3[] = {0x07, 0x20, 0x40, 0x00, 0x00, 0x10 }; | ||
102 | iap_send_pkt(data3, sizeof(data3)); | ||
100 | /* boost gain */ | 103 | /* boost gain */ |
101 | const unsigned char data1[] = {0x07, 0x24, 0x06 }; | 104 | const unsigned char data1[] = {0x07, 0x24, 0x06 }; |
102 | iap_send_pkt(data1, sizeof(data1)); | 105 | iap_send_pkt(data1, sizeof(data1)); |
106 | /* tuner mode */ | ||
107 | const unsigned char data4[] = {0x07, 0x0E, 0x00 }; | ||
108 | iap_send_pkt(data4, sizeof(data3)); | ||
103 | /* set volume */ | 109 | /* set volume */ |
104 | unsigned char data2[] = {0x03, 0x09, 0x04, 0x00, 0x00 }; | 110 | unsigned char data2[] = {0x03, 0x09, 0x04, 0x00, 0x00 }; |
105 | data2[4] = (char)((global_settings.volume+58) * 4); | 111 | data2[4] = (char)((global_settings.volume+58) * 4); |
106 | iap_send_pkt(data2, sizeof(data2)); | 112 | iap_send_pkt(data2, sizeof(data2)); |
107 | /* set rds on */ | ||
108 | const unsigned char data3[] = {0x07, 0x20, 0x40, 0x00, 0x00, 0x10 }; | ||
109 | iap_send_pkt(data3, sizeof(data3)); | ||
110 | } | 113 | } |
111 | else | 114 | else |
112 | { | 115 | { |
@@ -115,14 +118,14 @@ static void rmt_tuner_sleep(int state) | |||
115 | iap_send_pkt(data, sizeof(data)); | 118 | iap_send_pkt(data, sizeof(data)); |
116 | /* set rds off */ | 119 | /* set rds off */ |
117 | const unsigned char data1[] = {0x07, 0x20, 0x00, 0x00, 0x00, 0x00 }; | 120 | const unsigned char data1[] = {0x07, 0x20, 0x00, 0x00, 0x00, 0x00 }; |
118 | iap_send_pkt(data1, sizeof(data1)); | 121 | iap_send_pkt(data1, sizeof(data1)); |
119 | /* stop tuner HW */ | 122 | /* stop tuner HW */ |
120 | const unsigned char data2[] = {0x07, 0x05, 0x00}; | 123 | const unsigned char data2[] = {0x07, 0x05, 0x00}; |
121 | iap_send_pkt(data2, sizeof(data2)); | 124 | iap_send_pkt(data2, sizeof(data2)); |
122 | } | 125 | } |
123 | } | 126 | } |
124 | 127 | ||
125 | static void rmt_tuner_scan(int param) | 128 | void rmt_tuner_scan(int param) |
126 | { | 129 | { |
127 | const unsigned char data[] = {0x07, 0x11, 0x08}; /* RSSI level */ | 130 | const unsigned char data[] = {0x07, 0x11, 0x08}; /* RSSI level */ |
128 | unsigned char updown = 0x00; | 131 | unsigned char updown = 0x00; |
@@ -148,13 +151,23 @@ static void rmt_tuner_scan(int param) | |||
148 | static void rmt_tuner_mute(int value) | 151 | static void rmt_tuner_mute(int value) |
149 | { | 152 | { |
150 | /* mute flag off (play) */ | 153 | /* mute flag off (play) */ |
151 | unsigned char data[] = {0x03, 0x09, 0x03, 0x01}; | 154 | /* The Apple Tuner does NOT appear to support muting. The Apple |
155 | * firmware turns the power off when pressing pause on the iPod | ||
156 | * or on the Tuner Remote. | ||
157 | */ | ||
152 | if (value) | 158 | if (value) |
153 | { | 159 | { |
154 | /* mute flag on (pause) */ | 160 | /* mute flag on (pause) */ |
155 | data[3] = 0x02; | 161 | unsigned char data[] = {0x03, 0x09, 0x03, 0x02}; |
162 | iap_send_pkt(data, sizeof(data)); | ||
163 | rmt_tuner_sleep(1); | ||
164 | } | ||
165 | else | ||
166 | { | ||
167 | unsigned char data[] = {0x03, 0x09, 0x03, 0x01}; | ||
168 | iap_send_pkt(data, sizeof(data)); | ||
169 | rmt_tuner_sleep(0); | ||
156 | } | 170 | } |
157 | iap_send_pkt(data, sizeof(data)); | ||
158 | } | 171 | } |
159 | 172 | ||
160 | static void rmt_tuner_region(int region) | 173 | static void rmt_tuner_region(int region) |
@@ -163,13 +176,20 @@ static void rmt_tuner_region(int region) | |||
163 | { | 176 | { |
164 | const struct fm_region_data *rd = &fm_region_data[region]; | 177 | const struct fm_region_data *rd = &fm_region_data[region]; |
165 | unsigned char data[] = {0x07, 0x08, 0x00}; | 178 | unsigned char data[] = {0x07, 0x08, 0x00}; |
179 | /* Apple MFi Accessory Firmware Spec R46 now lists | ||
180 | * the following bands | ||
181 | * ID00 AM 520-1710Khz Not Supported | ||
182 | * ID02 Japan 76-90Mkz 100Khz 50/75uS | ||
183 | * ID01 87.5-108Mhz US 200Khz 75uS, EU 100Kz 50uS | ||
184 | * ID03 76-108Mhz Wideband. Not Supported | ||
185 | */ | ||
166 | if (rd->freq_min == 76000000) | 186 | if (rd->freq_min == 76000000) |
167 | { | 187 | { |
168 | data[2] = 0x02; /* japan band */ | 188 | data[2] = 0x02; /* japan band */ |
169 | } | 189 | } |
170 | else | 190 | else |
171 | { | 191 | { |
172 | data[2] = 0x01; /* us eur band */ | 192 | data[2] = 0x01; /* us/europe band */ |
173 | } | 193 | } |
174 | iap_send_pkt(data, sizeof(data)); | 194 | iap_send_pkt(data, sizeof(data)); |
175 | sleep(HZ/100); | 195 | sleep(HZ/100); |
@@ -225,11 +245,13 @@ static void set_deemphasis(int deemphasis) | |||
225 | case 1: | 245 | case 1: |
226 | { | 246 | { |
227 | tuner_param |= 0x40; | 247 | tuner_param |= 0x40; |
248 | /* 50uS */ | ||
228 | break; | 249 | break; |
229 | } | 250 | } |
230 | default: | 251 | default: |
231 | { | 252 | { |
232 | tuner_param |= 0x00; | 253 | tuner_param |= 0x00; |
254 | /* 75uS */ | ||
233 | break; | 255 | break; |
234 | } | 256 | } |
235 | } | 257 | } |
@@ -253,16 +275,15 @@ static void set_mono(int value) | |||
253 | static bool reply_timeout(void) | 275 | static bool reply_timeout(void) |
254 | { | 276 | { |
255 | int timeout = 0; | 277 | int timeout = 0; |
256 | 278 | ||
257 | sleep(HZ/50); | 279 | sleep(HZ/50); |
258 | do | 280 | do |
259 | { | 281 | { |
260 | iap_handlepkt(); | ||
261 | sleep(HZ/50); | 282 | sleep(HZ/50); |
262 | timeout++; | 283 | timeout++; |
263 | } | 284 | } |
264 | while((ipod_rmt_tuner_get(RADIO_TUNED) == 0) && (timeout < TIMEOUT_VALUE)); | 285 | while((ipod_rmt_tuner_get(RADIO_TUNED) == 0) && (timeout < TIMEOUT_VALUE)); |
265 | 286 | ||
266 | return (timeout >= TIMEOUT_VALUE); | 287 | return (timeout >= TIMEOUT_VALUE); |
267 | } | 288 | } |
268 | 289 | ||
@@ -277,7 +298,7 @@ void rmt_tuner_rds_data(unsigned int len, const unsigned char *buf) | |||
277 | rds_push_info(RDS_INFO_RT, (uintptr_t)(buf+4), len-4); | 298 | rds_push_info(RDS_INFO_RT, (uintptr_t)(buf+4), len-4); |
278 | } | 299 | } |
279 | } | 300 | } |
280 | 301 | ||
281 | /* tuner abstraction layer: set something to the tuner */ | 302 | /* tuner abstraction layer: set something to the tuner */ |
282 | int ipod_rmt_tuner_set(int setting, int value) | 303 | int ipod_rmt_tuner_set(int setting, int value) |
283 | { | 304 | { |
@@ -327,7 +348,7 @@ int ipod_rmt_tuner_set(int setting, int value) | |||
327 | /* scan up */ | 348 | /* scan up */ |
328 | else | 349 | else |
329 | rmt_tuner_scan(1); | 350 | rmt_tuner_scan(1); |
330 | 351 | ||
331 | sleep(HZ/10); | 352 | sleep(HZ/10); |
332 | if (reply_timeout()) | 353 | if (reply_timeout()) |
333 | { | 354 | { |
@@ -337,7 +358,7 @@ int ipod_rmt_tuner_set(int setting, int value) | |||
337 | return 0; | 358 | return 0; |
338 | } | 359 | } |
339 | radio_tuned = false; | 360 | radio_tuned = false; |
340 | } | 361 | } |
341 | 362 | ||
342 | if (tuner_frequency == value) | 363 | if (tuner_frequency == value) |
343 | { | 364 | { |
@@ -360,6 +381,27 @@ int ipod_rmt_tuner_set(int setting, int value) | |||
360 | 381 | ||
361 | case RADIO_REGION: | 382 | case RADIO_REGION: |
362 | { | 383 | { |
384 | /* The latest MFi Accessory Firmware Document I have lists the | ||
385 | * following regions | ||
386 | * US 87.5-108Mhz 200Khz 75uS | ||
387 | * US/EU 87.5-108Mhz 100Khz 75/50uS | ||
388 | * JP 76.0-90Mhz 100Mhz 50/75uS | ||
389 | * | ||
390 | * with the following bands | ||
391 | * 0x00 AM WordlWide 520-1710Khz | ||
392 | * 0x01 FM EU 87.5-108.0Mhz | ||
393 | * 0x02 FM JP 76.0-90.0Mhz | ||
394 | * 0x03 FM Wide 76.0-108.0Mhz | ||
395 | * | ||
396 | * | ||
397 | * A 7G Classic with the latest Apple Firmware returns the following | ||
398 | * regions with the settings listed | ||
399 | * Americas 87.5-108 200Khz 75uS | ||
400 | * Asia 87.5-108 100Khz 75uS | ||
401 | * Australia 87.5-108 200Khz 75uS | ||
402 | * Europe 87.5-108 100Khz 75uS | ||
403 | * Japan 76.0-90. 100Kz 75uS | ||
404 | */ | ||
363 | const struct fm_region_data *rd = &fm_region_data[value]; | 405 | const struct fm_region_data *rd = &fm_region_data[value]; |
364 | int band = (rd->freq_min == 76000000) ? 2 : 0; | 406 | int band = (rd->freq_min == 76000000) ? 2 : 0; |
365 | int spacing = (100000 / rd->freq_step); | 407 | int spacing = (100000 / rd->freq_step); |