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.zip
rockbox-70e9c7aed361787a404c4856211ddf53127fca9a.tar.gz
rockbox-70e9c7aed361787a404c4856211ddf53127fca9a.tar.bz2
rockbox-70e9c7aed361787a404c4856211ddf53127fca9a.tar.xz
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 c63bcb7..bd20136 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -52,6 +52,9 @@ tagtree.c
#endif
filetree.c
scrobbler.c
+#ifdef IPOD_ACCESSORY_PROTOCOL
+iap.c
+#endif
screen_access.c
#ifdef HAVE_BUTTONBAR
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index abb6018..f390cce 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1195,6 +1195,14 @@ bool dbg_ports(void)
lcd_puts(0, line++, buf);
#endif
+#if defined(IPOD_ACCESSORY_PROTOCOL)
+extern unsigned char serbuf[];
+ snprintf(buf, sizeof(buf), "IAP PACKET: %02x %02x %02x %02x %02x %02x %02x %02x",
+ serbuf[0], serbuf[1], serbuf[2], serbuf[3], serbuf[4], serbuf[5],
+ serbuf[6], serbuf[7]);
+ lcd_puts(0, line++, buf);
+#endif
+
#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
line++;
snprintf(buf, sizeof(buf), "BATT: %03x UNK1: %03x",
diff --git a/apps/features.txt b/apps/features.txt
index 0ddccce..4fbf427 100644
--- a/apps/features.txt
+++ b/apps/features.txt
@@ -181,3 +181,7 @@ usbstack
#if defined(HAVE_ACCESSORY_SUPPLY)
accessory_supply
#endif
+
+#if defined(IPOD_ACCESSORY_PROTOCOL)
+serial_port
+#endif
diff --git a/apps/iap.c b/apps/iap.c
new file mode 100644
index 0000000..a15fd81
--- /dev/null
+++ b/apps/iap.c
@@ -0,0 +1,730 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: iap.c 17400 2008-05-07 14:30:29Z xxxxxx $
+ *
+ * Copyright (C) 2002 by Alan Korr & Nick Robinson
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <memory.h>
+#include <string.h>
+
+#include "iap.h"
+#include "button.h"
+#include "config.h"
+#include "cpu.h"
+#include "system.h"
+#include "kernel.h"
+#include "serial.h"
+
+#include "playlist.h"
+#include "playback.h"
+#include "audio.h"
+#include "settings.h"
+#include "metadata.h"
+#include "gwps.h"
+
+#include "button.h"
+#include "action.h"
+
+#define RX_BUFLEN 260
+#define TX_BUFLEN 128
+
+static volatile int iap_pollspeed = 0;
+static volatile bool iap_remotetick = true;
+static bool iap_setupflag = false, iap_updateflag = false;
+static int iap_changedctr = 0;
+
+static unsigned long iap_remotebtn = 0;
+static int iap_repeatbtn = 0;
+static bool iap_btnrepeat = false, iap_btnshuffle = false;
+
+unsigned char serbuf[RX_BUFLEN];
+static int serbuf_i = 0;
+
+static unsigned char response[TX_BUFLEN];
+static int responselen;
+
+static void iap_task(void)
+{
+ static int count = 0;
+
+ count += iap_pollspeed;
+ if (count < (500/10)) return;
+
+ /* exec every 500ms if pollspeed == 1 */
+ count = 0;
+ queue_post(&button_queue, SYS_IAP_PERIODIC, 0);
+}
+
+void iap_setup(int ratenum)
+{
+ iap_bitrate_set(ratenum);
+ iap_pollspeed = 0;
+ iap_remotetick = true;
+ iap_updateflag = false;
+ iap_changedctr = 0;
+ iap_setupflag = true;
+ iap_remotebtn = BUTTON_NONE;
+ tick_add_task(iap_task);
+}
+
+void iap_bitrate_set(int ratenum)
+{
+ switch(ratenum)
+ {
+ case 0:
+ serial_bitrate(0);
+ break;
+ case 1:
+ serial_bitrate(9600);
+ break;
+ case 2:
+ serial_bitrate(19200);
+ break;
+ case 3:
+ serial_bitrate(38400);
+ break;
+ case 4:
+ serial_bitrate(57600);
+ break;
+ }
+}
+
+/* Message format:
+ 0xff
+ 0x55
+ length
+ mode
+ command (2 bytes)
+ parameters (0-n bytes)
+ checksum (length+mode+parameters+checksum == 0)
+*/
+
+void iap_send_pkt(unsigned char * data, int len)
+{
+ int i, chksum;
+
+ if(len > TX_BUFLEN-4) len = TX_BUFLEN-4;
+ responselen = len + 4;
+
+ response[0] = 0xFF;
+ response[1] = 0x55;
+
+ chksum = response[2] = len;
+ for(i = 0; i < len; i ++)
+ {
+ chksum += data[i];
+ response[i+3] = data[i];
+ }
+
+ response[i+3] = 0x100 - (chksum & 0xFF);
+
+ for(i = 0; i < responselen; i ++)
+ {
+ while (!tx_rdy()) ;
+ tx_writec(response[i]);
+ }
+}
+
+int iap_getc(unsigned char x)
+{
+ static unsigned char last_x = 0;
+ static bool newpkt = true;
+ static unsigned char chksum = 0;
+
+ /* Restart if the sync word is seen */
+ if(x == 0x55 && last_x == 0xff/* && newpkt*/)
+ {
+ serbuf[0] = 0;
+ serbuf_i = 0;
+ chksum = 0;
+ newpkt = false;
+ }
+ else
+ {
+ if(serbuf_i >= RX_BUFLEN)
+ serbuf_i = 0;
+
+ serbuf[serbuf_i++] = x;
+ chksum += x;
+ }
+ last_x = x;
+
+ /* Broadcast to queue if we have a complete message */
+ if(serbuf_i && (serbuf_i == serbuf[0]+2))
+ {
+ serbuf_i = 0;
+ newpkt = true;
+ if(chksum == 0)
+ queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
+ }
+ return newpkt;
+}
+
+void iap_track_changed(void)
+{
+ iap_changedctr = 1;
+}
+
+void iap_periodic(void)
+{
+ if(!iap_setupflag) return;
+ if(!iap_pollspeed) return;
+
+ unsigned char data[] = {0x04, 0x00, 0x27, 0x04, 0x00, 0x00, 0x00, 0x00};
+ unsigned long time_elapsed = audio_current_track()->elapsed;
+
+ time_elapsed += wps_state.ff_rewind_count;
+
+ data[3] = 0x04; // playing
+
+ /* If info has changed, don't flag it right away */
+ if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2)
+ {
+ /* track info has changed */
+ iap_changedctr = 0;
+ data[3] = 0x01; // 0x02 has same effect?
+ iap_updateflag = true;
+ }
+
+ data[4] = time_elapsed >> 24;
+ data[5] = time_elapsed >> 16;
+ data[6] = time_elapsed >> 8;
+ data[7] = time_elapsed;
+ iap_send_pkt(data, sizeof(data));
+}
+
+void iap_handlepkt(void)
+{
+
+ if(!iap_setupflag) return;
+ if(serbuf[0] == 0) return;
+
+ /* if we are waiting for a remote button to go out,
+ delay the handling of the new packet */
+ if(!iap_remotetick)
+ {
+ queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
+ return;
+ }
+
+ /* Handle Mode 0 */
+ if (serbuf[1] == 0x00)
+ {
+ switch (serbuf[2])
+ {
+ /* get model info */
+ case 0x0D:
+ {
+ unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
+ 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* No idea ??? */
+ case 0x0F:
+ {
+ unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* FM transmitter sends this: FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
+ case 0x01:
+ {
+ if(serbuf[3] == 0x05)
+ {
+ sleep(HZ/3);
+ unsigned char data[] = {0x05, 0x02};
+ iap_send_pkt(data, sizeof(data));
+ }
+ break;
+ }
+ /* FM transmitter sends this: FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (???)*/
+ case 0x13:
+ {
+ unsigned char data[] = {0x00, 0x02, 0x00, 0x13};
+ iap_send_pkt(data, sizeof(data));
+ unsigned char data2[] = {0x00, 0x27, 0x00};
+ iap_send_pkt(data2, sizeof(data2));
+ unsigned char data3[] = {0x05, 0x02};
+ iap_send_pkt(data3, sizeof(data3));
+ break;
+ }
+ /* FM transmitter sends this: FF 55 02 00 05 F9 (mode switch: AiR mode) */
+ case 0x05:
+ {
+ unsigned char data[] = {0x00, 0x02, 0x06, 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28};
+ iap_send_pkt(data, sizeof(data));
+ unsigned char data2[] = {0x00, 0x02, 0x00, 0x05};
+ iap_send_pkt(data2, sizeof(data2));
+ break;
+ }
+ /* default response is with cmd ok packet */
+ default:
+ {
+ unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
+ data[3] = serbuf[2]; //respond with cmd
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ }
+ }
+ /* Handle Mode 2 */
+ else if (serbuf[1] == 0x02)
+ {
+ if(serbuf[2] != 0) return;
+ iap_remotebtn = BUTTON_NONE;
+ iap_remotetick = false;
+
+ if(serbuf[0] >= 3 && serbuf[3] != 0)
+ {
+ if(serbuf[3] & 1)
+ iap_remotebtn |= BUTTON_RC_PLAY;
+ if(serbuf[3] & 2)
+ iap_remotebtn |= BUTTON_RC_VOL_UP;
+ if(serbuf[3] & 4)
+ iap_remotebtn |= BUTTON_RC_VOL_DOWN;
+ if(serbuf[3] & 8)
+ iap_remotebtn |= BUTTON_RC_RIGHT;
+ if(serbuf[3] & 16)
+ iap_remotebtn |= BUTTON_RC_LEFT;
+ }
+ else if(serbuf[0] >= 4 && serbuf[4] != 0)
+ {
+ if(serbuf[4] & 1) /* play */
+ {
+ if (audio_status() != AUDIO_STATUS_PLAY)
+ {
+ iap_remotebtn |= BUTTON_RC_PLAY;
+ iap_repeatbtn = 2;
+ iap_remotetick = false;
+ iap_changedctr = 1;
+ }
+ }
+ if(serbuf[4] & 2) /* pause */
+ {
+ if (audio_status() == AUDIO_STATUS_PLAY)
+ {
+ iap_remotebtn |= BUTTON_RC_PLAY;
+ iap_repeatbtn = 2;
+ iap_remotetick = false;
+ iap_changedctr = 1;
+ }
+ }
+ if((serbuf[4] & 128) && !iap_btnshuffle) /* shuffle */
+ {
+ iap_btnshuffle = true;
+ if(!global_settings.playlist_shuffle)
+ {
+ global_settings.playlist_shuffle = 1;
+ settings_save();
+ settings_apply(false);
+ if (audio_status() & AUDIO_STATUS_PLAY)
+ playlist_randomise(NULL, current_tick, true);
+ }
+ else if(global_settings.playlist_shuffle)
+ {
+ global_settings.playlist_shuffle = 0;
+ settings_save();
+ settings_apply(false);
+ if (audio_status() & AUDIO_STATUS_PLAY)
+ playlist_sort(NULL, true);
+ }
+ }
+ else
+ iap_btnshuffle = false;
+ }
+ else if(serbuf[0] >= 5 && serbuf[5] != 0)
+ {
+ if((serbuf[5] & 1) && !iap_btnrepeat) /* repeat */
+ {
+ int oldmode = global_settings.repeat_mode;
+ iap_btnrepeat = true;
+
+ if (oldmode == REPEAT_ONE)
+ global_settings.repeat_mode = REPEAT_OFF;
+ else if (oldmode == REPEAT_ALL)
+ global_settings.repeat_mode = REPEAT_ONE;
+ else if (oldmode == REPEAT_OFF)
+ global_settings.repeat_mode = REPEAT_ALL;
+
+ settings_save();
+ settings_apply(false);
+ if (audio_status() & AUDIO_STATUS_PLAY)
+ audio_flush_and_reload_tracks();
+ }
+ else
+ iap_btnrepeat = false;
+
+ if(serbuf[5] & 16) /* ffwd */
+ {
+ iap_remotebtn |= BUTTON_RC_RIGHT;
+ }
+ if(serbuf[5] & 32) /* frwd */
+ {
+ iap_remotebtn |= BUTTON_RC_LEFT;
+ }
+ }
+ }
+ /* Handle Mode 3 */
+ else if (serbuf[1] == 0x03)
+ {
+ switch(serbuf[2])
+ {
+ /* some kind of status packet? */
+ case 0x01:
+ {
+ unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ }
+ }
+ /* Handle Mode 4 */
+ else if (serbuf[1] == 0x04)
+ {
+ switch (((unsigned long)serbuf[2] << 8) | serbuf[3])
+ {
+ /* Get data updated??? flag */
+ case 0x0009:
+ {
+ unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
+ data[3] = iap_updateflag ? 0 : 1;
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Set data updated??? flag */
+ case 0x000B:
+ {
+ iap_updateflag = serbuf[4] ? 0 : 1;
+ /* respond with cmd ok packet */
+ unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x0B};
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Get iPod size? */
+ case 0x0012:
+ {
+ unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Get count of given types */
+ case 0x0018:
+ {
+ unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
+ unsigned long num = 0;
+ switch(serbuf[4]) /* type number */
+ {
+ case 0x01: /* total number of playlists */
+ num = 1;
+ break;
+ case 0x05: /* total number of songs */
+ num = 1;
+ }
+ data[3] = num >> 24;
+ data[4] = num >> 16;
+ data[5] = num >> 8;
+ data[6] = num;
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Get time and status */
+ case 0x001C:
+ {
+ unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ struct mp3entry *id3 = audio_current_track();
+ unsigned long time_total = id3->length;
+ unsigned long time_elapsed = id3->elapsed;
+ int status = audio_status();
+ data[3] = time_total >> 24;
+ data[4] = time_total >> 16;
+ data[5] = time_total >> 8;
+ data[6] = time_total;
+ data[7] = time_elapsed >> 24;
+ data[8] = time_elapsed >> 16;
+ data[9] = time_elapsed >> 8;
+ data[10] = time_elapsed;
+ if (status == AUDIO_STATUS_PLAY)
+ data[11] = 0x01; /* play */
+ else if (status & AUDIO_STATUS_PAUSE)
+ data[11] = 0x02; /* pause */
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Get current pos in playlist */
+ case 0x001E:
+ {
+ unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
+ long playlist_pos = playlist_next(0);
+ playlist_pos -= playlist_get_first_index(NULL);
+ if(playlist_pos < 0)
+ playlist_pos += playlist_amount();
+ data[3] = playlist_pos >> 24;
+ data[4] = playlist_pos >> 16;
+ data[5] = playlist_pos >> 8;
+ data[6] = playlist_pos;
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Get title of a song number */
+ case 0x0020:
+ /* Get artist of a song number */
+ case 0x0022:
+ /* Get album of a song number */
+ case 0x0024:
+ {
+ unsigned char data[70] = {0x04, 0x00, 0xFF};
+ struct mp3entry id3;
+ int fd;
+ long tracknum = (signed long)serbuf[4] << 24 |
+ (signed long)serbuf[5] << 16 |
+ (signed long)serbuf[6] << 8 | serbuf[7];
+ data[2] = serbuf[3] + 1;
+ memcpy(&id3, audio_current_track(), sizeof(id3));
+ tracknum += playlist_get_first_index(NULL);
+ if(tracknum >= playlist_amount())
+ tracknum -= playlist_amount();
+
+ /* If the tracknumber is not the current one,
+ read id3 from disk */
+ if(playlist_next(0) != tracknum)
+ {
+ struct playlist_track_info info;
+ playlist_get_track_info(NULL, tracknum, &info);
+ fd = open(info.filename, O_RDONLY);
+ memset(&id3, 0, sizeof(struct mp3entry));
+ get_metadata(&id3, fd, info.filename);
+ close(fd);
+ }
+
+ /* Return the requested track data */
+ switch(serbuf[3])
+ {
+ case 0x20:
+ strncpy((char *)&data[3], id3.title, 64);
+ iap_send_pkt(data, 4+strlen(id3.title));
+ break;
+ case 0x22:
+ strncpy((char *)&data[3], id3.artist, 64);
+ iap_send_pkt(data, 4+strlen(id3.artist));
+ break;
+ case 0x24:
+ strncpy((char *)&data[3], id3.album, 64);
+ iap_send_pkt(data, 4+strlen(id3.album));
+ break;
+ }
+ break;
+ }
+ /* Set polling mode */
+ case 0x0026:
+ {
+ iap_pollspeed = serbuf[4] ? 1 : 0;
+ /*responsed with cmd ok packet */
+ unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x26};
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* AiR playback control */
+ case 0x0029:
+ {
+ /* respond with cmd ok packet */
+ unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
+ iap_send_pkt(data, sizeof(data));
+ switch(serbuf[4])
+ {
+ case 0x01: /* play/pause */
+ iap_remotebtn = BUTTON_RC_PLAY;
+ iap_repeatbtn = 2;
+ iap_remotetick = false;
+ iap_changedctr = 1;
+ break;
+ case 0x02: /* stop */
+ iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
+ iap_repeatbtn = 2;
+ iap_remotetick = false;
+ iap_changedctr = 1;
+ break;
+ case 0x03: /* skip++ */
+ iap_remotebtn = BUTTON_RC_RIGHT;
+ iap_repeatbtn = 2;
+ iap_remotetick = false;
+ break;
+ case 0x04: /* skip-- */
+ iap_remotebtn = BUTTON_RC_LEFT;
+ iap_repeatbtn = 2;
+ iap_remotetick = false;
+ break;
+ case 0x05: /* ffwd */
+ iap_remotebtn = BUTTON_RC_RIGHT;
+ iap_remotetick = false;
+ if(iap_pollspeed) iap_pollspeed = 5;
+ break;
+ case 0x06: /* frwd */
+ iap_remotebtn = BUTTON_RC_LEFT;
+ iap_remotetick = false;
+ if(iap_pollspeed) iap_pollspeed = 5;
+ break;
+ case 0x07: /* end ffwd/frwd */
+ iap_remotebtn = BUTTON_NONE;
+ iap_remotetick = false;
+ if(iap_pollspeed) iap_pollspeed = 1;
+ break;
+ }
+ break;
+ }
+ /* Get shuffle mode */
+ case 0x002C:
+ {
+ unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
+ data[3] = global_settings.playlist_shuffle ? 1 : 0;
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Set shuffle mode */
+ case 0x002E:
+ {
+ if(serbuf[4] && !global_settings.playlist_shuffle)
+ {
+ global_settings.playlist_shuffle = 1;
+ settings_save();
+ settings_apply(false);
+ if (audio_status() & AUDIO_STATUS_PLAY)
+ playlist_randomise(NULL, current_tick, true);
+ }
+ else if(!serbuf[4] && global_settings.playlist_shuffle)
+ {
+ global_settings.playlist_shuffle = 0;
+ settings_save();
+ settings_apply(false);
+ if (audio_status() & AUDIO_STATUS_PLAY)
+ playlist_sort(NULL, true);
+ }
+
+
+ /* respond with cmd ok packet */
+ unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x2E};
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Get repeat mode */
+ case 0x002F:
+ {
+ unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
+ if(global_settings.repeat_mode == REPEAT_OFF)
+ data[3] = 0;
+ else if(global_settings.repeat_mode == REPEAT_ONE)
+ data[3] = 1;
+ else
+ data[3] = 2;
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Set repeat mode */
+ case 0x0031:
+ {
+ int oldmode = global_settings.repeat_mode;
+ if (serbuf[4] == 0)
+ global_settings.repeat_mode = REPEAT_OFF;
+ else if (serbuf[4] == 1)
+ global_settings.repeat_mode = REPEAT_ONE;
+ else if (serbuf[4] == 2)
+ global_settings.repeat_mode = REPEAT_ALL;
+
+ if (oldmode != global_settings.repeat_mode)
+ {
+ settings_save();
+ settings_apply(false);
+ if (audio_status() & AUDIO_STATUS_PLAY)
+ audio_flush_and_reload_tracks();
+ }
+
+ /* respond with cmd ok packet */
+ unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x31};
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Get Max Screen Size for Picture Upload??? */
+ case 0x0033:
+ {
+ unsigned char data[] = {0x04, 0x00, 0x34, 0x01, 0x36, 0x00, 0xA8, 0x01};
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Get number songs in current playlist */
+ case 0x0035:
+ {
+ unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
+ unsigned long playlist_amt = playlist_amount();
+ data[3] = playlist_amt >> 24;
+ data[4] = playlist_amt >> 16;
+ data[5] = playlist_amt >> 8;
+ data[6] = playlist_amt;
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ /* Jump to track number in current playlist */
+ case 0x0037:
+ {
+ long tracknum = (signed long)serbuf[4] << 24 |
+ (signed long)serbuf[5] << 16 |
+ (signed long)serbuf[6] << 8 | serbuf[7];
+ if (!wps_state.paused)
+ audio_pause();
+ audio_skip(tracknum - playlist_next(0));
+ if (!wps_state.paused)
+ audio_resume();
+
+ /* respond with cmd ok packet */
+ unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
+ data[4] = serbuf[2];
+ data[5] = serbuf[3];
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ default:
+ {
+ /* default response is with cmd ok packet */
+ unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
+ data[4] = serbuf[2];
+ data[5] = serbuf[3];
+ iap_send_pkt(data, sizeof(data));
+ break;
+ }
+ }
+ }
+ serbuf[0] = 0;
+}
+
+int remote_control_rx(void)
+{
+ int btn = iap_remotebtn;
+ if(iap_repeatbtn)
+ {
+ iap_repeatbtn--;
+ if(!iap_repeatbtn)
+ {
+ iap_remotebtn = BUTTON_NONE;
+ iap_remotetick = true;
+ }
+ }
+ else
+ iap_remotetick = true;
+
+ return btn;
+}
diff --git a/apps/keymaps/keymap-ipod.c b/apps/keymaps/keymap-ipod.c
index 5b735eb..0285452 100644
--- a/apps/keymaps/keymap-ipod.c
+++ b/apps/keymaps/keymap-ipod.c
@@ -187,9 +187,62 @@ const struct button_mapping button_context_recscreen[] = {
}; /* button_context_recscreen */
#endif
+#if BUTTON_REMOTE != 0
+/*****************************************************************************
+ * Remote control mappings
+ *****************************************************************************/
+
+static const struct button_mapping remote_button_context_standard[] = {
+ { ACTION_STD_PREV, BUTTON_RC_LEFT, BUTTON_NONE },
+ { ACTION_STD_NEXT, BUTTON_RC_RIGHT, BUTTON_NONE },
+ { ACTION_STD_CANCEL, BUTTON_RC_STOP, BUTTON_NONE },
+ { ACTION_STD_OK, BUTTON_RC_PLAY, BUTTON_NONE },
+
+ LAST_ITEM_IN_LIST
+};
+
+static const struct button_mapping remote_button_context_wps[] = {
+ { ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN, BUTTON_NONE },
+ { ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP, BUTTON_NONE },
+ { ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
+
+ { ACTION_WPS_PLAY, BUTTON_RC_PLAY|BUTTON_REL, BUTTON_RC_PLAY },
+ { ACTION_WPS_STOP, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_WPS_SKIPNEXT, BUTTON_RC_RIGHT|BUTTON_REL, BUTTON_RC_RIGHT },
+ { ACTION_WPS_SEEKFWD, BUTTON_RC_RIGHT|BUTTON_REPEAT,BUTTON_NONE },
+ { ACTION_WPS_STOPSEEK, BUTTON_RC_RIGHT|BUTTON_REL, BUTTON_RC_RIGHT|BUTTON_REPEAT },
+ { ACTION_WPS_SKIPPREV, BUTTON_RC_LEFT|BUTTON_REL, BUTTON_RC_LEFT },
+ { ACTION_WPS_SEEKBACK, BUTTON_RC_LEFT|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_WPS_STOPSEEK, BUTTON_RC_LEFT|BUTTON_REL, BUTTON_RC_LEFT|BUTTON_REPEAT },
+
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+};
+
+
+static const struct button_mapping* get_context_mapping_remote( int context )
+{
+ context ^= CONTEXT_REMOTE;
+
+ switch (context)
+ {
+ case CONTEXT_WPS:
+ return remote_button_context_wps;
+
+ default:
+ return remote_button_context_standard;
+ }
+}
+#endif /* BUTTON_REMOTE != 0 */
+
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
+#if BUTTON_REMOTE != 0
+ if (context&CONTEXT_REMOTE)
+ return get_context_mapping_remote(context);
+#endif
+
switch (context)
{
case CONTEXT_STD:
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index f0099e4..f5f9ed3 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -11811,6 +11811,110 @@
gigabeatf: "High"
</voice>
</phrase>
+<<<<<<< .mine
+<phrase>
+ id: LANG_SERIAL_BITRATE
+ desc: in system settings menu
+ user:
+ <source>
+ *: none
+ serial_port: "Serial Bitrate"
+ </source>
+ <dest>
+ *: none
+ serial_port: "Serial Bitrate"
+ </dest>
+ <voice>
+ *: none
+ serial_port: "Serial Bitrate"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_SERIAL_BITRATE_AUTO
+ desc: in system settings menu
+ user:
+ <source>
+ *: none
+ serial_port: "Auto"
+ </source>
+ <dest>
+ *: none
+ serial_port: "Auto"
+ </dest>
+ <voice>
+ *: none
+ serial_port: "Automatic"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_SERIAL_BITRATE_9600
+ desc: in system settings menu
+ user:
+ <source>
+ *: none
+ serial_port: "9600"
+ </source>
+ <dest>
+ *: none
+ serial_port: "9600"
+ </dest>
+ <voice>
+ *: none
+ serial_port: "9600"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_SERIAL_BITRATE_19200
+ desc: in system settings menu
+ user:
+ <source>
+ *: none
+ serial_port: "19200"
+ </source>
+ <dest>
+ *: none
+ serial_port: "19200"
+ </dest>
+ <voice>
+ *: none
+ serial_port: "19200"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_SERIAL_BITRATE_38400
+ desc: in system settings menu
+ user:
+ <source>
+ *: none
+ serial_port: "38400"
+ </source>
+ <dest>
+ *: none
+ serial_port: "38400"
+ </dest>
+ <voice>
+ *: none
+ serial_port: "38400"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_SERIAL_BITRATE_57600
+ desc: in system settings menu
+ user:
+ <source>
+ *: none
+ serial_port: "57600"
+ </source>
+ <dest>
+ *: none
+ serial_port: "57600"
+ </dest>
+ <voice>
+ *: none
+ serial_port: "57600"
+ </voice>
+</phrase>
+=======
<phrase>
id: LANG_VERY_SLOW
desc: in settings_menu
@@ -11909,6 +12013,9 @@
*: "slash"
</voice>
</phrase>
+<<<<<<< .mine
+>>>>>>> .r18116
+=======
<phrase>
id: LANG_GAIN_LEFT
desc: in the recording screen
@@ -12110,6 +12217,9 @@
*: "Search Results"
</voice>
</phrase>
+<<<<<<< .mine
+>>>>>>> .r18870
+=======
<phrase>
id: LANG_QS_ITEMS
desc: DEPRECATED
@@ -12243,3 +12353,4 @@
quickscreen: "Set as Bottom Quickscreen Item"
</voice>
</phrase>
+>>>>>>> .r19041
diff --git a/apps/main.c b/apps/main.c
index 111c5d1..45e6c77 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -73,6 +73,10 @@
#include "scrobbler.h"
#include "icon.h"
+#ifdef IPOD_ACCESSORY_PROTOCOL
+#include "iap.h"
+#endif
+
#if (CONFIG_CODEC == SWCODEC)
#include "playback.h"
#endif
@@ -583,6 +587,9 @@ static void init(void)
#if CONFIG_CHARGING
car_adapter_mode_init();
#endif
+#ifdef IPOD_ACCESSORY_PROTOCOL
+ iap_setup(global_settings.serial_bitrate);
+#endif
#ifdef HAVE_ACCESSORY_SUPPLY
accessory_supply_set(global_settings.accessory_supply);
#endif
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index d05726e..b6e5ad4 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);
#if CONFIG_CHARGING
MENUITEM_SETTING(car_adapter_mode, &global_settings.car_adapter_mode, NULL);
#endif
+#ifdef IPOD_ACCESSORY_PROTOCOL
+MENUITEM_SETTING(serial_bitrate, &global_settings.serial_bitrate, NULL);
+#endif
#ifdef HAVE_ACCESSORY_SUPPLY
MENUITEM_SETTING(accessory_supply, &global_settings.accessory_supply, NULL);
#endif
@@ -282,6 +285,9 @@ MAKE_MENU(system_menu, ID2P(LANG_SYSTEM),
#if CONFIG_CHARGING
&car_adapter_mode,
#endif
+#ifdef IPOD_ACCESSORY_PROTOCOL,
+ &serial_bitrate,
+#endif
#ifdef HAVE_ACCESSORY_SUPPLY
&accessory_supply,
#endif
diff --git a/apps/misc.c b/apps/misc.c
index 11cdee1..8b73411 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -61,6 +61,10 @@
#include "playlist.h"
#include "yesno.h"
+#ifdef IPOD_ACCESSORY_PROTOCOL
+#include "iap.h"
+#endif
+
#if (CONFIG_STORAGE & STORAGE_MMC)
#include "ata_mmc.h"
#endif
@@ -959,6 +963,14 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
unplug_change(false);
return SYS_PHONE_UNPLUGGED;
#endif
+#ifdef IPOD_ACCESSORY_PROTOCOL
+ case SYS_IAP_PERIODIC:
+ iap_periodic();
+ return SYS_IAP_PERIODIC;
+ case SYS_IAP_HANDLEPKT:
+ iap_handlepkt();
+ return SYS_IAP_HANDLEPKT;
+#endif
}
return 0;
}
diff --git a/apps/playback.c b/apps/playback.c
index d2d9bb6..0f76666 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -82,6 +82,10 @@
#include "pcm_record.h"
#endif
+#ifdef IPOD_ACCESSORY_PROTOCOL
+#include "iap.h"
+#endif
+
#define PLAYBACK_VOICE
/* default point to start buffer refill */
@@ -646,6 +650,9 @@ bool audio_has_changed_track(void)
{
if (track_changed)
{
+#ifdef IPOD_ACCESSORY_PROTOCOL
+ iap_track_changed();
+#endif
track_changed = false;
return true;
}
@@ -691,7 +698,7 @@ void audio_resume(void)
queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
}
-static void audio_skip(int direction)
+void audio_skip(int direction)
{
if (playlist_check(ci.new_track + wps_offset + direction))
{
diff --git a/apps/playback.h b/apps/playback.h
index d9f29cc..e65d5da 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -33,7 +33,7 @@ int audio_track_count(void);
long audio_filebufused(void);
void audio_pre_ff_rewind(void);
void audio_set_crossfade(int type);
-
+void audio_skip(int direction);
void audio_hard_stop(void); /* Stops audio from serving playback */
enum
diff --git a/apps/settings.h b/apps/settings.h
index b011787..f9b3239 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -488,6 +488,9 @@ struct user_settings
bool peak_meter_clipcounter; /* clipping count indicator */
#endif
bool car_adapter_mode; /* 0=off 1=on */
+#ifdef IPOD_ACCESSORY_PROTOCOL
+ int serial_bitrate; /* 0=auto 1=9600 2=19200 3=38400 4=57600 */
+#endif
#ifdef HAVE_ACCESSORY_SUPPLY
bool accessory_supply; /* 0=off 1=on, accessory power supply for iPod */
#endif
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 27739b2..e387456 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -49,6 +49,9 @@
#if CONFIG_TUNER
#include "radio.h"
#endif
+#ifdef IPOD_ACCESSORY_PROTOCOL
+#include "iap.h"
+#endif
#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT)
/** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h
@@ -595,6 +598,12 @@ const struct settings_list settings[] = {
OFFON_SETTING(NVRAM(1), car_adapter_mode,
LANG_CAR_ADAPTER_MODE, false, "car adapter mode", NULL),
#endif
+#ifdef IPOD_ACCESSORY_PROTOCOL
+ CHOICE_SETTING(0, serial_bitrate, LANG_SERIAL_BITRATE, 0, "serial bitrate",
+ "auto,9600,19200,38400,57600", iap_bitrate_set, 5, ID2P(LANG_SERIAL_BITRATE_AUTO),
+ ID2P(LANG_SERIAL_BITRATE_9600),ID2P(LANG_SERIAL_BITRATE_19200),
+ ID2P(LANG_SERIAL_BITRATE_38400),ID2P(LANG_SERIAL_BITRATE_57600)),
+#endif
#ifdef HAVE_ACCESSORY_SUPPLY
OFFON_SETTING(0, accessory_supply, LANG_ACCESSORY_SUPPLY,
true, "accessory power supply", accessory_supply_set),
diff --git a/firmware/drivers/serial.c b/firmware/drivers/serial.c
index 47fbf56..a496824 100644
--- a/firmware/drivers/serial.c
+++ b/firmware/drivers/serial.c
@@ -18,7 +18,9 @@
* KIND, either express or implied.
*
****************************************************************************/
+#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include "button.h"
#include "config.h"
#include "cpu.h"
@@ -28,6 +30,7 @@
#include "adc.h"
#include "lcd.h"
#include "serial.h"
+#include "iap.h"
#if CONFIG_CPU == IMX31L
#include "serial-imx31.h"
@@ -68,6 +71,35 @@ void serial_setup (void)
SCR1 = 0x10; /* Enable the receiver, no interrupt */
}
+int tx_rdy(void)
+{
+ /* a dummy */
+ return 1;
+}
+
+int rx_rdy(void)
+{
+ if(SSR1 & SCI_RDRF)
+ return 1;
+ else
+ return 0;
+}
+
+void tx_writec(unsigned char c)
+{
+ /* a dummy */
+}
+
+unsigned char rx_readc(void)
+{
+ char tmp;
+ /* Read byte and clear the Rx Full bit */
+ tmp = RDR1;
+ and_b(~SCI_RDRF, &SSR1);
+ return tmp;
+}
+
+
/* This function returns the received remote control code only if it is
received without errors before or after the reception.
It therefore returns the received code on the second call after the
@@ -87,11 +119,9 @@ int remote_control_rx(void)
return BUTTON_NONE;
}
- if(SSR1 & SCI_RDRF) {
- /* Read byte and clear the Rx Full bit */
- btn = RDR1;
- and_b(~SCI_RDRF, &SSR1);
-
+ if(rx_rdy()) {
+ btn = rx_readc();
+
if(last_was_error)
{
last_valid_button = BUTTON_NONE;
@@ -149,16 +179,6 @@ int remote_control_rx(void)
#endif /* !HAVE_FMADC && !STORAGE_MMC */
#elif defined(CPU_COLDFIRE) && defined(HAVE_SERIAL)
-void serial_tx(const unsigned char *buf)
-{
- while(*buf) {
- while(!(USR0 & 0x04))
- {
- };
- UTB0 = *buf++;
- }
-}
-
void serial_setup (void)
{
UCR0 = 0x30; /* Reset transmitter */
@@ -171,6 +191,25 @@ void serial_setup (void)
UCR0 = 0x04; /* Tx enable */
}
+int tx_rdy(void)
+{
+ if(USR0 & 0x04)
+ return 1;
+ else
+ return 0;
+}
+
+int rx_rdy(void)
+{
+ /* a dummy */
+ return 0;
+}
+
+void tx_writec(unsigned char c)
+{
+ UTB0 = c;
+}
+
#elif (CONFIG_CPU == IMX31L)
void serial_setup(void)
@@ -207,15 +246,216 @@ int rx_rdy(void)
return 0;
}
-void tx_writec(char c)
+void tx_writec(unsigned char c)
{
UTXD1=(int) c;
}
+#elif defined(IPOD_ACCESSORY_PROTOCOL)
+static int autobaud = 0;
+void serial_setup (void)
+{
+ int tmp;
+
+#if (MODEL_NUMBER == 3) || (MODEL_NUMBER == 8)
+
+ /* Route the Tx/Rx pins. 4G Ipod??? */
+ outl(0x70000018, inl(0x70000018) & ~0xc00);
+#elif (MODEL_NUMBER == 4) || (MODEL_NUMBER == 5)
+
+ /* Route the Tx/Rx pins. 5G Ipod */
+ (*(volatile unsigned long *)(0x7000008C)) &= ~0x0C;
+ GPO32_ENABLE &= ~0x0C;
+#endif
+
+ DEV_EN = DEV_EN | DEV_SER0;
+ CPU_HI_INT_DIS = SER0_MASK;
+
+ DEV_RS |= DEV_SER0;
+ sleep(1);
+ DEV_RS &= ~DEV_SER0;
+
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLM = 0x00;
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ SER0_IER = 0x01;
+
+ SER0_FCR = 0x07; /* Tx+Rx FIFO reset and FIFO enable */
+
+ CPU_INT_EN |= HI_MASK;
+ CPU_HI_INT_EN |= SER0_MASK;
+ tmp = SER0_RBR;
+
+ serial_bitrate(0);
+}
+
+void serial_bitrate(int rate)
+{
+ if(rate == 0)
+ {
+ autobaud = 2;
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 0x0D; /* 24000000/13/16 = 115384 baud */
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ return;
+ }
+
+ autobaud = 0;
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 24000000L / rate / 16;
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+}
+
+int tx_rdy(void)
+{
+ if((SER0_LSR & 0x20))
+ return 1;
+ else
+ return 0;
+}
+
+int rx_rdy(void)
+{
+ if((SER0_LSR & 0x1))
+ return 1;
+ else
+ return 0;
+}
+
+void tx_writec(unsigned char c)
+{
+ SER0_THR =(int) c;
+}
+
+unsigned char rx_readc(void)
+{
+ return (SER0_RBR & 0xFF);
+}
+
+void SERIAL0(void)
+{
+ static int badbaud = 0;
+ static bool newpkt = true;
+ char temp;
+
+ while(rx_rdy())
+ {
+ temp = rx_readc();
+ if (newpkt && autobaud > 0)
+ {
+ if (autobaud == 1)
+ {
+ switch (temp)
+ {
+ case 0xFF:
+ case 0x55:
+ break;
+ case 0xFC:
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 0x4E; /* 24000000/78/16 = 19230 baud */
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ temp = 0xFF;
+ break;
+ case 0xE0:
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 0x9C; /* 24000000/156/16 = 9615 baud */
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ temp = 0xFF;
+ break;
+ default:
+ badbaud++;
+ if (badbaud >= 6) /* Switch baud detection mode */
+ {
+ autobaud = 2;
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 0x0D; /* 24000000/13/16 = 115384 baud */
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ badbaud = 0;
+ } else {
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 0x1A; /* 24000000/26/16 = 57692 baud */
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ }
+ continue;
+ }
+ } else {
+ switch (temp)
+ {
+ case 0xFF:
+ case 0x55:
+ break;
+ case 0xFE:
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 0x1A; /* 24000000/26/16 = 57692 baud */
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ temp = 0xFF;
+ break;
+ case 0xFC:
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 0x27; /* 24000000/39/16 = 38461 baud */
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ temp = 0xFF;
+ break;
+ case 0xE0:
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 0x4E; /* 24000000/78/16 = 19230 baud */
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ temp = 0xFF;
+ break;
+ default:
+ badbaud++;
+ if (badbaud >= 6) /* Switch baud detection */
+ {
+ autobaud = 1;
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 0x1A; /* 24000000/26/16 = 57692 baud */
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ badbaud = 0;
+ } else {
+ SER0_LCR = 0x80; /* Divisor latch enable */
+ SER0_DLL = 0x0D; /* 24000000/13/16 = 115384 baud */
+ SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
+ }
+ continue;
+ }
+ }
+ }
+ bool pkt = iap_getc(temp);
+ if(newpkt == true && pkt == false)
+ autobaud = 0; /* Found good baud */
+ newpkt = pkt;
+ }
+}
+
+#else /* Other targets */
+void serial_setup (void)
+{
+ /* a dummy */
+}
+
+int tx_rdy(void)
+{
+ /* a dummy */
+ return 1;
+}
+
+int rx_rdy(void)
+{
+ /* a dummy */
+ return 0;
+}
+
+void tx_writec(unsigned char c)
+{
+ /* a dummy */
+}
+
+#endif
+
void dprintf(const char * str, ... )
{
char dprintfbuff[256];
- unsigned char * ptr;
+ char * ptr;
va_list ap;
va_start(ap, str);
@@ -224,7 +464,7 @@ void dprintf(const char * str, ... )
vsnprintf(ptr,sizeof(dprintfbuff),str,ap);
va_end(ap);
- serial_tx(ptr);
+ serial_tx((unsigned char *)ptr);
}
void serial_tx(const unsigned char * buf)
@@ -241,10 +481,3 @@ void serial_tx(const unsigned char * buf)
}
}
}
-
-#else /* Other targets */
-void serial_setup (void)
-{
- /* a dummy */
-}
-#endif
diff --git a/firmware/export/config-ipod4g.h b/firmware/export/config-ipod4g.h
index 89b14f9..f6c71f3 100644
--- a/firmware/export/config-ipod4g.h
+++ b/firmware/export/config-ipod4g.h
@@ -186,4 +186,6 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+#define IPOD_ACCESSORY_PROTOCOL
+
#endif
diff --git a/firmware/export/config-ipodcolor.h b/firmware/export/config-ipodcolor.h
index 47b7a4e..58a888a 100644
--- a/firmware/export/config-ipodcolor.h
+++ b/firmware/export/config-ipodcolor.h
@@ -166,4 +166,6 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+#define IPOD_ACCESSORY_PROTOCOL
+
#endif
diff --git a/firmware/export/config-ipodnano.h b/firmware/export/config-ipodnano.h
index 6017d0a..8752181 100644
--- a/firmware/export/config-ipodnano.h
+++ b/firmware/export/config-ipodnano.h
@@ -177,4 +177,6 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+#define IPOD_ACCESSORY_PROTOCOL
+
#endif
diff --git a/firmware/export/config-ipodvideo.h b/firmware/export/config-ipodvideo.h
index d04e562..ab974dc 100644
--- a/firmware/export/config-ipodvideo.h
+++ b/firmware/export/config-ipodvideo.h
@@ -197,4 +197,6 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+#define IPOD_ACCESSORY_PROTOCOL
+
#endif
diff --git a/firmware/export/iap.h b/firmware/export/iap.h
new file mode 100644
index 0000000..6c0b968
--- /dev/null
+++ b/firmware/export/iap.h
@@ -0,0 +1,31 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: iap.h 17400 2008-05-07 20:22:16Z xxxxxx $
+ *
+ * Copyright (C) 2002 by Alan Korr
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef __IAP_H__
+#define __IAP_H__
+
+extern int iap_getc(unsigned char x);
+extern void iap_write_pkt(unsigned char data, int len);
+extern void iap_setup(int ratenum);
+extern void iap_bitrate_set(int ratenum);
+extern void iap_periodic(void);
+extern void iap_handlepkt(void);
+extern void iap_track_changed(void);
+
+#endif
diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h
index ef65463..29cf8f2 100644
--- a/firmware/export/kernel.h
+++ b/firmware/export/kernel.h
@@ -78,6 +78,8 @@
#define SYS_REMOTE_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 5)
#define SYS_SCREENDUMP MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 0)
#define SYS_CAR_ADAPTER_RESUME MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 1)
+#define SYS_IAP_PERIODIC MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 2)
+#define SYS_IAP_HANDLEPKT MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 3)
#define IS_SYSEVENT(ev) ((ev & SYS_EVENT) == SYS_EVENT)
diff --git a/firmware/export/serial.h b/firmware/export/serial.h
index 425fc66..8a4780c 100644
--- a/firmware/export/serial.h
+++ b/firmware/export/serial.h
@@ -22,8 +22,11 @@
#ifndef __SERIAL_H__
#define __SERIAL_H__
-extern void serial_setup (void);
+extern void serial_setup(void);
+extern void serial_bitrate(int rate);
extern int remote_control_rx(void);
extern void serial_tx(const unsigned char *buf);
+extern void tx_writec(unsigned char c);
+extern int tx_rdy(void);
#endif
diff --git a/firmware/target/arm/ipod/button-clickwheel.c b/firmware/target/arm/ipod/button-clickwheel.c
index e36c928..21bbca6 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)
}
/* The int_btn variable is set in the button interrupt handler */
+#ifdef IPOD_ACCESSORY_PROTOCOL
+ return int_btn | remote_control_rx();
+#else
return int_btn;
+#endif
}
bool button_hold(void)
diff --git a/firmware/target/arm/ipod/button-target.h b/firmware/target/arm/ipod/button-target.h
index a0ac372..67bdc72 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);
|BUTTON_LEFT|BUTTON_RIGHT|BUTTON_SCROLL_FWD\
|BUTTON_SCROLL_BACK|BUTTON_PLAY)
+ /* Remote control's buttons */
+#ifdef IPOD_ACCESSORY_PROTOCOL
+#define BUTTON_RC_PLAY 0x00100000
+#define BUTTON_RC_STOP 0x00080000
+
+#define BUTTON_RC_LEFT 0x00040000
+#define BUTTON_RC_RIGHT 0x00020000
+#define BUTTON_RC_VOL_UP 0x00010000
+#define BUTTON_RC_VOL_DOWN 0x00008000
+
+#define BUTTON_REMOTE (BUTTON_RC_PLAY|BUTTON_RC_STOP\
+ |BUTTON_RC_LEFT|BUTTON_RC_RIGHT\
+ |BUTTON_RC_VOL_UP|BUTTON_RC_VOL_DOWN)
+#else
#define BUTTON_REMOTE 0
+#endif
/* This is for later
#define BUTTON_SCROLL_TOUCH 0x00000200
diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c
index d683b3a..b1f178c 100644
--- a/firmware/target/arm/system-pp502x.c
+++ b/firmware/target/arm/system-pp502x.c
@@ -32,6 +32,7 @@
#ifndef BOOTLOADER
extern void TIMER1(void);
extern void TIMER2(void);
+extern void SERIAL0(void);
extern void ipod_mini_button_int(void); /* iPod Mini 1st gen only */
extern void ipod_4g_button_int(void); /* iPod 4th gen and higher only */
@@ -78,6 +79,11 @@ void irq(void)
button_int();
}
#endif
+#ifdef IPOD_ACCESSORY_PROTOCOL
+ else if (CPU_HI_INT_STAT & SER0_MASK) {
+ SERIAL0();
+ }
+#endif
#ifdef HAVE_USBSTACK
else if (CPU_INT_STAT & USB_MASK) {
usb_drv_int();