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
* the audio sample rate to default.
*/
static void usb_audio_init_connection(void)
static int usb_audio_init_connection(void)
{
logf("usbaudio: init connection");
// make sure we can get the buffers first...
// TODO: disable this driver when failed
if (usb_audio_request_buf())
return;
return -1;
usbaudio_active = true;
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);
tmp_saved_vol = sound_current(SOUND_VOLUME);
usb_audio_playing = false;
return 0;
}
/*

View file

@ -38,7 +38,14 @@ struct usb_class_driver_ep_allocation {
struct usb_class_driver {
/* 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 error;
int first_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
ready to use.
Returns 0 on success and -1 on error.
Optional function */
void (*init_connection)(void);
int (*init_connection)(void);
/* Initialises the driver. This can be called multiple times,
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;
#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)
/** NOTE Serial Number
@ -399,6 +399,7 @@ void usb_core_init(void)
* yet which drivers will be enabled */
for(i = 0; i < USB_NUM_DRIVERS; i++) {
drivers[i]->enabled = false;
drivers[i]->error = false;
drivers[i]->first_interface = 0;
drivers[i]->last_interface = 0;
if(drivers[i]->init != NULL) {
@ -472,7 +473,7 @@ void usb_core_hotswap_event(int volume, bool inserted)
{
int 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);
}
#endif
@ -856,10 +857,14 @@ static int usb_core_do_set_config(uint8_t new_config)
if(usb_config != 0) {
init_deinit_endpoints(usb_config - 1, true);
for(int i = 0; i < USB_NUM_DRIVERS; i++) {
if(is_active(drivers[i]) && drivers[i]->init_connection != NULL) {
drivers[i]->init_connection();
require_exclusive |= drivers[i]->needs_exclusive_storage;
if(!is_active(drivers[i])) {
continue;
}
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);
}
static void usb_hid_init_connection(void)
static int usb_hid_init_connection(void)
{
logf("hid: init connection");
active = true;
currently_sending = false;
return 0;
}
/* 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;
}
static void usb_iap_init_connection(void) {
static int usb_iap_init_connection(void) {
stream.sample_rate = 48000;
last_charge_state = -1;
last_minute = -1;
@ -381,10 +381,8 @@ static void usb_iap_init_connection(void) {
iap_debug_reset_timestamp();
/* TODO: disable iap on error */
/* init audio sink */
check_act(iap_audio_init(), return);
check_act(iap_audio_init(), return -1);
/* init libiap */
if(!iap_ctx_mutex_initialized) {
@ -416,11 +414,12 @@ static void usb_iap_init_connection(void) {
iap_initialized = true;
LOG("initialized");
return;
return 0;
cleanup_audio:
_iap_release_ctx();
iap_audio_deinit();
return -1;
}
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;
}
static void usb_serial_init_connection(void)
static int usb_serial_init_connection(void)
{
/* prime rx endpoint */
usb_drv_recv_nonblocking(EP_OUT, receive_buffer, RECV_BUFFER_SIZE);
@ -341,6 +341,7 @@ static void usb_serial_init_connection(void)
sendout();
}
active=true;
return 0;
}
/* 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
static int usb_handle = 0;
#endif
static void usb_storage_init_connection(void)
static int usb_storage_init_connection(void)
{
logf("ums: set config");
/* 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));
queue_broadcast(SYS_USB_LUN_LOCKED, (i<<16)+0);
}
return 0;
}
void usb_storage_disconnect(void)