usb: add asynchronous interface release

This became necessary, since URBs may still be pending upon interface
release.

Fixes #2466
This commit is contained in:
Sebastian Sumpf 2017-07-24 09:52:01 +02:00 committed by Christian Helmuth
parent 132748a783
commit 5adda2d934

View File

@ -39,6 +39,7 @@ namespace Usb {
class Session_component; class Session_component;
class Root; class Root;
class Worker; class Worker;
class Cleaner;
} }
/** /**
@ -517,6 +518,51 @@ class Usb::Worker
}; };
struct Interface : List<Interface>::Element
{
usb_interface *iface;
Interface(usb_interface *iface) : iface(iface) { }
};
/**
* Asynchronous USB-interface release
*/
class Usb::Cleaner : List<Interface>
{
private:
static void _run(void *c)
{
Cleaner *cleaner = (Cleaner *)c;
while (true) {
cleaner->_task.block_and_schedule();
while (Interface *interface = cleaner->first()) {
usb_driver_release_interface(&raw_intf_driver, interface->iface);
cleaner->remove(interface);
destroy(Lx::Malloc::mem(), interface);
}
}
}
Lx::Task _task { _run, this, "raw_cleaner", Lx::Task::PRIORITY_2,
Lx::scheduler() };
public:
void schedule_release(usb_interface *iface)
{
Interface *interface = new(Lx::Malloc::mem()) Interface(iface);
insert(interface);
_task.unblock();
Lx::scheduler().schedule();
}
};
/***************** /*****************
** USB session ** ** USB session **
*****************/ *****************/
@ -537,6 +583,7 @@ class Usb::Session_component : public Session_rpc_object,
Io_signal_handler<Session_component> _ready_ack; Io_signal_handler<Session_component> _ready_ack;
Worker _worker; Worker _worker;
Ram_dataspace_capability _tx_ds; Ram_dataspace_capability _tx_ds;
Usb::Cleaner &_cleaner;
void _signal_state_change() void _signal_state_change()
@ -562,13 +609,12 @@ class Usb::Session_component : public Session_rpc_object,
Genode::Entrypoint &ep, Genode::Entrypoint &ep,
Genode::Region_map &rm, Genode::Region_map &rm,
unsigned long vendor, unsigned long product, unsigned long vendor, unsigned long product,
long bus, long dev) long bus, long dev, Usb::Cleaner &cleaner)
: Session_rpc_object(tx_ds, ep.rpc_ep(), rm), : Session_rpc_object(tx_ds, ep.rpc_ep(), rm),
_ep(ep), _ep(ep), _vendor(vendor), _product(product), _bus(bus), _dev(dev),
_vendor(vendor), _product(product), _bus(bus), _dev(dev),
_packet_avail(ep, *this, &Session_component::_receive), _packet_avail(ep, *this, &Session_component::_receive),
_ready_ack(ep, *this, &Session_component::_receive), _ready_ack(ep, *this, &Session_component::_receive),
_worker(sink()), _tx_ds(tx_ds) _worker(sink()), _tx_ds(tx_ds), _cleaner(cleaner)
{ {
Device *device; Device *device;
if (bus && dev) if (bus && dev)
@ -623,7 +669,7 @@ class Usb::Session_component : public Session_rpc_object,
if (!iface) if (!iface)
throw Interface_not_found(); throw Interface_not_found();
usb_driver_release_interface(&raw_intf_driver, iface); _cleaner.schedule_release(iface);
} }
void config_descriptor(Device_descriptor *device_descr, void config_descriptor(Device_descriptor *device_descr,
@ -639,7 +685,6 @@ class Usb::Session_component : public Session_rpc_object,
else else
Genode::memset(config_descr, 0, sizeof(usb_config_descriptor)); Genode::memset(config_descr, 0, sizeof(usb_config_descriptor));
device_descr->bus = _device->udev->bus->busnum;
device_descr->num = _device->udev->devnum; device_descr->num = _device->udev->devnum;
device_descr->speed = _device->udev->speed; device_descr->speed = _device->udev->speed;
} }
@ -774,6 +819,8 @@ class Usb::Root : public Genode::Root_component<Session_component>
Genode::Reporter _device_list_reporter { Genode::Reporter _device_list_reporter {
_env, "devices", "devices", 512*1024 }; _env, "devices", "devices", 512*1024 };
Usb::Cleaner _cleaner;
void _handle_config() void _handle_config()
{ {
Lx_kit::env().config_rom().update(); Lx_kit::env().config_rom().update();
@ -832,7 +879,7 @@ class Usb::Root : public Genode::Root_component<Session_component>
Ram_dataspace_capability tx_ds = _env.ram().alloc(tx_buf_size); Ram_dataspace_capability tx_ds = _env.ram().alloc(tx_buf_size);
Session_component *session = new (md_alloc()) Session_component *session = new (md_alloc())
Session_component(tx_ds, _env.ep(), _env.rm(), vendor, product, bus, dev); Session_component(tx_ds, _env.ep(), _env.rm(), vendor, product, bus, dev, _cleaner);
::Session::list()->insert(session); ::Session::list()->insert(session);
return session; return session;
} }