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); }