1
0
Fork 0
forked from len0rd/rockbox

iPod Classic: implement IPOD_ACCESSORY_PROTOCOL

Change-Id: I0f0950c42ae5bf5c5b4c2c2f097f8c68a92ba4dd
This commit is contained in:
Cástor Muñoz 2014-12-06 23:13:44 +01:00
parent 38ae0d53e8
commit efd047a08b
3 changed files with 116 additions and 4 deletions

View file

@ -247,10 +247,14 @@
#define USB_NUM_ENDPOINTS 6
#define USB_DEVBSS_ATTR __attribute__((aligned(16)))
#define HAVE_SERIAL
/* Disable iAP when LOGF_SERIAL is enabled to avoid conflicts */
#ifndef LOGF_SERIAL
#define IPOD_ACCESSORY_PROTOCOL
#endif
/* Define this if you can switch on/off the accessory power supply */
#define HAVE_ACCESSORY_SUPPLY
//#define IPOD_ACCESSORY_PROTOCOL
#define HAVE_SERIAL
/* Define this, if you can switch on/off the lineout */
#define HAVE_LINEOUT_POWEROFF

View file

@ -69,12 +69,12 @@ void accessory_supply_set(bool enable)
if (enable)
{
/* Accessory voltage supply on */
//TODO: pmu_ldo_power_on(6);
pmu_ldo_power_on(6);
}
else
{
/* Accessory voltage supply off */
//TODO: pmu_ldo_power_off(6);
pmu_ldo_power_off(6);
}
}
#endif

View file

@ -41,6 +41,9 @@
#define IPOD6G_UART_CLK_HZ 12000000 /* external OSC0 ??? */
extern struct uartc s5l8702_uart;
#ifdef IPOD_ACCESSORY_PROTOCOL
void iap_rx_isr(int, char*, char*, uint32_t);
#endif
struct uartc_port ser_port IDATA_ATTR = {
/* location */
@ -54,7 +57,11 @@ struct uartc_port ser_port IDATA_ATTR = {
.clkhz = IPOD6G_UART_CLK_HZ,
/* interrupt callbacks */
#ifdef IPOD_ACCESSORY_PROTOCOL
.rx_cb = iap_rx_isr,
#else
.rx_cb = NULL,
#endif
.tx_cb = NULL, /* polling */
};
@ -85,3 +92,104 @@ void tx_writec(unsigned char c)
{
uartc_port_tx_byte(&ser_port, c);
}
#ifdef IPOD_ACCESSORY_PROTOCOL
#include "iap.h"
enum {
ABR_STATUS_LAUNCHED, /* ST_SYNC */
ABR_STATUS_SYNCING, /* ST_SOF */
ABR_STATUS_DONE
};
int abr_status;
void serial_bitrate(int rate)
{
logf("[%lu] serial_bitrate(%d)", USEC_TIMER, rate);
if (rate == 0) {
/* Using auto-bitrate (ABR) to detect accessory Tx speed:
*
* + Here:
* - Disable Rx logic to clean the FIFO and the shift
* register, thus no Rx data interrupts are generated.
* - Launch ABR and wait for a low pulse in Rx line.
*
* + In ISR, when a low pulse is detected (ideally it is the
* start bit of 0xff):
* - Calculate and configure detected speed.
* - Enable Rx to verify that the next received data frame
* is 0x55 or 0xff:
* - If so, it's assumed bit rate is correctly detected,
* it will not be modified until speed is changed using
* RB options menu.
* - If not, reset iAP state machine and launch a new ABR.
*/
uartc_port_set_rx_mode(&ser_port, UCON_MODE_DISABLED);
uartc_port_abr_start(&ser_port);
abr_status = ABR_STATUS_LAUNCHED;
}
else {
uartc_port_abr_stop(&ser_port); /* abort ABR if already launched */
uartc_port_set_bitrate(&ser_port, rate);
uartc_port_set_rx_mode(&ser_port, UCON_MODE_INTREQ);
abr_status = ABR_STATUS_DONE;
}
}
void iap_rx_isr(int len, char *data, char *err, uint32_t abr_cnt)
{
/* ignore Rx errors, upper layer will discard bad packets */
(void) err;
static int sync_retry;
if (abr_status == ABR_STATUS_LAUNCHED) {
/* autobauding */
if (abr_cnt) {
#define BR2CNT(s) (IPOD6G_UART_CLK_HZ / (unsigned)(s))
unsigned speed;
if (abr_cnt < BR2CNT(57600*1.1) || abr_cnt > BR2CNT(9600*0.9)) {
/* detected speed out of range, relaunch ABR */
uartc_port_abr_start(&ser_port);
return;
}
/* valid speed detected, select it */
else if (abr_cnt < BR2CNT(48000)) speed = 57600;
else if (abr_cnt < BR2CNT(33600)) speed = 38400;
else if (abr_cnt < BR2CNT(24000)) speed = 28800;
else if (abr_cnt < BR2CNT(14400)) speed = 19200;
else speed = 9600;
/* set detected speed */
uartc_port_set_bitrate(&ser_port, speed);
uartc_port_set_rx_mode(&ser_port, UCON_MODE_INTREQ);
/* enter SOF state */
iap_getc(0xff);
abr_status = ABR_STATUS_SYNCING;
sync_retry = 2; /* we are expecting [0xff] 0x55 */
}
}
/* process received data */
while (len--) {
bool sync_done = !iap_getc(*data++);
if (abr_status == ABR_STATUS_SYNCING) {
if (sync_done) {
abr_status = ABR_STATUS_DONE;
}
else if (--sync_retry == 0) {
/* invalid speed detected, relaunch ABR
discarding remaining data (if any) */
serial_bitrate(0);
break;
}
}
}
}
#endif /* IPOD_ACCESSORY_PROTOCOL */