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

rockbox-gerrit-noreply--- via rockbox-cvs <[email protected]> Mon, 4 May 2026 07:15:30 -0400
Newsgroups gmane.comp.systems.archos.rockbox.cvs
Message-ID <[email protected]>
commit 732f7bcfd96f64f481f3a94a62a7c50087836e31
Author: mojyack <[email protected]>
Date:   Fri Dec 19 21:29:21 2025 +0900

    usb: allow class drivers to return error from init_connection()
    
    Change-Id: Idcd48dd00d9d2f06c49a347e02a41a5de7252431

diff --git a/firmware/usbstack/usb_audio.c b/firmware/usbstack/usb_audio.c
index 9dc96579e7..fad3d12b8c 100644
--- a/firmware/usbstack/usb_audio.c
+++ b/firmware/usbstack/usb_audio.c
@@ -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;
 }
 
 /*
diff --git a/firmware/usbstack/usb_class_driver.h b/firmware/usbstack/usb_class_driver.h
index dc19c31ad5..5d63ce0b89 100644
--- a/firmware/usbstack/usb_class_driver.h
+++ b/firmware/usbstack/usb_class_driver.h
@@ -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
diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c
index 3f1dee129c..814d502242 100644
--- a/firmware/usbstack/usb_core.c
+++ b/firmware/usbstack/usb_core.c
@@ -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;
         }
     }
 
diff --git a/firmware/usbstack/usb_hid.c b/firmware/usbstack/usb_hid.c
index 3b231cfa8c..ac06691df4 100644
--- a/firmware/usbstack/usb_hid.c
+++ b/firmware/usbstack/usb_hid.c
@@ -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() */
diff --git a/firmware/usbstack/usb_iap.c b/firmware/usbstack/usb_iap.c
index 99492f791b..2d6d3d3022 100644
--- a/firmware/usbstack/usb_iap.c
+++ b/firmware/usbstack/usb_iap.c
@@ -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) {
diff --git a/firmware/usbstack/usb_serial.c b/firmware/usbstack/usb_serial.c
index 80aaaaef5d..5490d1db11 100644
--- a/firmware/usbstack/usb_serial.c
+++ b/firmware/usbstack/usb_serial.c
@@ -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() */
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c
index 17677c44cd..c4bdbf9841 100644
--- a/firmware/usbstack/usb_storage.c
+++ b/firmware/usbstack/usb_storage.c
@@ -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)
-- 
rockbox-cvs mailing list
[email protected]
https://lists.haxx.se/mailman/listinfo/rockbox-cvs