forked from len0rd/rockbox
iPod Classic: implement IPOD_ACCESSORY_PROTOCOL
Change-Id: I0f0950c42ae5bf5c5b4c2c2f097f8c68a92ba4dd
This commit is contained in:
parent
38ae0d53e8
commit
efd047a08b
3 changed files with 116 additions and 4 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue