Index: apps/keymaps/keymap-ipod.c =================================================================== --- apps/keymaps/keymap-ipod.c (revision 16357) +++ apps/keymaps/keymap-ipod.c (working copy) @@ -171,9 +171,56 @@ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS) }; /* button_context_recscreen */ +#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_PLAY, BUTTON_RC_PLAY, BUTTON_NONE }, + { ACTION_WPS_SKIPNEXT, BUTTON_RC_RIGHT, BUTTON_NONE }, + { ACTION_WPS_SKIPPREV, BUTTON_RC_LEFT, BUTTON_NONE }, + { ACTION_WPS_STOP, BUTTON_RC_STOP, BUTTON_NONE }, + + { ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN, BUTTON_NONE }, + { ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP, BUTTON_NONE }, + + 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: Index: firmware/export/config-ipodvideo.h =================================================================== --- firmware/export/config-ipodvideo.h (revision 16357) +++ firmware/export/config-ipodvideo.h (working copy) @@ -178,4 +178,6 @@ #define ICODE_ATTR_TREMOR_NOT_MDCT +#define IPOD_ACCESSORY_PROTOCOL + #endif Index: firmware/target/arm/ipod/button-target.h =================================================================== --- firmware/target/arm/ipod/button-target.h (revision 16357) +++ firmware/target/arm/ipod/button-target.h (working copy) @@ -48,7 +48,22 @@ |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_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 Index: firmware/target/arm/ipod/button-clickwheel.c =================================================================== --- firmware/target/arm/ipod/button-clickwheel.c (revision 16357) +++ firmware/target/arm/ipod/button-clickwheel.c (working copy) @@ -314,7 +314,11 @@ } /* 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) Index: firmware/target/arm/system-pp502x.c =================================================================== --- firmware/target/arm/system-pp502x.c (revision 16357) +++ firmware/target/arm/system-pp502x.c (working copy) @@ -28,6 +28,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 */ extern void microsd_int(void); /* Sansa E200 and C200 */ @@ -67,6 +68,11 @@ microsd_int(); } #endif +#if defined(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(); Index: firmware/drivers/serial.c =================================================================== --- firmware/drivers/serial.c (revision 16357) +++ firmware/drivers/serial.c (working copy) @@ -240,6 +240,121 @@ } } +#elif defined(IPOD_ACCESSORY_PROTOCOL) +void serial_setup (void) +{ + int tmp; + +#if 0 + SER1_LCR = 0x80; /* Divisor latch enable */ + SER1_DLL = 0x4c; /* 24000000/76/16 = 19736 baud */ + SER1_DLM = 0x00; + SER1_LCR = 0x03; /* Latch disable, 8 bits */ + SER1_FCR = 0x07; /* Tx+Rx FIFO reset and FIFO enable */ + + outl(0x70000014, (inl(0x70000014) & ~0xf00) | 0xa00); + GPIOD_ENABLE &= ~6; + + DEV_EN = DEV_EN | DEV_SER1; + tmp = SER1_RBR; + DEV_RS |= DEV_SER1; + sleep(1); + DEV_RS &= ~DEV_SER1; +#endif + + /* Route the Tx/Rx pins. This probably applies to PP502x only */ + outl(0x70000018, inl(0x70000018) & ~0xc00); + + DEV_EN = DEV_EN | DEV_SER0; + tmp = SER0_RBR; + DEV_RS |= DEV_SER0; + sleep(1); + DEV_RS &= ~DEV_SER0; + + SER0_LCR = 0x80; /* Divisor latch enable */ + SER0_DLL = 0x4c; /* 24000000/76/16 = 19736 baud */ + SER0_DLM = 0x00; + SER0_LCR = 0x03; /* Latch disable, 8 bits */ + SER0_FCR = 0x07; /* Tx+Rx FIFO reset and FIFO enable */ + + SER0_IER = 0x01; + + CPU_INT_EN |= HI_MASK; + CPU_HI_INT_EN |= SER0_MASK; +} + +#define AP_BUFLEN 128 +static unsigned char serbuf[AP_BUFLEN]; +static int serbuf_i = 0; +static unsigned long remote_btn; + +/* Message format: + 0xff + 0x55 + length + mode + command (2 bytes) + parameters (0-n bytes) + checksum (length+mode+parameters+checksum == 0) +*/ +void SERIAL0(void) +{ + unsigned char x; + static unsigned char last_x = 0; + static unsigned char sum = 0; + + while(SER0_LSR & 1) { + x = SER0_RBR; + + /* Restart if the sync word is seen */ + if(x == 0x55 && last_x == 0xff) { + serbuf_i = 0; + sum = 0; + } else { + if(serbuf_i >= AP_BUFLEN) + serbuf_i = 0; + + serbuf[serbuf_i++] = x; + sum += x; + } + last_x = x; + } + + /* Proceed if we have a complete message */ + if(serbuf_i == serbuf[0]+2 && sum == 0) { + /* Handle Mode 2 */ + if(serbuf[1] == 2) { + remote_btn = serbuf[3]; + } + } +} + +int remote_control_rx(void) +{ + int btn; + + switch(remote_btn) { + case 1: + btn = BUTTON_RC_PLAY; + break; + case 2: + btn = BUTTON_RC_VOL_UP; + break; + case 4: + btn = BUTTON_RC_VOL_DOWN; + break; + case 8: + btn = BUTTON_RC_RIGHT; + break; + case 16: + btn = BUTTON_RC_LEFT; + break; + default: + btn = 0; + } + return btn; +} + #else /* Other targets */ void serial_setup (void) {