genode_c_api: support to handle empty usb session

Adds a function to the USB part of the Genode's C API, to enable
usb_host drivers to acknowledge USB request in client's packet buffer
although they are not assigned to an USB device. The requests are
marked with a "no device" error.

This commit fixes a regression originally solved in genodelabs/genode#4149

Ref genodelabs/genode#4416
This commit is contained in:
Stefan Kalkowski 2022-02-16 13:01:50 +01:00 committed by Norman Feske
parent c2efa5406e
commit 3c07bf4e86
3 changed files with 53 additions and 1 deletions

View File

@ -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

View File

@ -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<genode_usb_session>
*/
template <typename FUNC>
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<genode_usb_session>(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();
}

View File

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