mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-19 15:43:56 +00:00
usb_host: refine class heuristics on device report
This patch is an interim fix for using HID devices that offer a HID interface as not the first interface. It also supplements the interface classes as supplemental information to the USB-devices report. Fixes #4035
This commit is contained in:
@ -55,7 +55,7 @@ struct Device : List<Device>::Element
|
|||||||
return &_l;
|
return &_l;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Device * device_product(uint16_t vendor, uint16_t product)
|
static Device * device_by_product(uint16_t vendor, uint16_t product)
|
||||||
{
|
{
|
||||||
for (Device *d = list()->first(); d; d = d->next()) {
|
for (Device *d = list()->first(); d; d = d->next()) {
|
||||||
if (d->udev->descriptor.idVendor == vendor && d->udev->descriptor.idProduct == product)
|
if (d->udev->descriptor.idVendor == vendor && d->udev->descriptor.idProduct == product)
|
||||||
@ -66,7 +66,7 @@ struct Device : List<Device>::Element
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Device * device_bus(long bus, long dev)
|
static Device * device_by_bus(long bus, long dev)
|
||||||
{
|
{
|
||||||
for (Device *d = list()->first(); d; d = d->next()) {
|
for (Device *d = list()->first(); d; d = d->next()) {
|
||||||
if (d->udev->bus->busnum == bus && d->udev->devnum == dev)
|
if (d->udev->bus->busnum == bus && d->udev->devnum == dev)
|
||||||
@ -76,11 +76,10 @@ struct Device : List<Device>::Element
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Device * device_class(long class_, Session_label label)
|
static Device * device_by_class(long class_value, Session_label label)
|
||||||
{
|
{
|
||||||
for (Device *d = list()->first(); d; d = d->next()) {
|
for (Device *d = list()->first(); d; d = d->next()) {
|
||||||
long c = d->interface(0)->cur_altsetting->desc.bInterfaceClass;
|
if (class_value == d->device_class_value() && label == d->label())
|
||||||
if (class_ == c && label == d->label())
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,6 +112,90 @@ struct Device : List<Device>::Element
|
|||||||
return iface;
|
return iface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename FN>
|
||||||
|
void _with_interface(unsigned index, FN const &fn)
|
||||||
|
{
|
||||||
|
if (!udev || !udev->actconfig)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (index >= udev->actconfig->desc.bNumInterfaces)
|
||||||
|
return;
|
||||||
|
|
||||||
|
usb_interface * const interface_ptr = udev->actconfig->interface[index];
|
||||||
|
|
||||||
|
if (!interface_ptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fn(*interface_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FN>
|
||||||
|
void _for_each_interface(FN const &fn)
|
||||||
|
{
|
||||||
|
if (!udev || !udev->actconfig)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < udev->actconfig->desc.bNumInterfaces; i++)
|
||||||
|
_with_interface(i, fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return pseudo device class of USB device
|
||||||
|
*
|
||||||
|
* The returned value expresses the type of USB device. If the device
|
||||||
|
* has at least one HID interface, the value is USB_CLASS_HID. Otherwise,
|
||||||
|
* the class of the first interface is interpreted at type the device.
|
||||||
|
*
|
||||||
|
* Note this classification of USB devices is meant as an interim solution
|
||||||
|
* only to assist the implementation of access-control policies.
|
||||||
|
*/
|
||||||
|
unsigned device_class_value()
|
||||||
|
{
|
||||||
|
unsigned result = 0;
|
||||||
|
|
||||||
|
_with_interface(0, [&] (usb_interface &interface) {
|
||||||
|
if (interface.cur_altsetting)
|
||||||
|
result = interface.cur_altsetting->desc.bInterfaceClass; });
|
||||||
|
|
||||||
|
_for_each_interface([&] (usb_interface &interface) {
|
||||||
|
if (interface.cur_altsetting)
|
||||||
|
if (interface.cur_altsetting->desc.bInterfaceClass == USB_CLASS_HID)
|
||||||
|
result = USB_CLASS_HID; });
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void report(Xml_generator &xml)
|
||||||
|
{
|
||||||
|
if (!udev || !udev->actconfig)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
using Value = String<64>;
|
||||||
|
|
||||||
|
xml.attribute("label", label());
|
||||||
|
xml.attribute("vendor_id", Value(Hex(udev->descriptor.idVendor)));
|
||||||
|
xml.attribute("product_id", Value(Hex(udev->descriptor.idProduct)));
|
||||||
|
xml.attribute("bus", Value(Hex(udev->bus->busnum)));
|
||||||
|
xml.attribute("dev", Value(Hex(udev->devnum)));
|
||||||
|
xml.attribute("class", Value(Hex(device_class_value())));
|
||||||
|
|
||||||
|
_for_each_interface([&] (usb_interface &interface) {
|
||||||
|
|
||||||
|
if (!interface.cur_altsetting)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xml.node("interface", [&] () {
|
||||||
|
|
||||||
|
uint8_t const class_value =
|
||||||
|
interface.cur_altsetting->desc.bInterfaceClass;
|
||||||
|
|
||||||
|
xml.attribute("class", Value(Hex(class_value)));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
usb_host_endpoint *endpoint(usb_interface *iface, unsigned alt_setting,
|
usb_host_endpoint *endpoint(usb_interface *iface, unsigned alt_setting,
|
||||||
unsigned endpoint_num)
|
unsigned endpoint_num)
|
||||||
{
|
{
|
||||||
@ -838,17 +921,18 @@ class Usb::Session_component : public Session_rpc_object,
|
|||||||
_ready_ack(ep, *this, &Session_component::_receive),
|
_ready_ack(ep, *this, &Session_component::_receive),
|
||||||
_worker(sink()), _tx_ds(tx_ds), _cleaner(cleaner)
|
_worker(sink()), _tx_ds(tx_ds), _cleaner(cleaner)
|
||||||
{
|
{
|
||||||
Device *device;
|
Device *device_ptr;
|
||||||
if (bus && dev) {
|
if (bus && dev) {
|
||||||
device = Device::device_bus(bus, dev);
|
device_ptr = Device::device_by_bus(bus, dev);
|
||||||
} else if (vendor && product) {
|
} else if (vendor && product) {
|
||||||
device = Device::device_product(_vendor, _product);
|
device_ptr = Device::device_by_product(_vendor, _product);
|
||||||
} else
|
} else {
|
||||||
device = Device::device_class(_class, _label);
|
device_ptr = Device::device_by_class(_class, _label);
|
||||||
if (device) {
|
|
||||||
state_change(DEVICE_ADD, device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (device_ptr)
|
||||||
|
state_change(DEVICE_ADD, device_ptr);
|
||||||
|
|
||||||
/* register signal handlers */
|
/* register signal handlers */
|
||||||
_tx.sigh_packet_avail(_packet_avail);
|
_tx.sigh_packet_avail(_packet_avail);
|
||||||
}
|
}
|
||||||
@ -994,7 +1078,7 @@ class Usb::Session_component : public Session_rpc_object,
|
|||||||
|| (_bus && _dev && _bus == device->udev->bus->busnum &&
|
|| (_bus && _dev && _bus == device->udev->bus->busnum &&
|
||||||
_dev == device->udev->devnum)
|
_dev == device->udev->devnum)
|
||||||
|| (iface && iface->cur_altsetting &&
|
|| (iface && iface->cur_altsetting &&
|
||||||
_class == iface->cur_altsetting->desc.bInterfaceClass &&
|
_class == device->device_class_value() &&
|
||||||
_label == device->label())? true : false;
|
_label == device->label())? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1193,40 +1277,13 @@ void Device::report_device_list()
|
|||||||
{
|
{
|
||||||
|
|
||||||
for (Device *d = list()->first(); d; d = d->next()) {
|
for (Device *d = list()->first(); d; d = d->next()) {
|
||||||
usb_interface *iface = d->interface(0);
|
|
||||||
|
|
||||||
if (!iface || !iface->cur_altsetting || !d->udev || !d->udev->bus) {
|
if (!d->udev || !d->udev->bus) {
|
||||||
Genode::warning("device ", d->label().string(), " state incomplete");
|
Genode::warning("device ", d->label().string(), " state incomplete");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.node("device", [&] ()
|
xml.node("device", [&] () { d->report(xml); });
|
||||||
{
|
|
||||||
char buf[16];
|
|
||||||
|
|
||||||
unsigned const bus = d->udev->bus->busnum;
|
|
||||||
unsigned const dev = d->udev->devnum;
|
|
||||||
|
|
||||||
xml.attribute("label", d->label().string());
|
|
||||||
|
|
||||||
Genode::snprintf(buf, sizeof(buf), "0x%4x",
|
|
||||||
d->udev->descriptor.idVendor);
|
|
||||||
xml.attribute("vendor_id", buf);
|
|
||||||
|
|
||||||
Genode::snprintf(buf, sizeof(buf), "0x%4x",
|
|
||||||
d->udev->descriptor.idProduct);
|
|
||||||
xml.attribute("product_id", buf);
|
|
||||||
|
|
||||||
Genode::snprintf(buf, sizeof(buf), "0x%4x", bus);
|
|
||||||
xml.attribute("bus", buf);
|
|
||||||
|
|
||||||
Genode::snprintf(buf, sizeof(buf), "0x%4x", dev);
|
|
||||||
xml.attribute("dev", buf);
|
|
||||||
|
|
||||||
Genode::snprintf(buf, sizeof(buf), "0x%02x",
|
|
||||||
iface->cur_altsetting->desc.bInterfaceClass);
|
|
||||||
xml.attribute("class", buf);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1256,8 +1313,7 @@ int raw_notify(struct notifier_block *nb, unsigned long action, void *data)
|
|||||||
|
|
||||||
case USB_DEVICE_REMOVE:
|
case USB_DEVICE_REMOVE:
|
||||||
{
|
{
|
||||||
Device *dev = Device::device_bus(udev->bus->busnum,
|
Device *dev = Device::device_by_bus(udev->bus->busnum, udev->devnum);
|
||||||
udev->devnum);
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
::Session::list()->state_change(Usb::Session_component::DEVICE_REMOVE, dev);
|
::Session::list()->state_change(Usb::Session_component::DEVICE_REMOVE, dev);
|
||||||
destroy(Lx::Malloc::mem(), dev);
|
destroy(Lx::Malloc::mem(), dev);
|
||||||
|
Reference in New Issue
Block a user