1
0
Fork 0
forked from len0rd/rockbox

IAP: Reset IAP state upon headphone or dock unplug

Provides a semi-automatic way of recovering from desynchronization

Change-Id: I527b0bacc22ef38c1e7213653e522ea1b0ac155d
This commit is contained in:
Solomon Peachy 2025-08-06 14:26:34 -04:00
parent 80eca90481
commit 472a6a69c6
5 changed files with 93 additions and 15 deletions

View file

@ -118,10 +118,6 @@
#include "usb_core.h" #include "usb_core.h"
#endif #endif
#if defined(IPOD_ACCESSORY_PROTOCOL)
#include "iap.h"
#endif
#include "talk.h" #include "talk.h"
#if defined(HAVE_DEVICEDATA)// && !defined(SIMULATOR) #if defined(HAVE_DEVICEDATA)// && !defined(SIMULATOR)
@ -140,6 +136,10 @@
#include "norboot-target.h" #include "norboot-target.h"
#endif #endif
#if defined(IPOD_ACCESSORY_PROTOCOL)
#include "iap.h"
#endif
#define SCREEN_MAX_CHARS (LCD_WIDTH / SYSFONT_WIDTH) #define SCREEN_MAX_CHARS (LCD_WIDTH / SYSFONT_WIDTH)
static const char* threads_getname(int selected_item, void *data, static const char* threads_getname(int selected_item, void *data,
@ -2852,6 +2852,9 @@ static const struct {
#if (defined(HAVE_WHEEL_ACCELERATION) && (CONFIG_KEYPAD==IPOD_4G_PAD) \ #if (defined(HAVE_WHEEL_ACCELERATION) && (CONFIG_KEYPAD==IPOD_4G_PAD) \
&& !defined(IPOD_MINI) && !defined(SIMULATOR)) && !defined(IPOD_MINI) && !defined(SIMULATOR))
{"Debug scrollwheel", dbg_scrollwheel }, {"Debug scrollwheel", dbg_scrollwheel },
#endif
#if defined(IPOD_ACCESSORY_PROTOCOL)
{"Debug IAP", dbg_iap },
#endif #endif
{"Talk engine stats", dbg_talk }, {"Talk engine stats", dbg_talk },
#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR) #if defined(HAVE_BOOTDATA) && !defined(SIMULATOR)

View file

@ -177,7 +177,7 @@ unsigned char lingo_versions[32][2] = {
/* states of the iap de-framing state machine */ /* states of the iap de-framing state machine */
enum fsm_state { enum fsm_state {
ST_SYNC, /* wait for 0xFF sync byte */ ST_SYNC = 0, /* wait for 0xFF sync byte */
ST_SOF, /* wait for 0x55 start-of-frame byte */ ST_SOF, /* wait for 0x55 start-of-frame byte */
ST_LEN, /* receive length byte (small packet) */ ST_LEN, /* receive length byte (small packet) */
ST_LENH, /* receive length high byte (large packet) */ ST_LENH, /* receive length high byte (large packet) */
@ -210,6 +210,17 @@ static struct buflib_callbacks iap_buflib_callbacks = {
static void iap_malloc(void); static void iap_malloc(void);
static void iap_reset_buffers(void)
{
iap_txstart = iap_buffers;
iap_txpayload = iap_txstart+5;
iap_txnext = iap_txpayload;
iap_rxstart = iap_buffers+(TX_BUFLEN+6);
iap_rxpayload = iap_rxstart;
iap_rxnext = iap_rxpayload;
iap_rxlen = RX_BUFLEN+2;
}
void put_u16(unsigned char *buf, const uint16_t data) void put_u16(unsigned char *buf, const uint16_t data)
{ {
buf[0] = (data >> 8) & 0xFF; buf[0] = (data >> 8) & 0xFF;
@ -295,6 +306,27 @@ void iap_reset_auth(struct auth_t* auth)
auth->next_section = 0; auth->next_section = 0;
} }
void iap_reset_state(int port)
{
if (!iap_running)
return;
/* 0 is dock, 1 is headphone. This is for
when we eventually maintain independent state */
(void)port;
iap_reset_device(&device);
iap_bitrate_set(global_settings.serial_bitrate);
#if 0 // XXX this is still screwed up
memset(&frame_state, 0, sizeof(frame_state));
interface_state = IST_STANDARD;
frame_state.state = ST_SYNC;
iap_reset_buffers();
#endif
}
void iap_reset_device(struct device_t* device) void iap_reset_device(struct device_t* device)
{ {
iap_reset_auth(&(device->auth)); iap_reset_auth(&(device->auth));
@ -326,7 +358,6 @@ void iap_set_remote_volume(void)
iap_send_tx(); iap_send_tx();
} }
/* This thread is waiting for events posted to iap_queue and calls /* This thread is waiting for events posted to iap_queue and calls
* the appropriate subroutines in response * the appropriate subroutines in response
*/ */
@ -460,13 +491,8 @@ static void iap_malloc(void)
#else #else
iap_buffers = serbuf; iap_buffers = serbuf;
#endif #endif
iap_txstart = iap_buffers;
iap_txpayload = iap_txstart+5; iap_reset_buffers();
iap_txnext = iap_txpayload;
iap_rxstart = iap_buffers+(TX_BUFLEN+6);
iap_rxpayload = iap_rxstart;
iap_rxnext = iap_rxpayload;
iap_rxlen = RX_BUFLEN+2;
iap_running = true; iap_running = true;
} }
@ -1418,3 +1444,32 @@ void iap_fill_power_state(void)
IAP_TX_PUT(0x00); IAP_TX_PUT(0x00);
} }
} }
#include "lcd.h"
#include "font.h"
bool dbg_iap(void)
{
lcd_setfont(FONT_SYSFIXED);
while (1)
{
if (action_userabort(HZ/10))
break;
lcd_clear_display();
/* show internal state of IAP subsystem */
lcd_putsf(0, 0, "auth: %d acc: %d", device.auth.state, device.accinfo);
lcd_putsf(0, 1, "lin: %08x", device.lingoes);
lcd_putsf(0, 2, "notif: %08x", device.notifications);
lcd_putsf(0, 3, "cap: %08x/%08x", device.capabilities, device.capabilities_queried);
// frame_state.state
// serial state
lcd_update();
}
lcd_setfont(FONT_UI);
return false;
}

View file

@ -45,6 +45,10 @@
#include "lcd.h" /* lcd_active() prototype */ #include "lcd.h" /* lcd_active() prototype */
#endif #endif
#if defined(IPOD_ACCESSORY_PROTOCOL) && (defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IPOD_MINI2G))
#include "iap.h"
#endif
static long lastbtn; /* Last valid button status */ static long lastbtn; /* Last valid button status */
static long last_read; /* Last button status, for debouncing/filtering */ static long last_read; /* Last button status, for debouncing/filtering */
static bool flipped; /* buttons can be flipped to match the LCD flip */ static bool flipped; /* buttons can be flipped to match the LCD flip */
@ -102,6 +106,12 @@ static int hp_detect_callback(struct timeout *tmo)
/* Try to post only transistions */ /* Try to post only transistions */
const long id = tmo->data ? SYS_PHONE_PLUGGED : SYS_PHONE_UNPLUGGED; const long id = tmo->data ? SYS_PHONE_PLUGGED : SYS_PHONE_UNPLUGGED;
button_queue_post_remove_head(id, 0); button_queue_post_remove_head(id, 0);
#if defined(IPOD_ACCESSORY_PROTOCOL) && (defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IPOD_MINI2G))
if (id == SYS_PHONE_UNPLUGGED)
iap_reset_state(1);
#endif
return 0; return 0;
/*misc.c:hp_unplug_change*/ /*misc.c:hp_unplug_change*/
} }
@ -113,6 +123,7 @@ static int lo_detect_callback(struct timeout *tmo)
/* Try to post only transistions */ /* Try to post only transistions */
const long id = tmo->data ? SYS_LINEOUT_PLUGGED : SYS_LINEOUT_UNPLUGGED; const long id = tmo->data ? SYS_LINEOUT_PLUGGED : SYS_LINEOUT_UNPLUGGED;
button_queue_post_remove_head(id, 0); button_queue_post_remove_head(id, 0);
return 0; return 0;
/*misc.c:lo_unplug_change*/ /*misc.c:lo_unplug_change*/
} }

View file

@ -37,5 +37,6 @@ const unsigned char *iap_get_serbuf(void);
#ifdef HAVE_LINE_REC #ifdef HAVE_LINE_REC
extern bool iap_record(bool onoff); extern bool iap_record(bool onoff);
#endif #endif
void iap_reset_state(int port); /* 0 is dock, 1 is headphone */
bool dbg_iap(void);
#endif #endif

View file

@ -51,6 +51,10 @@
#include "gui/skin_engine/skin_engine.h" #include "gui/skin_engine/skin_engine.h"
#endif #endif
#if defined(IPOD_ACCESSORY_PROTOCOL)
#include "iap.h"
#endif
/* Conditions under which we want the entire driver */ /* Conditions under which we want the entire driver */
#if !defined(BOOTLOADER) || \ #if !defined(BOOTLOADER) || \
(defined(HAVE_USBSTACK) && defined(HAVE_BOOTLOADER_USB_MODE)) || \ (defined(HAVE_USBSTACK) && defined(HAVE_BOOTLOADER_USB_MODE)) || \
@ -521,6 +525,10 @@ static void NORETURN_ATTR usb_thread(void)
if(usb_state == USB_POWERED || usb_state == USB_INSERTED) if(usb_state == USB_POWERED || usb_state == USB_INSERTED)
usb_stack_enable(false); usb_stack_enable(false);
#ifdef IPOD_ACCESSORY_PROTOCOL
iap_reset_state(0);
#endif
/* Only disable the USB slave mode if we really have enabled /* Only disable the USB slave mode if we really have enabled
it. Some expected acks may not have been received. */ it. Some expected acks may not have been received. */
if(usb_state == USB_INSERTED) if(usb_state == USB_INSERTED)