From 2d869dd15eaec7bea4307b2f1e522dc60e901741 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Fri, 8 May 2015 18:00:35 +0200 Subject: [PATCH] usb_drv: generate a device list report The report lists all connected devices and gets updated when devices are added or removed. Example report: 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: The report only gets generated if enabled in the 'usb_drv' configuration: Fixes #1506 --- repos/dde_linux/README | 32 +++++ repos/dde_linux/src/lib/usb/dummies.c | 4 - repos/dde_linux/src/lib/usb/include/lx_emul.h | 7 ++ .../dde_linux/src/lib/usb/include/platform.h | 10 +- repos/dde_linux/src/lib/usb/include/signal.h | 2 +- repos/dde_linux/src/lib/usb/lx_emul.cc | 58 +++++++++ repos/dde_linux/src/lib/usb/main.cc | 14 ++- repos/dde_linux/src/lib/usb/raw/raw.cc | 113 ++++++++++++++---- repos/dde_linux/src/lib/usb/raw/raw.h | 4 +- repos/dde_linux/src/lib/usb/raw/raw_driver.c | 13 +- 10 files changed, 216 insertions(+), 41 deletions(-) diff --git a/repos/dde_linux/README b/repos/dde_linux/README index 56bfcf304..e2b5ac08f 100644 --- a/repos/dde_linux/README +++ b/repos/dde_linux/README @@ -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: + +! +! +! +! +! +! +! +! +! + +The optional 'devices' report lists the connected devices and gets updated when devices are added or removed. + +Example report: + + + + + + + + + + +There is no distinction yet for multiple devices of the same type. diff --git a/repos/dde_linux/src/lib/usb/dummies.c b/repos/dde_linux/src/lib/usb/dummies.c index fdde85cad..0f9629671 100644 --- a/repos/dde_linux/src/lib/usb/dummies.c +++ b/repos/dde_linux/src/lib/usb/dummies.c @@ -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, diff --git a/repos/dde_linux/src/lib/usb/include/lx_emul.h b/repos/dde_linux/src/lib/usb/include/lx_emul.h index cd37530c8..65cb28e7a 100644 --- a/repos/dde_linux/src/lib/usb/include/lx_emul.h +++ b/repos/dde_linux/src/lib/usb/include/lx_emul.h @@ -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 { diff --git a/repos/dde_linux/src/lib/usb/include/platform.h b/repos/dde_linux/src/lib/usb/include/platform.h index a96a2e441..bcd5c1727 100644 --- a/repos/dde_linux/src/lib/usb/include/platform.h +++ b/repos/dde_linux/src/lib/usb/include/platform.h @@ -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 config node found - not starting external USB service"); } diff --git a/repos/dde_linux/src/lib/usb/include/signal.h b/repos/dde_linux/src/lib/usb/include/signal.h index 38faafd73..c5b666583 100644 --- a/repos/dde_linux/src/lib/usb/include/signal.h +++ b/repos/dde_linux/src/lib/usb/include/signal.h @@ -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_ */ diff --git a/repos/dde_linux/src/lib/usb/lx_emul.cc b/repos/dde_linux/src/lib/usb/lx_emul.cc index ad52977b3..a17907042 100644 --- a/repos/dde_linux/src/lib/usb/lx_emul.cc +++ b/repos/dde_linux/src/lib/usb/lx_emul.cc @@ -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); +} diff --git a/repos/dde_linux/src/lib/usb/main.cc b/repos/dde_linux/src/lib/usb/main.cc index 99af661f0..4f0676170 100644 --- a/repos/dde_linux/src/lib/usb/main.cc +++ b/repos/dde_linux/src/lib/usb/main.cc @@ -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(); diff --git a/repos/dde_linux/src/lib/usb/raw/raw.cc b/repos/dde_linux/src/lib/usb/raw/raw.cc index c0384194d..581a16c4e 100644 --- a/repos/dde_linux/src/lib/usb/raw/raw.cc +++ b/repos/dde_linux/src/lib/usb/raw/raw.cc @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -43,13 +44,6 @@ struct Device : List::Element { usb_device *udev; - Device(usb_device *udev) : udev(udev) - { - list()->insert(this); - } - - ~Device() { list()->remove(this); } - static List *list() { static List _l; @@ -66,6 +60,50 @@ struct Device : List::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 return session; } + void _destroy_session(Session_component *session) + { + ::Session::list()->remove(session); + Genode::Root_component::_destroy_session(session); + } + public: Root(Server::Entrypoint &session_ep, @@ -686,8 +732,9 @@ class Usb::Root : public Genode::Root_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); -} - diff --git a/repos/dde_linux/src/lib/usb/raw/raw.h b/repos/dde_linux/src/lib/usb/raw/raw.h index 041ce439b..672717236 100644 --- a/repos/dde_linux/src/lib/usb/raw/raw.h +++ b/repos/dde_linux/src/lib/usb/raw/raw.h @@ -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_ */ diff --git a/repos/dde_linux/src/lib/usb/raw/raw_driver.c b/repos/dde_linux/src/lib/usb/raw/raw_driver.c index 8c3e3fa7a..d8b9b6373 100644 --- a/repos/dde_linux/src/lib/usb/raw/raw_driver.c +++ b/repos/dde_linux/src/lib/usb/raw/raw_driver.c @@ -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; }