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