summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Giacomelli <giac2000@hotmail.com>2008-12-25 01:46:16 +0000
committerMichael Giacomelli <giac2000@hotmail.com>2008-12-25 01:46:16 +0000
commit70e9c7aed361787a404c4856211ddf53127fca9a (patch)
tree3072967cf3ed2779acf939e150694ef437cbad2d
parentf921f74873a1439cf4e25b87192b31c079863924 (diff)
downloadrockbox-70e9c7aed361787a404c4856211ddf53127fca9a.tar.gz
rockbox-70e9c7aed361787a404c4856211ddf53127fca9a.zip
Commit FS#8624 by Linus Nielsen, Ryan Press, Craig Elliott, and Kenderes Tamas. Adds preliminary support for numerous accessories that use the ipod serial port on the dock connector. See IpodAccessories for a list of tested devices.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19585 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/SOURCES3
-rw-r--r--apps/debug_menu.c8
-rw-r--r--apps/features.txt4
-rw-r--r--apps/iap.c730
-rw-r--r--apps/keymaps/keymap-ipod.c53
-rw-r--r--apps/lang/english.lang111
-rw-r--r--apps/main.c7
-rw-r--r--apps/menus/settings_menu.c6
-rw-r--r--apps/misc.c12
-rw-r--r--apps/playback.c9
-rw-r--r--apps/playback.h2
-rw-r--r--apps/settings.h3
-rw-r--r--apps/settings_list.c9
-rw-r--r--firmware/drivers/serial.c283
-rw-r--r--firmware/export/config-ipod4g.h2
-rw-r--r--firmware/export/config-ipodcolor.h2
-rw-r--r--firmware/export/config-ipodnano.h2
-rw-r--r--firmware/export/config-ipodvideo.h2
-rw-r--r--firmware/export/iap.h31
-rw-r--r--firmware/export/kernel.h2
-rw-r--r--firmware/export/serial.h5
-rw-r--r--firmware/target/arm/ipod/button-clickwheel.c4
-rw-r--r--firmware/target/arm/ipod/button-target.h15
-rw-r--r--firmware/target/arm/system-pp502x.c6
24 files changed, 1283 insertions, 28 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index c63bcb78e2..bd20136d1e 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -52,6 +52,9 @@ tagtree.c
52#endif 52#endif
53filetree.c 53filetree.c
54scrobbler.c 54scrobbler.c
55#ifdef IPOD_ACCESSORY_PROTOCOL
56iap.c
57#endif
55 58
56screen_access.c 59screen_access.c
57#ifdef HAVE_BUTTONBAR 60#ifdef HAVE_BUTTONBAR
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index abb6018a10..f390cced85 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1195,6 +1195,14 @@ bool dbg_ports(void)
1195 lcd_puts(0, line++, buf); 1195 lcd_puts(0, line++, buf);
1196#endif 1196#endif
1197 1197
1198#if defined(IPOD_ACCESSORY_PROTOCOL)
1199extern unsigned char serbuf[];
1200 snprintf(buf, sizeof(buf), "IAP PACKET: %02x %02x %02x %02x %02x %02x %02x %02x",
1201 serbuf[0], serbuf[1], serbuf[2], serbuf[3], serbuf[4], serbuf[5],
1202 serbuf[6], serbuf[7]);
1203 lcd_puts(0, line++, buf);
1204#endif
1205
1198#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) 1206#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
1199 line++; 1207 line++;
1200 snprintf(buf, sizeof(buf), "BATT: %03x UNK1: %03x", 1208 snprintf(buf, sizeof(buf), "BATT: %03x UNK1: %03x",
diff --git a/apps/features.txt b/apps/features.txt
index 0ddccced3c..4fbf427a23 100644
--- a/apps/features.txt
+++ b/apps/features.txt
@@ -181,3 +181,7 @@ usbstack
181#if defined(HAVE_ACCESSORY_SUPPLY) 181#if defined(HAVE_ACCESSORY_SUPPLY)
182accessory_supply 182accessory_supply
183#endif 183#endif
184
185#if defined(IPOD_ACCESSORY_PROTOCOL)
186serial_port
187#endif
diff --git a/apps/iap.c b/apps/iap.c
new file mode 100644
index 0000000000..a15fd81a90
--- /dev/null
+++ b/apps/iap.c
@@ -0,0 +1,730 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: iap.c 17400 2008-05-07 14:30:29Z xxxxxx $
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 <stdio.h>
20#include <stdlib.h>
21#include <stdarg.h>
22#include <memory.h>
23#include <string.h>
24
25#include "iap.h"
26#include "button.h"
27#include "config.h"
28#include "cpu.h"
29#include "system.h"
30#include "kernel.h"
31#include "serial.h"
32
33#include "playlist.h"
34#include "playback.h"
35#include "audio.h"
36#include "settings.h"
37#include "metadata.h"
38#include "gwps.h"
39
40#include "button.h"
41#include "action.h"
42
43#define RX_BUFLEN 260
44#define TX_BUFLEN 128
45
46static volatile int iap_pollspeed = 0;
47static volatile bool iap_remotetick = true;
48static bool iap_setupflag = false, iap_updateflag = false;
49static int iap_changedctr = 0;
50
51static unsigned long iap_remotebtn = 0;
52static int iap_repeatbtn = 0;
53static bool iap_btnrepeat = false, iap_btnshuffle = false;
54
55unsigned char serbuf[RX_BUFLEN];
56static int serbuf_i = 0;
57
58static unsigned char response[TX_BUFLEN];
59static int responselen;
60
61static void iap_task(void)
62{
63 static int count = 0;
64
65 count += iap_pollspeed;
66 if (count < (500/10)) return;
67
68 /* exec every 500ms if pollspeed == 1 */
69 count = 0;
70 queue_post(&button_queue, SYS_IAP_PERIODIC, 0);
71}
72
73void iap_setup(int ratenum)
74{
75 iap_bitrate_set(ratenum);
76 iap_pollspeed = 0;
77 iap_remotetick = true;
78 iap_updateflag = false;
79 iap_changedctr = 0;
80 iap_setupflag = true;
81 iap_remotebtn = BUTTON_NONE;
82 tick_add_task(iap_task);
83}
84
85void iap_bitrate_set(int ratenum)
86{
87 switch(ratenum)
88 {
89 case 0:
90 serial_bitrate(0);
91 break;
92 case 1:
93 serial_bitrate(9600);
94 break;
95 case 2:
96 serial_bitrate(19200);
97 break;
98 case 3:
99 serial_bitrate(38400);
100 break;
101 case 4:
102 serial_bitrate(57600);
103 break;
104 }
105}
106
107/* Message format:
108 0xff
109 0x55
110 length
111 mode
112 command (2 bytes)
113 parameters (0-n bytes)
114 checksum (length+mode+parameters+checksum == 0)
115*/
116
117void iap_send_pkt(unsigned char * data, int len)
118{
119 int i, chksum;
120
121 if(len > TX_BUFLEN-4) len = TX_BUFLEN-4;
122 responselen = len + 4;
123
124 response[0] = 0xFF;
125 response[1] = 0x55;
126
127 chksum = response[2] = len;
128 for(i = 0; i < len; i ++)
129 {
130 chksum += data[i];
131 response[i+3] = data[i];
132 }
133
134 response[i+3] = 0x100 - (chksum & 0xFF);
135
136 for(i = 0; i < responselen; i ++)
137 {
138 while (!tx_rdy()) ;
139 tx_writec(response[i]);
140 }
141}
142
143int iap_getc(unsigned char x)
144{
145 static unsigned char last_x = 0;
146 static bool newpkt = true;
147 static unsigned char chksum = 0;
148
149 /* Restart if the sync word is seen */
150 if(x == 0x55 && last_x == 0xff/* && newpkt*/)
151 {
152 serbuf[0] = 0;
153 serbuf_i = 0;
154 chksum = 0;
155 newpkt = false;
156 }
157 else
158 {
159 if(serbuf_i >= RX_BUFLEN)
160 serbuf_i = 0;
161
162 serbuf[serbuf_i++] = x;
163 chksum += x;
164 }
165 last_x = x;
166
167 /* Broadcast to queue if we have a complete message */
168 if(serbuf_i && (serbuf_i == serbuf[0]+2))
169 {
170 serbuf_i = 0;
171 newpkt = true;
172 if(chksum == 0)
173 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
174 }
175 return newpkt;
176}
177
178void iap_track_changed(void)
179{
180 iap_changedctr = 1;
181}
182
183void iap_periodic(void)
184{
185 if(!iap_setupflag) return;
186 if(!iap_pollspeed) return;
187
188 unsigned char data[] = {0x04, 0x00, 0x27, 0x04, 0x00, 0x00, 0x00, 0x00};
189 unsigned long time_elapsed = audio_current_track()->elapsed;
190
191 time_elapsed += wps_state.ff_rewind_count;
192
193 data[3] = 0x04; // playing
194
195 /* If info has changed, don't flag it right away */
196 if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2)
197 {
198 /* track info has changed */
199 iap_changedctr = 0;
200 data[3] = 0x01; // 0x02 has same effect?
201 iap_updateflag = true;
202 }
203
204 data[4] = time_elapsed >> 24;
205 data[5] = time_elapsed >> 16;
206 data[6] = time_elapsed >> 8;
207 data[7] = time_elapsed;
208 iap_send_pkt(data, sizeof(data));
209}
210
211void iap_handlepkt(void)
212{
213
214 if(!iap_setupflag) return;
215 if(serbuf[0] == 0) return;
216
217 /* if we are waiting for a remote button to go out,
218 delay the handling of the new packet */
219 if(!iap_remotetick)
220 {
221 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
222 return;
223 }
224
225 /* Handle Mode 0 */
226 if (serbuf[1] == 0x00)
227 {
228 switch (serbuf[2])
229 {
230 /* get model info */
231 case 0x0D:
232 {
233 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
234 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
235 iap_send_pkt(data, sizeof(data));
236 break;
237 }
238 /* No idea ??? */
239 case 0x0F:
240 {
241 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
242 iap_send_pkt(data, sizeof(data));
243 break;
244 }
245 /* FM transmitter sends this: FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
246 case 0x01:
247 {
248 if(serbuf[3] == 0x05)
249 {
250 sleep(HZ/3);
251 unsigned char data[] = {0x05, 0x02};
252 iap_send_pkt(data, sizeof(data));
253 }
254 break;
255 }
256 /* FM transmitter sends this: FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (???)*/
257 case 0x13:
258 {
259 unsigned char data[] = {0x00, 0x02, 0x00, 0x13};
260 iap_send_pkt(data, sizeof(data));
261 unsigned char data2[] = {0x00, 0x27, 0x00};
262 iap_send_pkt(data2, sizeof(data2));
263 unsigned char data3[] = {0x05, 0x02};
264 iap_send_pkt(data3, sizeof(data3));
265 break;
266 }
267 /* FM transmitter sends this: FF 55 02 00 05 F9 (mode switch: AiR mode) */
268 case 0x05:
269 {
270 unsigned char data[] = {0x00, 0x02, 0x06, 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28};
271 iap_send_pkt(data, sizeof(data));
272 unsigned char data2[] = {0x00, 0x02, 0x00, 0x05};
273 iap_send_pkt(data2, sizeof(data2));
274 break;
275 }
276 /* default response is with cmd ok packet */
277 default:
278 {
279 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
280 data[3] = serbuf[2]; //respond with cmd
281 iap_send_pkt(data, sizeof(data));
282 break;
283 }
284 }
285 }
286 /* Handle Mode 2 */
287 else if (serbuf[1] == 0x02)
288 {
289 if(serbuf[2] != 0) return;
290 iap_remotebtn = BUTTON_NONE;
291 iap_remotetick = false;
292
293 if(serbuf[0] >= 3 && serbuf[3] != 0)
294 {
295 if(serbuf[3] & 1)
296 iap_remotebtn |= BUTTON_RC_PLAY;
297 if(serbuf[3] & 2)
298 iap_remotebtn |= BUTTON_RC_VOL_UP;
299 if(serbuf[3] & 4)
300 iap_remotebtn |= BUTTON_RC_VOL_DOWN;
301 if(serbuf[3] & 8)
302 iap_remotebtn |= BUTTON_RC_RIGHT;
303 if(serbuf[3] & 16)
304 iap_remotebtn |= BUTTON_RC_LEFT;
305 }
306 else if(serbuf[0] >= 4 && serbuf[4] != 0)
307 {
308 if(serbuf[4] & 1) /* play */
309 {
310 if (audio_status() != AUDIO_STATUS_PLAY)
311 {
312 iap_remotebtn |= BUTTON_RC_PLAY;
313 iap_repeatbtn = 2;
314 iap_remotetick = false;
315 iap_changedctr = 1;
316 }
317 }
318 if(serbuf[4] & 2) /* pause */
319 {
320 if (audio_status() == AUDIO_STATUS_PLAY)
321 {
322 iap_remotebtn |= BUTTON_RC_PLAY;
323 iap_repeatbtn = 2;
324 iap_remotetick = false;
325 iap_changedctr = 1;
326 }
327 }
328 if((serbuf[4] & 128) && !iap_btnshuffle) /* shuffle */
329 {
330 iap_btnshuffle = true;
331 if(!global_settings.playlist_shuffle)
332 {
333 global_settings.playlist_shuffle = 1;
334 settings_save();
335 settings_apply(false);
336 if (audio_status() & AUDIO_STATUS_PLAY)
337 playlist_randomise(NULL, current_tick, true);
338 }
339 else if(global_settings.playlist_shuffle)
340 {
341 global_settings.playlist_shuffle = 0;
342 settings_save();
343 settings_apply(false);
344 if (audio_status() & AUDIO_STATUS_PLAY)
345 playlist_sort(NULL, true);
346 }
347 }
348 else
349 iap_btnshuffle = false;
350 }
351 else if(serbuf[0] >= 5 && serbuf[5] != 0)
352 {
353 if((serbuf[5] & 1) && !iap_btnrepeat) /* repeat */
354 {
355 int oldmode = global_settings.repeat_mode;
356 iap_btnrepeat = true;
357
358 if (oldmode == REPEAT_ONE)
359 global_settings.repeat_mode = REPEAT_OFF;
360 else if (oldmode == REPEAT_ALL)
361 global_settings.repeat_mode = REPEAT_ONE;
362 else if (oldmode == REPEAT_OFF)
363 global_settings.repeat_mode = REPEAT_ALL;
364
365 settings_save();
366 settings_apply(false);
367 if (audio_status() & AUDIO_STATUS_PLAY)
368 audio_flush_and_reload_tracks();
369 }
370 else
371 iap_btnrepeat = false;
372
373 if(serbuf[5] & 16) /* ffwd */
374 {
375 iap_remotebtn |= BUTTON_RC_RIGHT;
376 }
377 if(serbuf[5] & 32) /* frwd */
378 {
379 iap_remotebtn |= BUTTON_RC_LEFT;
380 }
381 }
382 }
383 /* Handle Mode 3 */
384 else if (serbuf[1] == 0x03)
385 {
386 switch(serbuf[2])
387 {
388 /* some kind of status packet? */
389 case 0x01:
390 {
391 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
392 iap_send_pkt(data, sizeof(data));
393 break;
394 }
395 }
396 }
397 /* Handle Mode 4 */
398 else if (serbuf[1] == 0x04)
399 {
400 switch (((unsigned long)serbuf[2] << 8) | serbuf[3])
401 {
402 /* Get data updated??? flag */
403 case 0x0009:
404 {
405 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
406 data[3] = iap_updateflag ? 0 : 1;
407 iap_send_pkt(data, sizeof(data));
408 break;
409 }
410 /* Set data updated??? flag */
411 case 0x000B:
412 {
413 iap_updateflag = serbuf[4] ? 0 : 1;
414 /* respond with cmd ok packet */
415 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x0B};
416 iap_send_pkt(data, sizeof(data));
417 break;
418 }
419 /* Get iPod size? */
420 case 0x0012:
421 {
422 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
423 iap_send_pkt(data, sizeof(data));
424 break;
425 }
426 /* Get count of given types */
427 case 0x0018:
428 {
429 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
430 unsigned long num = 0;
431 switch(serbuf[4]) /* type number */
432 {
433 case 0x01: /* total number of playlists */
434 num = 1;
435 break;
436 case 0x05: /* total number of songs */
437 num = 1;
438 }
439 data[3] = num >> 24;
440 data[4] = num >> 16;
441 data[5] = num >> 8;
442 data[6] = num;
443 iap_send_pkt(data, sizeof(data));
444 break;
445 }
446 /* Get time and status */
447 case 0x001C:
448 {
449 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
450 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
451 struct mp3entry *id3 = audio_current_track();
452 unsigned long time_total = id3->length;
453 unsigned long time_elapsed = id3->elapsed;
454 int status = audio_status();
455 data[3] = time_total >> 24;
456 data[4] = time_total >> 16;
457 data[5] = time_total >> 8;
458 data[6] = time_total;
459 data[7] = time_elapsed >> 24;
460 data[8] = time_elapsed >> 16;
461 data[9] = time_elapsed >> 8;
462 data[10] = time_elapsed;
463 if (status == AUDIO_STATUS_PLAY)
464 data[11] = 0x01; /* play */
465 else if (status & AUDIO_STATUS_PAUSE)
466 data[11] = 0x02; /* pause */
467 iap_send_pkt(data, sizeof(data));
468 break;
469 }
470 /* Get current pos in playlist */
471 case 0x001E:
472 {
473 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
474 long playlist_pos = playlist_next(0);
475 playlist_pos -= playlist_get_first_index(NULL);
476 if(playlist_pos < 0)
477 playlist_pos += playlist_amount();
478 data[3] = playlist_pos >> 24;
479 data[4] = playlist_pos >> 16;
480 data[5] = playlist_pos >> 8;
481 data[6] = playlist_pos;
482 iap_send_pkt(data, sizeof(data));
483 break;
484 }
485 /* Get title of a song number */
486 case 0x0020:
487 /* Get artist of a song number */
488 case 0x0022:
489 /* Get album of a song number */
490 case 0x0024:
491 {
492 unsigned char data[70] = {0x04, 0x00, 0xFF};
493 struct mp3entry id3;
494 int fd;
495 long tracknum = (signed long)serbuf[4] << 24 |
496 (signed long)serbuf[5] << 16 |
497 (signed long)serbuf[6] << 8 | serbuf[7];
498 data[2] = serbuf[3] + 1;
499 memcpy(&id3, audio_current_track(), sizeof(id3));
500 tracknum += playlist_get_first_index(NULL);
501 if(tracknum >= playlist_amount())
502 tracknum -= playlist_amount();
503
504 /* If the tracknumber is not the current one,
505 read id3 from disk */
506 if(playlist_next(0) != tracknum)
507 {
508 struct playlist_track_info info;
509 playlist_get_track_info(NULL, tracknum, &info);
510 fd = open(info.filename, O_RDONLY);
511 memset(&id3, 0, sizeof(struct mp3entry));
512 get_metadata(&id3, fd, info.filename);
513 close(fd);
514 }
515
516 /* Return the requested track data */
517 switch(serbuf[3])
518 {
519 case 0x20:
520 strncpy((char *)&data[3], id3.title, 64);
521 iap_send_pkt(data, 4+strlen(id3.title));
522 break;
523 case 0x22:
524 strncpy((char *)&data[3], id3.artist, 64);
525 iap_send_pkt(data, 4+strlen(id3.artist));
526 break;
527 case 0x24:
528 strncpy((char *)&data[3], id3.album, 64);
529 iap_send_pkt(data, 4+strlen(id3.album));
530 break;
531 }
532 break;
533 }
534 /* Set polling mode */
535 case 0x0026:
536 {
537 iap_pollspeed = serbuf[4] ? 1 : 0;
538 /*responsed with cmd ok packet */
539 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x26};
540 iap_send_pkt(data, sizeof(data));
541 break;
542 }
543 /* AiR playback control */
544 case 0x0029:
545 {
546 /* respond with cmd ok packet */
547 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
548 iap_send_pkt(data, sizeof(data));
549 switch(serbuf[4])
550 {
551 case 0x01: /* play/pause */
552 iap_remotebtn = BUTTON_RC_PLAY;
553 iap_repeatbtn = 2;
554 iap_remotetick = false;
555 iap_changedctr = 1;
556 break;
557 case 0x02: /* stop */
558 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
559 iap_repeatbtn = 2;
560 iap_remotetick = false;
561 iap_changedctr = 1;
562 break;
563 case 0x03: /* skip++ */
564 iap_remotebtn = BUTTON_RC_RIGHT;
565 iap_repeatbtn = 2;
566 iap_remotetick = false;
567 break;
568 case 0x04: /* skip-- */
569 iap_remotebtn = BUTTON_RC_LEFT;
570 iap_repeatbtn = 2;
571 iap_remotetick = false;
572 break;
573 case 0x05: /* ffwd */
574 iap_remotebtn = BUTTON_RC_RIGHT;
575 iap_remotetick = false;
576 if(iap_pollspeed) iap_pollspeed = 5;
577 break;
578 case 0x06: /* frwd */
579 iap_remotebtn = BUTTON_RC_LEFT;
580 iap_remotetick = false;
581 if(iap_pollspeed) iap_pollspeed = 5;
582 break;
583 case 0x07: /* end ffwd/frwd */
584 iap_remotebtn = BUTTON_NONE;
585 iap_remotetick = false;
586 if(iap_pollspeed) iap_pollspeed = 1;
587 break;
588 }
589 break;
590 }
591 /* Get shuffle mode */
592 case 0x002C:
593 {
594 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
595 data[3] = global_settings.playlist_shuffle ? 1 : 0;
596 iap_send_pkt(data, sizeof(data));
597 break;
598 }
599 /* Set shuffle mode */
600 case 0x002E:
601 {
602 if(serbuf[4] && !global_settings.playlist_shuffle)
603 {
604 global_settings.playlist_shuffle = 1;
605 settings_save();
606 settings_apply(false);
607 if (audio_status() & AUDIO_STATUS_PLAY)
608 playlist_randomise(NULL, current_tick, true);
609 }
610 else if(!serbuf[4] && global_settings.playlist_shuffle)
611 {
612 global_settings.playlist_shuffle = 0;
613 settings_save();
614 settings_apply(false);
615 if (audio_status() & AUDIO_STATUS_PLAY)
616 playlist_sort(NULL, true);
617 }
618
619
620 /* respond with cmd ok packet */
621 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x2E};
622 iap_send_pkt(data, sizeof(data));
623 break;
624 }
625 /* Get repeat mode */
626 case 0x002F:
627 {
628 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
629 if(global_settings.repeat_mode == REPEAT_OFF)
630 data[3] = 0;
631 else if(global_settings.repeat_mode == REPEAT_ONE)
632 data[3] = 1;
633 else
634 data[3] = 2;
635 iap_send_pkt(data, sizeof(data));
636 break;
637 }
638 /* Set repeat mode */
639 case 0x0031:
640 {
641 int oldmode = global_settings.repeat_mode;
642 if (serbuf[4] == 0)
643 global_settings.repeat_mode = REPEAT_OFF;
644 else if (serbuf[4] == 1)
645 global_settings.repeat_mode = REPEAT_ONE;
646 else if (serbuf[4] == 2)
647 global_settings.repeat_mode = REPEAT_ALL;
648
649 if (oldmode != global_settings.repeat_mode)
650 {
651 settings_save();
652 settings_apply(false);
653 if (audio_status() & AUDIO_STATUS_PLAY)
654 audio_flush_and_reload_tracks();
655 }
656
657 /* respond with cmd ok packet */
658 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x31};
659 iap_send_pkt(data, sizeof(data));
660 break;
661 }
662 /* Get Max Screen Size for Picture Upload??? */
663 case 0x0033:
664 {
665 unsigned char data[] = {0x04, 0x00, 0x34, 0x01, 0x36, 0x00, 0xA8, 0x01};
666 iap_send_pkt(data, sizeof(data));
667 break;
668 }
669 /* Get number songs in current playlist */
670 case 0x0035:
671 {
672 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
673 unsigned long playlist_amt = playlist_amount();
674 data[3] = playlist_amt >> 24;
675 data[4] = playlist_amt >> 16;
676 data[5] = playlist_amt >> 8;
677 data[6] = playlist_amt;
678 iap_send_pkt(data, sizeof(data));
679 break;
680 }
681 /* Jump to track number in current playlist */
682 case 0x0037:
683 {
684 long tracknum = (signed long)serbuf[4] << 24 |
685 (signed long)serbuf[5] << 16 |
686 (signed long)serbuf[6] << 8 | serbuf[7];
687 if (!wps_state.paused)
688 audio_pause();
689 audio_skip(tracknum - playlist_next(0));
690 if (!wps_state.paused)
691 audio_resume();
692
693 /* respond with cmd ok packet */
694 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
695 data[4] = serbuf[2];
696 data[5] = serbuf[3];
697 iap_send_pkt(data, sizeof(data));
698 break;
699 }
700 default:
701 {
702 /* default response is with cmd ok packet */
703 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
704 data[4] = serbuf[2];
705 data[5] = serbuf[3];
706 iap_send_pkt(data, sizeof(data));
707 break;
708 }
709 }
710 }
711 serbuf[0] = 0;
712}
713
714int remote_control_rx(void)
715{
716 int btn = iap_remotebtn;
717 if(iap_repeatbtn)
718 {
719 iap_repeatbtn--;
720 if(!iap_repeatbtn)
721 {
722 iap_remotebtn = BUTTON_NONE;
723 iap_remotetick = true;
724 }
725 }
726 else
727 iap_remotetick = true;
728
729 return btn;
730}
diff --git a/apps/keymaps/keymap-ipod.c b/apps/keymaps/keymap-ipod.c
index 5b735eb530..02854524d2 100644
--- a/apps/keymaps/keymap-ipod.c
+++ b/apps/keymaps/keymap-ipod.c
@@ -187,9 +187,62 @@ const struct button_mapping button_context_recscreen[] = {
187}; /* button_context_recscreen */ 187}; /* button_context_recscreen */
188#endif 188#endif
189 189
190#if BUTTON_REMOTE != 0
191/*****************************************************************************
192 * Remote control mappings
193 *****************************************************************************/
194
195static const struct button_mapping remote_button_context_standard[] = {
196 { ACTION_STD_PREV, BUTTON_RC_LEFT, BUTTON_NONE },
197 { ACTION_STD_NEXT, BUTTON_RC_RIGHT, BUTTON_NONE },
198 { ACTION_STD_CANCEL, BUTTON_RC_STOP, BUTTON_NONE },
199 { ACTION_STD_OK, BUTTON_RC_PLAY, BUTTON_NONE },
200
201 LAST_ITEM_IN_LIST
202};
203
204static const struct button_mapping remote_button_context_wps[] = {
205 { ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN, BUTTON_NONE },
206 { ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
207 { ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP, BUTTON_NONE },
208 { ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
209
210 { ACTION_WPS_PLAY, BUTTON_RC_PLAY|BUTTON_REL, BUTTON_RC_PLAY },
211 { ACTION_WPS_STOP, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_NONE },
212 { ACTION_WPS_SKIPNEXT, BUTTON_RC_RIGHT|BUTTON_REL, BUTTON_RC_RIGHT },
213 { ACTION_WPS_SEEKFWD, BUTTON_RC_RIGHT|BUTTON_REPEAT,BUTTON_NONE },
214 { ACTION_WPS_STOPSEEK, BUTTON_RC_RIGHT|BUTTON_REL, BUTTON_RC_RIGHT|BUTTON_REPEAT },
215 { ACTION_WPS_SKIPPREV, BUTTON_RC_LEFT|BUTTON_REL, BUTTON_RC_LEFT },
216 { ACTION_WPS_SEEKBACK, BUTTON_RC_LEFT|BUTTON_REPEAT, BUTTON_NONE },
217 { ACTION_WPS_STOPSEEK, BUTTON_RC_LEFT|BUTTON_REL, BUTTON_RC_LEFT|BUTTON_REPEAT },
218
219 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
220};
221
222
223static const struct button_mapping* get_context_mapping_remote( int context )
224{
225 context ^= CONTEXT_REMOTE;
226
227 switch (context)
228 {
229 case CONTEXT_WPS:
230 return remote_button_context_wps;
231
232 default:
233 return remote_button_context_standard;
234 }
235}
236#endif /* BUTTON_REMOTE != 0 */
237
190/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */ 238/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
191const struct button_mapping* get_context_mapping(int context) 239const struct button_mapping* get_context_mapping(int context)
192{ 240{
241#if BUTTON_REMOTE != 0
242 if (context&CONTEXT_REMOTE)
243 return get_context_mapping_remote(context);
244#endif
245
193 switch (context) 246 switch (context)
194 { 247 {
195 case CONTEXT_STD: 248 case CONTEXT_STD:
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index f0099e4ec9..f5f9ed3b80 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -11811,6 +11811,110 @@
11811 gigabeatf: "High" 11811 gigabeatf: "High"
11812 </voice> 11812 </voice>
11813</phrase> 11813</phrase>
11814<<<<<<< .mine
11815<phrase>
11816 id: LANG_SERIAL_BITRATE
11817 desc: in system settings menu
11818 user:
11819 <source>
11820 *: none
11821 serial_port: "Serial Bitrate"
11822 </source>
11823 <dest>
11824 *: none
11825 serial_port: "Serial Bitrate"
11826 </dest>
11827 <voice>
11828 *: none
11829 serial_port: "Serial Bitrate"
11830 </voice>
11831</phrase>
11832<phrase>
11833 id: LANG_SERIAL_BITRATE_AUTO
11834 desc: in system settings menu
11835 user:
11836 <source>
11837 *: none
11838 serial_port: "Auto"
11839 </source>
11840 <dest>
11841 *: none
11842 serial_port: "Auto"
11843 </dest>
11844 <voice>
11845 *: none
11846 serial_port: "Automatic"
11847 </voice>
11848</phrase>
11849<phrase>
11850 id: LANG_SERIAL_BITRATE_9600
11851 desc: in system settings menu
11852 user:
11853 <source>
11854 *: none
11855 serial_port: "9600"
11856 </source>
11857 <dest>
11858 *: none
11859 serial_port: "9600"
11860 </dest>
11861 <voice>
11862 *: none
11863 serial_port: "9600"
11864 </voice>
11865</phrase>
11866<phrase>
11867 id: LANG_SERIAL_BITRATE_19200
11868 desc: in system settings menu
11869 user:
11870 <source>
11871 *: none
11872 serial_port: "19200"
11873 </source>
11874 <dest>
11875 *: none
11876 serial_port: "19200"
11877 </dest>
11878 <voice>
11879 *: none
11880 serial_port: "19200"
11881 </voice>
11882</phrase>
11883<phrase>
11884 id: LANG_SERIAL_BITRATE_38400
11885 desc: in system settings menu
11886 user:
11887 <source>
11888 *: none
11889 serial_port: "38400"
11890 </source>
11891 <dest>
11892 *: none
11893 serial_port: "38400"
11894 </dest>
11895 <voice>
11896 *: none
11897 serial_port: "38400"
11898 </voice>
11899</phrase>
11900<phrase>
11901 id: LANG_SERIAL_BITRATE_57600
11902 desc: in system settings menu
11903 user:
11904 <source>
11905 *: none
11906 serial_port: "57600"
11907 </source>
11908 <dest>
11909 *: none
11910 serial_port: "57600"
11911 </dest>
11912 <voice>
11913 *: none
11914 serial_port: "57600"
11915 </voice>
11916</phrase>
11917=======
11814<phrase> 11918<phrase>
11815 id: LANG_VERY_SLOW 11919 id: LANG_VERY_SLOW
11816 desc: in settings_menu 11920 desc: in settings_menu
@@ -11909,6 +12013,9 @@
11909 *: "slash" 12013 *: "slash"
11910 </voice> 12014 </voice>
11911</phrase> 12015</phrase>
12016<<<<<<< .mine
12017>>>>>>> .r18116
12018=======
11912<phrase> 12019<phrase>
11913 id: LANG_GAIN_LEFT 12020 id: LANG_GAIN_LEFT
11914 desc: in the recording screen 12021 desc: in the recording screen
@@ -12110,6 +12217,9 @@
12110 *: "Search Results" 12217 *: "Search Results"
12111 </voice> 12218 </voice>
12112</phrase> 12219</phrase>
12220<<<<<<< .mine
12221>>>>>>> .r18870
12222=======
12113<phrase> 12223<phrase>
12114 id: LANG_QS_ITEMS 12224 id: LANG_QS_ITEMS
12115 desc: DEPRECATED 12225 desc: DEPRECATED
@@ -12243,3 +12353,4 @@
12243 quickscreen: "Set as Bottom Quickscreen Item" 12353 quickscreen: "Set as Bottom Quickscreen Item"
12244 </voice> 12354 </voice>
12245</phrase> 12355</phrase>
12356>>>>>>> .r19041
diff --git a/apps/main.c b/apps/main.c
index 111c5d1e78..45e6c77801 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -73,6 +73,10 @@
73#include "scrobbler.h" 73#include "scrobbler.h"
74#include "icon.h" 74#include "icon.h"
75 75
76#ifdef IPOD_ACCESSORY_PROTOCOL
77#include "iap.h"
78#endif
79
76#if (CONFIG_CODEC == SWCODEC) 80#if (CONFIG_CODEC == SWCODEC)
77#include "playback.h" 81#include "playback.h"
78#endif 82#endif
@@ -583,6 +587,9 @@ static void init(void)
583#if CONFIG_CHARGING 587#if CONFIG_CHARGING
584 car_adapter_mode_init(); 588 car_adapter_mode_init();
585#endif 589#endif
590#ifdef IPOD_ACCESSORY_PROTOCOL
591 iap_setup(global_settings.serial_bitrate);
592#endif
586#ifdef HAVE_ACCESSORY_SUPPLY 593#ifdef HAVE_ACCESSORY_SUPPLY
587 accessory_supply_set(global_settings.accessory_supply); 594 accessory_supply_set(global_settings.accessory_supply);
588#endif 595#endif
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index d05726ea44..b6e5ad4171 100644
--- a/apps/menus/settings_menu.c
+++ b/apps/menus/settings_menu.c
@@ -247,6 +247,9 @@ MENUITEM_SETTING(line_in, &global_settings.line_in, linein_callback);
247#if CONFIG_CHARGING 247#if CONFIG_CHARGING
248MENUITEM_SETTING(car_adapter_mode, &global_settings.car_adapter_mode, NULL); 248MENUITEM_SETTING(car_adapter_mode, &global_settings.car_adapter_mode, NULL);
249#endif 249#endif
250#ifdef IPOD_ACCESSORY_PROTOCOL
251MENUITEM_SETTING(serial_bitrate, &global_settings.serial_bitrate, NULL);
252#endif
250#ifdef HAVE_ACCESSORY_SUPPLY 253#ifdef HAVE_ACCESSORY_SUPPLY
251MENUITEM_SETTING(accessory_supply, &global_settings.accessory_supply, NULL); 254MENUITEM_SETTING(accessory_supply, &global_settings.accessory_supply, NULL);
252#endif 255#endif
@@ -282,6 +285,9 @@ MAKE_MENU(system_menu, ID2P(LANG_SYSTEM),
282#if CONFIG_CHARGING 285#if CONFIG_CHARGING
283 &car_adapter_mode, 286 &car_adapter_mode,
284#endif 287#endif
288#ifdef IPOD_ACCESSORY_PROTOCOL,
289 &serial_bitrate,
290#endif
285#ifdef HAVE_ACCESSORY_SUPPLY 291#ifdef HAVE_ACCESSORY_SUPPLY
286 &accessory_supply, 292 &accessory_supply,
287#endif 293#endif
diff --git a/apps/misc.c b/apps/misc.c
index 11cdee17b9..8b73411549 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -61,6 +61,10 @@
61#include "playlist.h" 61#include "playlist.h"
62#include "yesno.h" 62#include "yesno.h"
63 63
64#ifdef IPOD_ACCESSORY_PROTOCOL
65#include "iap.h"
66#endif
67
64#if (CONFIG_STORAGE & STORAGE_MMC) 68#if (CONFIG_STORAGE & STORAGE_MMC)
65#include "ata_mmc.h" 69#include "ata_mmc.h"
66#endif 70#endif
@@ -959,6 +963,14 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
959 unplug_change(false); 963 unplug_change(false);
960 return SYS_PHONE_UNPLUGGED; 964 return SYS_PHONE_UNPLUGGED;
961#endif 965#endif
966#ifdef IPOD_ACCESSORY_PROTOCOL
967 case SYS_IAP_PERIODIC:
968 iap_periodic();
969 return SYS_IAP_PERIODIC;
970 case SYS_IAP_HANDLEPKT:
971 iap_handlepkt();
972 return SYS_IAP_HANDLEPKT;
973#endif
962 } 974 }
963 return 0; 975 return 0;
964} 976}
diff --git a/apps/playback.c b/apps/playback.c
index d2d9bb6a34..0f76666c1e 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -82,6 +82,10 @@
82#include "pcm_record.h" 82#include "pcm_record.h"
83#endif 83#endif
84 84
85#ifdef IPOD_ACCESSORY_PROTOCOL
86#include "iap.h"
87#endif
88
85#define PLAYBACK_VOICE 89#define PLAYBACK_VOICE
86 90
87/* default point to start buffer refill */ 91/* default point to start buffer refill */
@@ -646,6 +650,9 @@ bool audio_has_changed_track(void)
646{ 650{
647 if (track_changed) 651 if (track_changed)
648 { 652 {
653#ifdef IPOD_ACCESSORY_PROTOCOL
654 iap_track_changed();
655#endif
649 track_changed = false; 656 track_changed = false;
650 return true; 657 return true;
651 } 658 }
@@ -691,7 +698,7 @@ void audio_resume(void)
691 queue_send(&audio_queue, Q_AUDIO_PAUSE, false); 698 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
692} 699}
693 700
694static void audio_skip(int direction) 701void audio_skip(int direction)
695{ 702{
696 if (playlist_check(ci.new_track + wps_offset + direction)) 703 if (playlist_check(ci.new_track + wps_offset + direction))
697 { 704 {
diff --git a/apps/playback.h b/apps/playback.h
index d9f29cc56a..e65d5da150 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -33,7 +33,7 @@ int audio_track_count(void);
33long audio_filebufused(void); 33long audio_filebufused(void);
34void audio_pre_ff_rewind(void); 34void audio_pre_ff_rewind(void);
35void audio_set_crossfade(int type); 35void audio_set_crossfade(int type);
36 36void audio_skip(int direction);
37void audio_hard_stop(void); /* Stops audio from serving playback */ 37void audio_hard_stop(void); /* Stops audio from serving playback */
38 38
39enum 39enum
diff --git a/apps/settings.h b/apps/settings.h
index b0117874cc..f9b3239e05 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -488,6 +488,9 @@ struct user_settings
488 bool peak_meter_clipcounter; /* clipping count indicator */ 488 bool peak_meter_clipcounter; /* clipping count indicator */
489#endif 489#endif
490 bool car_adapter_mode; /* 0=off 1=on */ 490 bool car_adapter_mode; /* 0=off 1=on */
491#ifdef IPOD_ACCESSORY_PROTOCOL
492 int serial_bitrate; /* 0=auto 1=9600 2=19200 3=38400 4=57600 */
493#endif
491#ifdef HAVE_ACCESSORY_SUPPLY 494#ifdef HAVE_ACCESSORY_SUPPLY
492 bool accessory_supply; /* 0=off 1=on, accessory power supply for iPod */ 495 bool accessory_supply; /* 0=off 1=on, accessory power supply for iPod */
493#endif 496#endif
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 27739b29c9..e3874566ac 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -49,6 +49,9 @@
49#if CONFIG_TUNER 49#if CONFIG_TUNER
50#include "radio.h" 50#include "radio.h"
51#endif 51#endif
52#ifdef IPOD_ACCESSORY_PROTOCOL
53#include "iap.h"
54#endif
52 55
53#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT) 56#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT)
54/** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h 57/** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h
@@ -595,6 +598,12 @@ const struct settings_list settings[] = {
595 OFFON_SETTING(NVRAM(1), car_adapter_mode, 598 OFFON_SETTING(NVRAM(1), car_adapter_mode,
596 LANG_CAR_ADAPTER_MODE, false, "car adapter mode", NULL), 599 LANG_CAR_ADAPTER_MODE, false, "car adapter mode", NULL),
597#endif 600#endif
601#ifdef IPOD_ACCESSORY_PROTOCOL
602 CHOICE_SETTING(0, serial_bitrate, LANG_SERIAL_BITRATE, 0, "serial bitrate",
603 "auto,9600,19200,38400,57600", iap_bitrate_set, 5, ID2P(LANG_SERIAL_BITRATE_AUTO),
604 ID2P(LANG_SERIAL_BITRATE_9600),ID2P(LANG_SERIAL_BITRATE_19200),
605 ID2P(LANG_SERIAL_BITRATE_38400),ID2P(LANG_SERIAL_BITRATE_57600)),
606#endif
598#ifdef HAVE_ACCESSORY_SUPPLY 607#ifdef HAVE_ACCESSORY_SUPPLY
599 OFFON_SETTING(0, accessory_supply, LANG_ACCESSORY_SUPPLY, 608 OFFON_SETTING(0, accessory_supply, LANG_ACCESSORY_SUPPLY,
600 true, "accessory power supply", accessory_supply_set), 609 true, "accessory power supply", accessory_supply_set),
diff --git a/firmware/drivers/serial.c b/firmware/drivers/serial.c
index 47fbf564ff..a496824261 100644
--- a/firmware/drivers/serial.c
+++ b/firmware/drivers/serial.c
@@ -18,7 +18,9 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include <stdio.h>
21#include <stdlib.h> 22#include <stdlib.h>
23#include <stdarg.h>
22#include "button.h" 24#include "button.h"
23#include "config.h" 25#include "config.h"
24#include "cpu.h" 26#include "cpu.h"
@@ -28,6 +30,7 @@
28#include "adc.h" 30#include "adc.h"
29#include "lcd.h" 31#include "lcd.h"
30#include "serial.h" 32#include "serial.h"
33#include "iap.h"
31 34
32#if CONFIG_CPU == IMX31L 35#if CONFIG_CPU == IMX31L
33#include "serial-imx31.h" 36#include "serial-imx31.h"
@@ -68,6 +71,35 @@ void serial_setup (void)
68 SCR1 = 0x10; /* Enable the receiver, no interrupt */ 71 SCR1 = 0x10; /* Enable the receiver, no interrupt */
69} 72}
70 73
74int tx_rdy(void)
75{
76 /* a dummy */
77 return 1;
78}
79
80int rx_rdy(void)
81{
82 if(SSR1 & SCI_RDRF)
83 return 1;
84 else
85 return 0;
86}
87
88void tx_writec(unsigned char c)
89{
90 /* a dummy */
91}
92
93unsigned char rx_readc(void)
94{
95 char tmp;
96 /* Read byte and clear the Rx Full bit */
97 tmp = RDR1;
98 and_b(~SCI_RDRF, &SSR1);
99 return tmp;
100}
101
102
71/* This function returns the received remote control code only if it is 103/* This function returns the received remote control code only if it is
72 received without errors before or after the reception. 104 received without errors before or after the reception.
73 It therefore returns the received code on the second call after the 105 It therefore returns the received code on the second call after the
@@ -87,11 +119,9 @@ int remote_control_rx(void)
87 return BUTTON_NONE; 119 return BUTTON_NONE;
88 } 120 }
89 121
90 if(SSR1 & SCI_RDRF) { 122 if(rx_rdy()) {
91 /* Read byte and clear the Rx Full bit */ 123 btn = rx_readc();
92 btn = RDR1; 124
93 and_b(~SCI_RDRF, &SSR1);
94
95 if(last_was_error) 125 if(last_was_error)
96 { 126 {
97 last_valid_button = BUTTON_NONE; 127 last_valid_button = BUTTON_NONE;
@@ -149,16 +179,6 @@ int remote_control_rx(void)
149#endif /* !HAVE_FMADC && !STORAGE_MMC */ 179#endif /* !HAVE_FMADC && !STORAGE_MMC */
150#elif defined(CPU_COLDFIRE) && defined(HAVE_SERIAL) 180#elif defined(CPU_COLDFIRE) && defined(HAVE_SERIAL)
151 181
152void serial_tx(const unsigned char *buf)
153{
154 while(*buf) {
155 while(!(USR0 & 0x04))
156 {
157 };
158 UTB0 = *buf++;
159 }
160}
161
162void serial_setup (void) 182void serial_setup (void)
163{ 183{
164 UCR0 = 0x30; /* Reset transmitter */ 184 UCR0 = 0x30; /* Reset transmitter */
@@ -171,6 +191,25 @@ void serial_setup (void)
171 UCR0 = 0x04; /* Tx enable */ 191 UCR0 = 0x04; /* Tx enable */
172} 192}
173 193
194int tx_rdy(void)
195{
196 if(USR0 & 0x04)
197 return 1;
198 else
199 return 0;
200}
201
202int rx_rdy(void)
203{
204 /* a dummy */
205 return 0;
206}
207
208void tx_writec(unsigned char c)
209{
210 UTB0 = c;
211}
212
174#elif (CONFIG_CPU == IMX31L) 213#elif (CONFIG_CPU == IMX31L)
175 214
176void serial_setup(void) 215void serial_setup(void)
@@ -207,15 +246,216 @@ int rx_rdy(void)
207 return 0; 246 return 0;
208} 247}
209 248
210void tx_writec(char c) 249void tx_writec(unsigned char c)
211{ 250{
212 UTXD1=(int) c; 251 UTXD1=(int) c;
213} 252}
214 253
254#elif defined(IPOD_ACCESSORY_PROTOCOL)
255static int autobaud = 0;
256void serial_setup (void)
257{
258 int tmp;
259
260#if (MODEL_NUMBER == 3) || (MODEL_NUMBER == 8)
261
262 /* Route the Tx/Rx pins. 4G Ipod??? */
263 outl(0x70000018, inl(0x70000018) & ~0xc00);
264#elif (MODEL_NUMBER == 4) || (MODEL_NUMBER == 5)
265
266 /* Route the Tx/Rx pins. 5G Ipod */
267 (*(volatile unsigned long *)(0x7000008C)) &= ~0x0C;
268 GPO32_ENABLE &= ~0x0C;
269#endif
270
271 DEV_EN = DEV_EN | DEV_SER0;
272 CPU_HI_INT_DIS = SER0_MASK;
273
274 DEV_RS |= DEV_SER0;
275 sleep(1);
276 DEV_RS &= ~DEV_SER0;
277
278 SER0_LCR = 0x80; /* Divisor latch enable */
279 SER0_DLM = 0x00;
280 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
281 SER0_IER = 0x01;
282
283 SER0_FCR = 0x07; /* Tx+Rx FIFO reset and FIFO enable */
284
285 CPU_INT_EN |= HI_MASK;
286 CPU_HI_INT_EN |= SER0_MASK;
287 tmp = SER0_RBR;
288
289 serial_bitrate(0);
290}
291
292void serial_bitrate(int rate)
293{
294 if(rate == 0)
295 {
296 autobaud = 2;
297 SER0_LCR = 0x80; /* Divisor latch enable */
298 SER0_DLL = 0x0D; /* 24000000/13/16 = 115384 baud */
299 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
300 return;
301 }
302
303 autobaud = 0;
304 SER0_LCR = 0x80; /* Divisor latch enable */
305 SER0_DLL = 24000000L / rate / 16;
306 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
307}
308
309int tx_rdy(void)
310{
311 if((SER0_LSR & 0x20))
312 return 1;
313 else
314 return 0;
315}
316
317int rx_rdy(void)
318{
319 if((SER0_LSR & 0x1))
320 return 1;
321 else
322 return 0;
323}
324
325void tx_writec(unsigned char c)
326{
327 SER0_THR =(int) c;
328}
329
330unsigned char rx_readc(void)
331{
332 return (SER0_RBR & 0xFF);
333}
334
335void SERIAL0(void)
336{
337 static int badbaud = 0;
338 static bool newpkt = true;
339 char temp;
340
341 while(rx_rdy())
342 {
343 temp = rx_readc();
344 if (newpkt && autobaud > 0)
345 {
346 if (autobaud == 1)
347 {
348 switch (temp)
349 {
350 case 0xFF:
351 case 0x55:
352 break;
353 case 0xFC:
354 SER0_LCR = 0x80; /* Divisor latch enable */
355 SER0_DLL = 0x4E; /* 24000000/78/16 = 19230 baud */
356 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
357 temp = 0xFF;
358 break;
359 case 0xE0:
360 SER0_LCR = 0x80; /* Divisor latch enable */
361 SER0_DLL = 0x9C; /* 24000000/156/16 = 9615 baud */
362 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
363 temp = 0xFF;
364 break;
365 default:
366 badbaud++;
367 if (badbaud >= 6) /* Switch baud detection mode */
368 {
369 autobaud = 2;
370 SER0_LCR = 0x80; /* Divisor latch enable */
371 SER0_DLL = 0x0D; /* 24000000/13/16 = 115384 baud */
372 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
373 badbaud = 0;
374 } else {
375 SER0_LCR = 0x80; /* Divisor latch enable */
376 SER0_DLL = 0x1A; /* 24000000/26/16 = 57692 baud */
377 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
378 }
379 continue;
380 }
381 } else {
382 switch (temp)
383 {
384 case 0xFF:
385 case 0x55:
386 break;
387 case 0xFE:
388 SER0_LCR = 0x80; /* Divisor latch enable */
389 SER0_DLL = 0x1A; /* 24000000/26/16 = 57692 baud */
390 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
391 temp = 0xFF;
392 break;
393 case 0xFC:
394 SER0_LCR = 0x80; /* Divisor latch enable */
395 SER0_DLL = 0x27; /* 24000000/39/16 = 38461 baud */
396 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
397 temp = 0xFF;
398 break;
399 case 0xE0:
400 SER0_LCR = 0x80; /* Divisor latch enable */
401 SER0_DLL = 0x4E; /* 24000000/78/16 = 19230 baud */
402 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
403 temp = 0xFF;
404 break;
405 default:
406 badbaud++;
407 if (badbaud >= 6) /* Switch baud detection */
408 {
409 autobaud = 1;
410 SER0_LCR = 0x80; /* Divisor latch enable */
411 SER0_DLL = 0x1A; /* 24000000/26/16 = 57692 baud */
412 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
413 badbaud = 0;
414 } else {
415 SER0_LCR = 0x80; /* Divisor latch enable */
416 SER0_DLL = 0x0D; /* 24000000/13/16 = 115384 baud */
417 SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
418 }
419 continue;
420 }
421 }
422 }
423 bool pkt = iap_getc(temp);
424 if(newpkt == true && pkt == false)
425 autobaud = 0; /* Found good baud */
426 newpkt = pkt;
427 }
428}
429
430#else /* Other targets */
431void serial_setup (void)
432{
433 /* a dummy */
434}
435
436int tx_rdy(void)
437{
438 /* a dummy */
439 return 1;
440}
441
442int rx_rdy(void)
443{
444 /* a dummy */
445 return 0;
446}
447
448void tx_writec(unsigned char c)
449{
450 /* a dummy */
451}
452
453#endif
454
215void dprintf(const char * str, ... ) 455void dprintf(const char * str, ... )
216{ 456{
217 char dprintfbuff[256]; 457 char dprintfbuff[256];
218 unsigned char * ptr; 458 char * ptr;
219 459
220 va_list ap; 460 va_list ap;
221 va_start(ap, str); 461 va_start(ap, str);
@@ -224,7 +464,7 @@ void dprintf(const char * str, ... )
224 vsnprintf(ptr,sizeof(dprintfbuff),str,ap); 464 vsnprintf(ptr,sizeof(dprintfbuff),str,ap);
225 va_end(ap); 465 va_end(ap);
226 466
227 serial_tx(ptr); 467 serial_tx((unsigned char *)ptr);
228} 468}
229 469
230void serial_tx(const unsigned char * buf) 470void serial_tx(const unsigned char * buf)
@@ -241,10 +481,3 @@ void serial_tx(const unsigned char * buf)
241 } 481 }
242 } 482 }
243} 483}
244
245#else /* Other targets */
246void serial_setup (void)
247{
248 /* a dummy */
249}
250#endif
diff --git a/firmware/export/config-ipod4g.h b/firmware/export/config-ipod4g.h
index 89b14f9907..f6c71f39d8 100644
--- a/firmware/export/config-ipod4g.h
+++ b/firmware/export/config-ipod4g.h
@@ -186,4 +186,6 @@
186 186
187#define ICODE_ATTR_TREMOR_NOT_MDCT 187#define ICODE_ATTR_TREMOR_NOT_MDCT
188 188
189#define IPOD_ACCESSORY_PROTOCOL
190
189#endif 191#endif
diff --git a/firmware/export/config-ipodcolor.h b/firmware/export/config-ipodcolor.h
index 47b7a4eacf..58a888a969 100644
--- a/firmware/export/config-ipodcolor.h
+++ b/firmware/export/config-ipodcolor.h
@@ -166,4 +166,6 @@
166 166
167#define ICODE_ATTR_TREMOR_NOT_MDCT 167#define ICODE_ATTR_TREMOR_NOT_MDCT
168 168
169#define IPOD_ACCESSORY_PROTOCOL
170
169#endif 171#endif
diff --git a/firmware/export/config-ipodnano.h b/firmware/export/config-ipodnano.h
index 6017d0a2e8..8752181bb9 100644
--- a/firmware/export/config-ipodnano.h
+++ b/firmware/export/config-ipodnano.h
@@ -177,4 +177,6 @@
177 177
178#define ICODE_ATTR_TREMOR_NOT_MDCT 178#define ICODE_ATTR_TREMOR_NOT_MDCT
179 179
180#define IPOD_ACCESSORY_PROTOCOL
181
180#endif 182#endif
diff --git a/firmware/export/config-ipodvideo.h b/firmware/export/config-ipodvideo.h
index d04e562086..ab974dc236 100644
--- a/firmware/export/config-ipodvideo.h
+++ b/firmware/export/config-ipodvideo.h
@@ -197,4 +197,6 @@
197 197
198#define ICODE_ATTR_TREMOR_NOT_MDCT 198#define ICODE_ATTR_TREMOR_NOT_MDCT
199 199
200#define IPOD_ACCESSORY_PROTOCOL
201
200#endif 202#endif
diff --git a/firmware/export/iap.h b/firmware/export/iap.h
new file mode 100644
index 0000000000..6c0b968ab0
--- /dev/null
+++ b/firmware/export/iap.h
@@ -0,0 +1,31 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: iap.h 17400 2008-05-07 20:22:16Z xxxxxx $
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef __IAP_H__
21#define __IAP_H__
22
23extern int iap_getc(unsigned char x);
24extern void iap_write_pkt(unsigned char data, int len);
25extern void iap_setup(int ratenum);
26extern void iap_bitrate_set(int ratenum);
27extern void iap_periodic(void);
28extern void iap_handlepkt(void);
29extern void iap_track_changed(void);
30
31#endif
diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h
index ef65463e5d..29cf8f2eb9 100644
--- a/firmware/export/kernel.h
+++ b/firmware/export/kernel.h
@@ -78,6 +78,8 @@
78#define SYS_REMOTE_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 5) 78#define SYS_REMOTE_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 5)
79#define SYS_SCREENDUMP MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 0) 79#define SYS_SCREENDUMP MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 0)
80#define SYS_CAR_ADAPTER_RESUME MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 1) 80#define SYS_CAR_ADAPTER_RESUME MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 1)
81#define SYS_IAP_PERIODIC MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 2)
82#define SYS_IAP_HANDLEPKT MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 3)
81 83
82#define IS_SYSEVENT(ev) ((ev & SYS_EVENT) == SYS_EVENT) 84#define IS_SYSEVENT(ev) ((ev & SYS_EVENT) == SYS_EVENT)
83 85
diff --git a/firmware/export/serial.h b/firmware/export/serial.h
index 425fc66fc6..8a4780c3f1 100644
--- a/firmware/export/serial.h
+++ b/firmware/export/serial.h
@@ -22,8 +22,11 @@
22#ifndef __SERIAL_H__ 22#ifndef __SERIAL_H__
23#define __SERIAL_H__ 23#define __SERIAL_H__
24 24
25extern void serial_setup (void); 25extern void serial_setup(void);
26extern void serial_bitrate(int rate);
26extern int remote_control_rx(void); 27extern int remote_control_rx(void);
27extern void serial_tx(const unsigned char *buf); 28extern void serial_tx(const unsigned char *buf);
29extern void tx_writec(unsigned char c);
30extern int tx_rdy(void);
28 31
29#endif 32#endif
diff --git a/firmware/target/arm/ipod/button-clickwheel.c b/firmware/target/arm/ipod/button-clickwheel.c
index e36c928fb0..21bbca62f0 100644
--- a/firmware/target/arm/ipod/button-clickwheel.c
+++ b/firmware/target/arm/ipod/button-clickwheel.c
@@ -316,7 +316,11 @@ int button_read_device(void)
316 } 316 }
317 317
318 /* The int_btn variable is set in the button interrupt handler */ 318 /* The int_btn variable is set in the button interrupt handler */
319#ifdef IPOD_ACCESSORY_PROTOCOL
320 return int_btn | remote_control_rx();
321#else
319 return int_btn; 322 return int_btn;
323#endif
320} 324}
321 325
322bool button_hold(void) 326bool button_hold(void)
diff --git a/firmware/target/arm/ipod/button-target.h b/firmware/target/arm/ipod/button-target.h
index a0ac372839..67bdc72955 100644
--- a/firmware/target/arm/ipod/button-target.h
+++ b/firmware/target/arm/ipod/button-target.h
@@ -50,7 +50,22 @@ void ipod_4g_button_int(void);
50 |BUTTON_LEFT|BUTTON_RIGHT|BUTTON_SCROLL_FWD\ 50 |BUTTON_LEFT|BUTTON_RIGHT|BUTTON_SCROLL_FWD\
51 |BUTTON_SCROLL_BACK|BUTTON_PLAY) 51 |BUTTON_SCROLL_BACK|BUTTON_PLAY)
52 52
53 /* Remote control's buttons */
54#ifdef IPOD_ACCESSORY_PROTOCOL
55#define BUTTON_RC_PLAY 0x00100000
56#define BUTTON_RC_STOP 0x00080000
57
58#define BUTTON_RC_LEFT 0x00040000
59#define BUTTON_RC_RIGHT 0x00020000
60#define BUTTON_RC_VOL_UP 0x00010000
61#define BUTTON_RC_VOL_DOWN 0x00008000
62
63#define BUTTON_REMOTE (BUTTON_RC_PLAY|BUTTON_RC_STOP\
64 |BUTTON_RC_LEFT|BUTTON_RC_RIGHT\
65 |BUTTON_RC_VOL_UP|BUTTON_RC_VOL_DOWN)
66#else
53#define BUTTON_REMOTE 0 67#define BUTTON_REMOTE 0
68#endif
54 69
55/* This is for later 70/* This is for later
56#define BUTTON_SCROLL_TOUCH 0x00000200 71#define BUTTON_SCROLL_TOUCH 0x00000200
diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c
index d683b3a561..b1f178c8d5 100644
--- a/firmware/target/arm/system-pp502x.c
+++ b/firmware/target/arm/system-pp502x.c
@@ -32,6 +32,7 @@
32#ifndef BOOTLOADER 32#ifndef BOOTLOADER
33extern void TIMER1(void); 33extern void TIMER1(void);
34extern void TIMER2(void); 34extern void TIMER2(void);
35extern void SERIAL0(void);
35extern void ipod_mini_button_int(void); /* iPod Mini 1st gen only */ 36extern void ipod_mini_button_int(void); /* iPod Mini 1st gen only */
36extern void ipod_4g_button_int(void); /* iPod 4th gen and higher only */ 37extern void ipod_4g_button_int(void); /* iPod 4th gen and higher only */
37 38
@@ -78,6 +79,11 @@ void irq(void)
78 button_int(); 79 button_int();
79 } 80 }
80#endif 81#endif
82#ifdef IPOD_ACCESSORY_PROTOCOL
83 else if (CPU_HI_INT_STAT & SER0_MASK) {
84 SERIAL0();
85 }
86#endif
81#ifdef HAVE_USBSTACK 87#ifdef HAVE_USBSTACK
82 else if (CPU_INT_STAT & USB_MASK) { 88 else if (CPU_INT_STAT & USB_MASK) {
83 usb_drv_int(); 89 usb_drv_int();