usb: allow class drivers to return error from init_connection()

Change-Id: Idcd48dd00d9d2f06c49a347e02a41a5de7252431
This commit is contained in:
mojyack 2025-12-19 21:29:21 +09:00
parent 3c10b21c10
commit 732f7bcfd9
7 changed files with 32 additions and 17 deletions

View file

@ -1204,14 +1204,13 @@ static bool usb_audio_control_request(struct usb_ctrlrequest* req, void *reqdata
* connection is ready to be used. Currently just sets * connection is ready to be used. Currently just sets
* the audio sample rate to default. * the audio sample rate to default.
*/ */
static void usb_audio_init_connection(void) static int usb_audio_init_connection(void)
{ {
logf("usbaudio: init connection"); logf("usbaudio: init connection");
// make sure we can get the buffers first... // make sure we can get the buffers first...
// TODO: disable this driver when failed
if (usb_audio_request_buf()) if (usb_audio_request_buf())
return; return -1;
usbaudio_active = true; usbaudio_active = true;
dsp = dsp_get_config(CODEC_IDX_AUDIO); dsp = dsp_get_config(CODEC_IDX_AUDIO);
@ -1227,6 +1226,7 @@ static void usb_audio_init_connection(void)
set_playback_sampling_frequency(HW_SAMPR_DEFAULT); set_playback_sampling_frequency(HW_SAMPR_DEFAULT);
tmp_saved_vol = sound_current(SOUND_VOLUME); tmp_saved_vol = sound_current(SOUND_VOLUME);
usb_audio_playing = false; usb_audio_playing = false;
return 0;
} }
/* /*

View file

@ -38,7 +38,14 @@ struct usb_class_driver_ep_allocation {
struct usb_class_driver { struct usb_class_driver {
/* First some runtime data */ /* First some runtime data */
/* there are three possible runtime states for class driver:
* !enabled -> disabled, invisible from host
* enabled && !error -> enabled, healthy
* enabled && error -> recognized by host, but failed */
bool enabled; bool enabled;
bool error;
int first_interface; int first_interface;
int last_interface; int last_interface;
@ -69,8 +76,9 @@ struct usb_class_driver {
/* Tells the driver that a usb connection has been set up and is now /* Tells the driver that a usb connection has been set up and is now
ready to use. ready to use.
Returns 0 on success and -1 on error.
Optional function */ Optional function */
void (*init_connection)(void); int (*init_connection)(void);
/* Initialises the driver. This can be called multiple times, /* Initialises the driver. This can be called multiple times,
and should not perform any action that can disturb other threads and should not perform any action that can disturb other threads

View file

@ -236,7 +236,7 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req, void*
static unsigned char response_data[256] USB_DEVBSS_ATTR; static unsigned char response_data[256] USB_DEVBSS_ATTR;
#define is_active(driver) ((driver)->enabled && (driver)->config == usb_config) #define is_active(driver) ((driver)->enabled && !(driver)->error && (driver)->config == usb_config)
#define has_if(driver, interface) ((interface) >= (driver)->first_interface && (interface) < (driver)->last_interface) #define has_if(driver, interface) ((interface) >= (driver)->first_interface && (interface) < (driver)->last_interface)
/** NOTE Serial Number /** NOTE Serial Number
@ -399,6 +399,7 @@ void usb_core_init(void)
* yet which drivers will be enabled */ * yet which drivers will be enabled */
for(i = 0; i < USB_NUM_DRIVERS; i++) { for(i = 0; i < USB_NUM_DRIVERS; i++) {
drivers[i]->enabled = false; drivers[i]->enabled = false;
drivers[i]->error = false;
drivers[i]->first_interface = 0; drivers[i]->first_interface = 0;
drivers[i]->last_interface = 0; drivers[i]->last_interface = 0;
if(drivers[i]->init != NULL) { if(drivers[i]->init != NULL) {
@ -472,7 +473,7 @@ void usb_core_hotswap_event(int volume, bool inserted)
{ {
int i; int i;
for(i = 0; i < USB_NUM_DRIVERS; i++) for(i = 0; i < USB_NUM_DRIVERS; i++)
if(drivers[i]->enabled && drivers[i]->notify_hotswap != NULL) if(is_active(drivers[i]) && drivers[i]->notify_hotswap != NULL)
drivers[i]->notify_hotswap(volume, inserted); drivers[i]->notify_hotswap(volume, inserted);
} }
#endif #endif
@ -856,10 +857,14 @@ static int usb_core_do_set_config(uint8_t new_config)
if(usb_config != 0) { if(usb_config != 0) {
init_deinit_endpoints(usb_config - 1, true); init_deinit_endpoints(usb_config - 1, true);
for(int i = 0; i < USB_NUM_DRIVERS; i++) { for(int i = 0; i < USB_NUM_DRIVERS; i++) {
if(is_active(drivers[i]) && drivers[i]->init_connection != NULL) { if(!is_active(drivers[i])) {
drivers[i]->init_connection(); continue;
require_exclusive |= drivers[i]->needs_exclusive_storage;
} }
if(drivers[i]->init_connection != NULL && drivers[i]->init_connection() < 0) {
drivers[i]->error = true;
continue;
}
require_exclusive |= drivers[i]->needs_exclusive_storage;
} }
} }

View file

@ -543,11 +543,12 @@ static int usb_hid_get_config_descriptor(unsigned char *dest, int max_packet_siz
return (int)(dest - orig_dest); return (int)(dest - orig_dest);
} }
static void usb_hid_init_connection(void) static int usb_hid_init_connection(void)
{ {
logf("hid: init connection"); logf("hid: init connection");
active = true; active = true;
currently_sending = false; currently_sending = false;
return 0;
} }
/* called by usb_core_init() */ /* called by usb_core_init() */

View file

@ -373,7 +373,7 @@ static int usb_iap_get_config_descriptor(unsigned char* dest, int max_packet_siz
return dest - orig_dest; return dest - orig_dest;
} }
static void usb_iap_init_connection(void) { static int usb_iap_init_connection(void) {
stream.sample_rate = 48000; stream.sample_rate = 48000;
last_charge_state = -1; last_charge_state = -1;
last_minute = -1; last_minute = -1;
@ -381,10 +381,8 @@ static void usb_iap_init_connection(void) {
iap_debug_reset_timestamp(); iap_debug_reset_timestamp();
/* TODO: disable iap on error */
/* init audio sink */ /* init audio sink */
check_act(iap_audio_init(), return); check_act(iap_audio_init(), return -1);
/* init libiap */ /* init libiap */
if(!iap_ctx_mutex_initialized) { if(!iap_ctx_mutex_initialized) {
@ -416,11 +414,12 @@ static void usb_iap_init_connection(void) {
iap_initialized = true; iap_initialized = true;
LOG("initialized"); LOG("initialized");
return; return 0;
cleanup_audio: cleanup_audio:
_iap_release_ctx(); _iap_release_ctx();
iap_audio_deinit(); iap_audio_deinit();
return -1;
} }
static int usb_iap_set_interface(int intf, int alt) { static int usb_iap_set_interface(int intf, int alt) {

View file

@ -329,7 +329,7 @@ static bool usb_serial_control_request(struct usb_ctrlrequest* req, void* reqdat
return handled; return handled;
} }
static void usb_serial_init_connection(void) static int usb_serial_init_connection(void)
{ {
/* prime rx endpoint */ /* prime rx endpoint */
usb_drv_recv_nonblocking(EP_OUT, receive_buffer, RECV_BUFFER_SIZE); usb_drv_recv_nonblocking(EP_OUT, receive_buffer, RECV_BUFFER_SIZE);
@ -341,6 +341,7 @@ static void usb_serial_init_connection(void)
sendout(); sendout();
} }
active=true; active=true;
return 0;
} }
/* called by usb_code_init() */ /* called by usb_code_init() */

View file

@ -436,7 +436,7 @@ static int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_
#else #else
static int usb_handle = 0; static int usb_handle = 0;
#endif #endif
static void usb_storage_init_connection(void) static int usb_storage_init_connection(void)
{ {
logf("ums: set config"); logf("ums: set config");
/* prime rx endpoint. We only need room for commands */ /* prime rx endpoint. We only need room for commands */
@ -483,6 +483,7 @@ static void usb_storage_init_connection(void)
ejected[i] = !check_disk_present(IF_MD(i)); ejected[i] = !check_disk_present(IF_MD(i));
queue_broadcast(SYS_USB_LUN_LOCKED, (i<<16)+0); queue_broadcast(SYS_USB_LUN_LOCKED, (i<<16)+0);
} }
return 0;
} }
void usb_storage_disconnect(void) void usb_storage_disconnect(void)