usb_drv: generate a device list report

The report lists all connected devices and gets updated when devices are
added or removed.

Example report:

<devices>
    <device vendor_id="0x17ef" product_id="0x4816"/>
    <device vendor_id="0x0a5c" product_id="0x217f"/>
    <device vendor_id="0x8087" product_id="0x0020"/>
    <device vendor_id="0x8087" product_id="0x0020"/>
    <device vendor_id="0x1d6b" product_id="0x0002"/>
    <device vendor_id="0x1d6b" product_id="0x0002"/>
</devices>

There is no distinction yet for multiple devices of the same type.

The report is named "devices" and an example policy for 'report_rom' would
look like:

<policy label="vbox -> usb_devices" report="usb_drv -> devices"/>

The report only gets generated if enabled in the 'usb_drv' configuration:

<config>
    <raw>
        <report devices="yes"/>
    </raw>
</config>

Fixes #1506
This commit is contained in:
Christian Prochaska 2015-05-08 18:00:35 +02:00 committed by Christian Helmuth
parent e8f82a1da3
commit 2d869dd15e
10 changed files with 216 additions and 41 deletions

View File

@ -178,3 +178,35 @@ component can control the wireless driver. An example therefore is the Qt
based component in 'src/app/qt_wifi_connect'.
Currently only WPA/WPA2 protection using a pre-shared key is supported.
RAW
~~~
Allows raw access to USB devices via the 'Usb' session interface.
Configuration snippet:
!<start name="usb_drv">
! <resource name="RAM" quantum="8M"/>
! <provides><service name="Usb"/></provides>
! <config uhci="yes" ehci="yes" xhci="yes">
! <raw>
! <report devices="yes"/>
! </raw>
! </config>
!</start>
The optional 'devices' report lists the connected devices and gets updated when devices are added or removed.
Example report:
<devices>
<device vendor_id="0x17ef" product_id="0x4816"/>
<device vendor_id="0x0a5c" product_id="0x217f"/>
<device vendor_id="0x8087" product_id="0x0020"/>
<device vendor_id="0x8087" product_id="0x0020"/>
<device vendor_id="0x1d6b" product_id="0x0002"/>
<device vendor_id="0x1d6b" product_id="0x0002"/>
</devices>
There is no distinction yet for multiple devices of the same type.

View File

@ -241,12 +241,8 @@ int kthread_stop(struct task_struct *k) { TRACE; return 0; }
** linux/notifier.h **
**********************/
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *nb) { TRACE; return 0; }
int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
struct notifier_block *nb) { TRACE; return 0; }
int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v) { TRACE; return 0; }
int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
struct notifier_block *nb) { TRACE; return 0; }
int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,

View File

@ -1337,6 +1337,13 @@ enum {
struct notifier_block {
int (*notifier_call)(struct notifier_block *, unsigned long, void *);
struct notifier_block *next;
int priority;
};
struct raw_notifier_head
{
struct notifier_block *head;
};
struct atomic_notifier_head {

View File

@ -43,6 +43,9 @@ struct Services
unsigned long screen_width = 0;
unsigned long screen_height = 0;
/* report generation */
bool raw_report_device_list = false;
Services()
{
using namespace Genode;
@ -79,8 +82,13 @@ struct Services
}
try {
config()->xml_node().sub_node("raw");
Genode::Xml_node node_raw = config()->xml_node().sub_node("raw");
raw = true;
try {
Genode::Xml_node node_report = node_raw.sub_node("report");
raw_report_device_list = node_report.attribute("devices").has_value("yes");
} catch (...) { }
} catch (Xml_node::Nonexistent_sub_node) {
PDBG("No <raw> config node found - not starting external USB service");
}

View File

@ -100,7 +100,7 @@ namespace Nic
namespace Raw
{
void init(Server::Entrypoint &ep);
void init(Server::Entrypoint &ep, bool report_device_list);
}
#endif /* _SIGNAL_H_ */

View File

@ -1299,3 +1299,61 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int len,
return 2 * length;
}
/**********************
** linux/notifier.h **
**********************/
int raw_notifier_chain_register(struct raw_notifier_head *nh,
struct notifier_block *n)
{
struct notifier_block *nl = nh->head;
struct notifier_block *pr = 0;
while (nl) {
if (n->priority > nl->priority)
break;
pr = nl;
nl = nl->next;
}
n->next = nl;
if (pr)
pr->next = n;
else
nh->head = n;
return 0;
}
int raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v)
{
int ret = NOTIFY_DONE;
struct notifier_block *nb = nh->head;
while (nb) {
ret = nb->notifier_call(nb, val, v);
if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
break;
nb = nb->next;
}
return ret;
}
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *n)
{
return raw_notifier_chain_register((struct raw_notifier_head *)nh, n);
}
int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v)
{
return raw_notifier_call_chain((struct raw_notifier_head *)nh, val, v);
}

View File

@ -59,6 +59,14 @@ static void init(Services *services)
/* start jiffies */
dde_kit_timer_init(0, 0);
/*
* The RAW driver is initialized first to make sure that it doesn't miss
* notifications about added devices.
*/
if (services->raw)
/* low level interface */
module_raw_driver_init();
/* USB */
subsys_usb_init();
@ -82,10 +90,6 @@ static void init(Services *services)
/* storage */
if (services->stor)
module_usb_storage_driver_init();
if (services->raw)
/* low level interface */
module_raw_driver_init();
}
@ -103,7 +107,7 @@ void start_usb_driver(Server::Entrypoint &ep)
Nic::init(ep);
if (services.raw)
Raw::init(ep);
Raw::init(ep, services.raw_report_device_list);
Routine::add(0, 0, "Main", true);
Routine::make_main_current();

View File

@ -13,6 +13,7 @@
#include <base/env.h>
#include <base/printf.h>
#include <os/reporter.h>
#include <root/component.h>
#include <usb_session/rpc_object.h>
#include <util/list.h>
@ -43,13 +44,6 @@ struct Device : List<Device>::Element
{
usb_device *udev;
Device(usb_device *udev) : udev(udev)
{
list()->insert(this);
}
~Device() { list()->remove(this); }
static List<Device> *list()
{
static List<Device> _l;
@ -66,6 +60,50 @@ struct Device : List<Device>::Element
return nullptr;
}
static Genode::Reporter &device_list_reporter()
{
static Genode::Reporter _r("devices", 512*1024);
return _r;
}
static void report_device_list()
{
Genode::Reporter::Xml_generator xml(device_list_reporter(), [&] ()
{
for (Device *d = list()->first(); d; d = d->next()) {
xml.node("device", [&] ()
{
char buf[7];
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);
});
}
});
}
Device(usb_device *udev) : udev(udev)
{
list()->insert(this);
if (device_list_reporter().is_enabled())
report_device_list();
}
~Device()
{
list()->remove(this);
if (device_list_reporter().is_enabled())
report_device_list();
}
usb_interface *interface(unsigned index)
{
usb_interface *iface = udev->actconfig->interface[index];
@ -387,9 +425,6 @@ class Usb::Worker
_wait_event(_device);
_wait_event(_device->udev->actconfig);
/* set raw driver */
_device->udev->dev.driver = &raw_driver.drvwrap.driver;
if (_sigh_ready.valid())
Signal_transmitter(_sigh_ready).submit(1);
@ -510,6 +545,11 @@ class Usb::Session_component : public Session_rpc_object,
_tx.sigh_packet_avail(_packet_avail);
}
~Session_component()
{
_worker.stop();
}
/***********************
** Session interface **
***********************/
@ -677,6 +717,12 @@ class Usb::Root : public Genode::Root_component<Session_component>
return session;
}
void _destroy_session(Session_component *session)
{
::Session::list()->remove(session);
Genode::Root_component<Session_component>::_destroy_session(session);
}
public:
Root(Server::Entrypoint &session_ep,
@ -686,8 +732,9 @@ class Usb::Root : public Genode::Root_component<Session_component>
};
void Raw::init(Server::Entrypoint &ep)
void Raw::init(Server::Entrypoint &ep, bool report_device_list)
{
Device::device_list_reporter().enabled(report_device_list);
static Usb::Root root(ep, env()->heap());
Genode::env()->parent()->announce(ep.rpc_ep().manage(&root));
}
@ -697,18 +744,36 @@ void Raw::init(Server::Entrypoint &ep)
** C interface **
*****************/
void raw_register_device(struct usb_device *udev)
int raw_notify(struct notifier_block *nb, unsigned long action, void *data)
{
::Session::list()->state_change(Usb::Session_component::DEVICE_ADD,
new (env()->heap()) Device(udev));
struct usb_device *udev = (struct usb_device*)data;
switch (action) {
case USB_DEVICE_ADD:
{
::Session::list()->state_change(Usb::Session_component::DEVICE_ADD,
new (env()->heap()) Device(udev));
break;
}
case USB_DEVICE_REMOVE:
{
Device *dev = Device::device(udev->descriptor.idVendor,
udev->descriptor.idProduct);
if (dev) {
::Session::list()->state_change(Usb::Session_component::DEVICE_REMOVE, dev);
destroy(env()->heap(), dev);
}
break;
}
case USB_BUS_ADD:
break;
case USB_BUS_REMOVE:
break;
}
return NOTIFY_OK;
}
void raw_unregister_device(struct usb_device *udev)
{
Device *dev = Device::device(udev->descriptor.idVendor,
udev->descriptor.idProduct);
if (dev)
::Session::list()->state_change(Usb::Session_component::DEVICE_REMOVE, dev);
}

View File

@ -7,8 +7,6 @@ struct usb_driver;
extern struct usb_device_driver raw_driver;
extern struct usb_driver raw_intf_driver;
void raw_register_device(struct usb_device *udev);
void raw_unregister_device(struct usb_device *udev);
int raw_notify(struct notifier_block *nb, unsigned long action, void *data);
#endif /* _RAW_H_ */

View File

@ -19,15 +19,12 @@ static int raw_probe(struct usb_device *udev)
printk("RAW: vendor: %x product: %x dev %p\n",
udev->descriptor.idVendor, udev->descriptor.idProduct, udev);
raw_register_device(udev);
return -ENODEV;
}
static void raw_disconnect(struct usb_device *udev)
{
printk("driver disconnect called\n");
raw_unregister_device(udev);
}
@ -67,6 +64,12 @@ struct usb_driver raw_intf_driver =
};
struct notifier_block usb_nb =
{
.notifier_call = raw_notify
};
static int raw_driver_init(void)
{
int err;
@ -81,6 +84,10 @@ static int raw_driver_init(void)
printk("RAW: interface driver registered\n");
usb_register_notify(&usb_nb);
printk("RAW: notify function registered\n");
return 0;
}