diff --git a/repos/dde_linux/src/drivers/usb/main.cc b/repos/dde_linux/src/drivers/usb/main.cc
index 7cb48d0258..0a5d253032 100644
--- a/repos/dde_linux/src/drivers/usb/main.cc
+++ b/repos/dde_linux/src/drivers/usb/main.cc
@@ -12,14 +12,86 @@
*/
#include
+#include
extern void start_usb_driver(Genode::Env &env);
+namespace Usb_driver {
+
+ using namespace Genode;
+
+ struct Driver_starter { virtual void start_driver() = 0; };
+ struct Main;
+}
+
+
+struct Usb_driver::Main : Driver_starter
+{
+ Env &_env;
+
+ /*
+ * Defer the startup of the USB driver until the first configuration
+ * becomes available. This is needed in scenarios where the configuration
+ * is dynamically generated and supplied to the USB driver via the
+ * report-ROM service.
+ */
+ struct Initial_config_handler
+ {
+ Driver_starter &_driver_starter;
+
+ Attached_rom_dataspace _config;
+
+ Signal_handler _config_handler;
+
+ void _handle_config()
+ {
+ _config.update();
+
+ if (_config.xml().type() == "config")
+ _driver_starter.start_driver();
+ }
+
+ Initial_config_handler(Env &env, Driver_starter &driver_starter)
+ :
+ _driver_starter(driver_starter),
+ _config(env, "config"),
+ _config_handler(env.ep(), *this, &Initial_config_handler::_handle_config)
+ {
+ _config.sigh(_config_handler);
+ _handle_config();
+ }
+ };
+
+ void _handle_start()
+ {
+ if (_initial_config_handler.constructed()) {
+ _initial_config_handler.destruct();
+ start_usb_driver(_env);
+ }
+ }
+
+ Signal_handler _start_handler {
+ _env.ep(), *this, &Main::_handle_start };
+
+ Reconstructible _initial_config_handler { _env, *this };
+
+ /*
+ * Called from 'Initial_config_handler'
+ */
+ void start_driver() override
+ {
+ Signal_transmitter(_start_handler).submit();
+ }
+
+ Main(Env &env) : _env(env) { }
+};
+
+
void Component::construct(Genode::Env &env)
{
/* XXX execute constructors of global statics */
env.exec_static_constructors();
- start_usb_driver(env);
+ static Usb_driver::Main main(env);
}