diff --git a/repos/os/include/genode_c_api/usb.h b/repos/os/include/genode_c_api/usb.h index 918d827b4d..cd316acf09 100644 --- a/repos/os/include/genode_c_api/usb.h +++ b/repos/os/include/genode_c_api/usb.h @@ -222,6 +222,8 @@ void genode_usb_ack_request(genode_usb_session_handle_t session_handle, void genode_usb_notify_peers(void); +void genode_usb_handle_empty_sessions(void); + #ifdef __cplusplus } #endif diff --git a/repos/os/src/lib/genode_c_api/usb.cc b/repos/os/src/lib/genode_c_api/usb.cc index acebcb4042..1b7bb5714e 100644 --- a/repos/os/src/lib/genode_c_api/usb.cc +++ b/repos/os/src/lib/genode_c_api/usb.cc @@ -107,6 +107,11 @@ class genode_usb_session : public Usb::Session_rpc_object */ void notify(); + /* + * Acknowledge all remaining requests in the packet stream + */ + void flush_packet_stream(); + /*************************** ** USB session interface ** @@ -228,6 +233,11 @@ class Root : public Root_component */ template void session(genode_usb_session_handle_t id, FUNC const & fn); + + /* + * Acknowledge requests from sessions without device + */ + void handle_empty_sessions(); }; @@ -248,6 +258,22 @@ void genode_usb_session::notify() } +void genode_usb_session::flush_packet_stream() +{ + /* ack packets in flight */ + for (unsigned idx = 0; idx < MAX_PACKETS_IN_FLY; idx++) { + if (!packets[idx].constructed()) + continue; + _ack(Usb::Packet_descriptor::NO_DEVICE_ERROR, *packets[idx]); + packets[idx].destruct(); + } + + /* ack all packets in request stream */ + while (sink()->packet_avail() && sink()->ack_slots_free()) + _ack(Usb::Packet_descriptor::NO_DEVICE_ERROR, sink()->get_packet()); +} + + bool genode_usb_session::plugged() { genode_usb_bus_num_t bus; @@ -634,8 +660,10 @@ void ::Root::discontinue_device(genode_usb_bus_num_t bus, _devices[idx]->dev != dev) continue; - if (_devices[idx]->usb_session) + if (_devices[idx]->usb_session) { _devices[idx]->usb_session->notify(); + _devices[idx]->usb_session->flush_packet_stream(); + } _devices[idx].destruct(); _report(); @@ -682,6 +710,18 @@ bool ::Root::device_associated(genode_usb_session * session, } +void ::Root::handle_empty_sessions() +{ + _for_each_session([&] (genode_usb_session & s) { + bool associated = false; + _for_each_device([&] (Device & d) { + if (d.usb_session == &s) associated = true; }); + if (!associated) + s.flush_packet_stream(); + }); +} + + ::Root::Root(Env & env, Allocator & alloc, Signal_context_capability cap) : Root_component(env.ep(), alloc), @@ -766,3 +806,12 @@ extern "C" void genode_usb_ack_request(genode_usb_session_handle_t session_id, extern "C" void genode_usb_notify_peers() { } + + +extern "C" void genode_usb_handle_empty_sessions() +{ + if (!_usb_root) + return; + + _usb_root->handle_empty_sessions(); +} diff --git a/repos/pc/src/drivers/usb_host/pc/usb.c b/repos/pc/src/drivers/usb_host/pc/usb.c index 93c90f9c2d..f95ca883ac 100644 --- a/repos/pc/src/drivers/usb_host/pc/usb.c +++ b/repos/pc/src/drivers/usb_host/pc/usb.c @@ -473,6 +473,7 @@ static int usb_poll_sessions(void * data) usb_for_each_dev(&work_done, poll_usb_device); if (work_done) continue; + genode_usb_handle_empty_sessions(); lx_emul_task_schedule(true); }