WIP: Use USB hot-plugging to detect devices as they come and go
... if only it was working Change-Id: I6fddd62ce015dbf0151563e514a7bdf20ed01810
This commit is contained in:
parent
8e3924db25
commit
b4c3d9eed0
|
@ -194,7 +194,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* probe devices */
|
/* probe devices */
|
||||||
rv = e1_usb_probe(e1d);
|
rv = e1_usb_init(e1d);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
LOGP(DE1D, LOGL_ERROR, "Failed to prove usb devices\n");
|
LOGP(DE1D, LOGL_ERROR, "Failed to prove usb devices\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -422,7 +422,7 @@ int main(int argc, char **argv)
|
||||||
e1gen_init();
|
e1gen_init();
|
||||||
|
|
||||||
/* probe devices */
|
/* probe devices */
|
||||||
rv = e1_usb_probe(e1d);
|
rv = e1_usb_init(e1d);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
LOGP(DE1D, LOGL_ERROR, "Failed to prove usb devices\n");
|
LOGP(DE1D, LOGL_ERROR, "Failed to prove usb devices\n");
|
||||||
}
|
}
|
||||||
|
|
145
src/usb.c
145
src/usb.c
|
@ -960,12 +960,107 @@ next_interface:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
e1_usb_probe(struct e1_daemon *e1d)
|
_libusb_hotplug_cb(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event, void *user_data)
|
||||||
{
|
{
|
||||||
struct libusb_device **dev_list;
|
struct libusb_device_descriptor desc;
|
||||||
ssize_t n_dev;
|
struct e1_daemon *e1d = user_data;
|
||||||
int i, ret;
|
int ret;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
|
||||||
|
ret = libusb_get_device_descriptor(device, &desc);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* a bit redundant as we register the call-back only for those two, but
|
||||||
|
* in the future we might support more hardware and extend the checks here
|
||||||
|
* and drop the matching in the callback registration */
|
||||||
|
if ((desc.idVendor != USB_VID) || (desc.idProduct != USB_PID))
|
||||||
|
break;
|
||||||
|
|
||||||
|
LOGP(DE1D, LOGL_NOTICE, "HOTPLUG: USB Device plugged in\n");
|
||||||
|
_e1_usb_open_device(e1d, device);
|
||||||
|
break;
|
||||||
|
case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
|
||||||
|
LOGP(DE1D, LOGL_NOTICE, "HOTPLUG: USB Device removed\n");
|
||||||
|
/* TODO: iterate over list of interfaces, check for driver + usb-dev, ... */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* BEGIN libosmocore <= 1.6.0 workaround
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
|
static int _osmo_usb_fd_cb(struct osmo_fd *ofd, unsigned int what)
|
||||||
|
{
|
||||||
|
libusb_context *luctx = ofd->data;
|
||||||
|
|
||||||
|
/* we assume that we're running Linux v2.6.27 with timerfd support here
|
||||||
|
* and hence don't have to perform manual timeout handling. See
|
||||||
|
* "Notes on time-based events" at
|
||||||
|
* http://libusb.sourceforge.net/api-1.0/group__libusb__poll.html */
|
||||||
|
struct timeval zero_tv = { 0, 0 };
|
||||||
|
libusb_handle_events_timeout(luctx, &zero_tv);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _osmo_usb_added_cb(int fd, short events, void *user_data)
|
||||||
|
{
|
||||||
|
struct osmo_fd *ofd = talloc_zero(OTC_GLOBAL, struct osmo_fd);
|
||||||
|
libusb_context *luctx = user_data;
|
||||||
|
unsigned int when = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
LOGP(DLINP, LOGL_ERROR, "Adding fd=%u, events=0x%02x\n", fd, events);
|
||||||
|
|
||||||
|
if (events & POLLIN)
|
||||||
|
when |= OSMO_FD_READ;
|
||||||
|
if (events & POLLOUT)
|
||||||
|
when |= OSMO_FD_WRITE;
|
||||||
|
|
||||||
|
osmo_fd_setup(ofd, fd, when, _osmo_usb_fd_cb, luctx, 0);
|
||||||
|
rc = osmo_fd_register(ofd);
|
||||||
|
if (rc)
|
||||||
|
LOGP(DLINP, LOGL_ERROR, "osmo_fd_register() failed with rc=%d\n", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* work around a bug in all libosmocore versions <= 1.6.0 caused by misundertanding strange API
|
||||||
|
* requirements of libusb. */
|
||||||
|
static void libosmocore_160_workaround(void)
|
||||||
|
{
|
||||||
|
const struct libusb_pollfd **pfds;
|
||||||
|
|
||||||
|
/* get the initial file descriptors which were created even before during libusb_init() */
|
||||||
|
pfds = libusb_get_pollfds(g_usb);
|
||||||
|
if (pfds) {
|
||||||
|
const struct libusb_pollfd **pfds2 = pfds;
|
||||||
|
const struct libusb_pollfd *pfd;
|
||||||
|
|
||||||
|
/* synthesize 'add' call-backs. not sure why libusb doesn't do that by itself? */
|
||||||
|
for (pfd = *pfds2; pfd; pfd = *++pfds2) {
|
||||||
|
if (!osmo_fd_get_by_fd(pfd->fd))
|
||||||
|
_osmo_usb_added_cb(pfd->fd, pfd->events, g_usb);
|
||||||
|
}
|
||||||
|
libusb_free_pollfds(pfds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* END libosmocore <= 1.6.0 workaround
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
int
|
||||||
|
e1_usb_init(struct e1_daemon *e1d)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int events = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT;
|
||||||
|
|
||||||
if (!g_usb) {
|
if (!g_usb) {
|
||||||
ret = osmo_libusb_init(&g_usb);
|
ret = osmo_libusb_init(&g_usb);
|
||||||
|
@ -973,28 +1068,30 @@ e1_usb_probe(struct e1_daemon *e1d)
|
||||||
LOGP(DE1D, LOGL_ERROR, "Failed to initialize libusb\n");
|
LOGP(DE1D, LOGL_ERROR, "Failed to initialize libusb\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
libosmocore_160_workaround();
|
||||||
}
|
}
|
||||||
|
|
||||||
n_dev = libusb_get_device_list(g_usb, &dev_list);
|
if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
|
||||||
if (n_dev < 0) {
|
ret = libusb_hotplug_register_callback(g_usb, events, LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
|
||||||
LOGP(DE1D, LOGL_ERROR, "Failed to list devices\n");
|
LIBUSB_HOTPLUG_MATCH_ANY, _libusb_hotplug_cb, e1d, NULL);
|
||||||
return -EIO;
|
if (ret != LIBUSB_SUCCESS) {
|
||||||
|
LOGP(DE1D, LOGL_ERROR, "Failed to register USB hot plug call-back\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* no hot-plug capability, fall back to iterating devices once */
|
||||||
|
struct libusb_device **dev_list;
|
||||||
|
ssize_t n_dev, i;
|
||||||
|
|
||||||
|
n_dev = libusb_get_device_list(g_usb, &dev_list);
|
||||||
|
if (n_dev < 0) {
|
||||||
|
LOGP(DE1D, LOGL_ERROR, "Failed to list devices\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n_dev; i++)
|
||||||
|
_libusb_hotplug_cb(g_usb, dev_list[i], LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, e1d);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n_dev; i++) {
|
|
||||||
struct libusb_device_descriptor desc;
|
|
||||||
|
|
||||||
ret = libusb_get_device_descriptor(dev_list[i], &desc);
|
|
||||||
if (ret)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((desc.idVendor != USB_VID) || (desc.idProduct != USB_PID))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_e1_usb_open_device(e1d, dev_list[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_free_device_list(dev_list, 1);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,4 +18,4 @@ int e1_usb_ctrl_get_gpsdo_status(struct e1_intf *intf);
|
||||||
|
|
||||||
int e1_usb_intf_gpsdo_state_string(char *buf, size_t len, const struct e1_intf *intf);
|
int e1_usb_intf_gpsdo_state_string(char *buf, size_t len, const struct e1_intf *intf);
|
||||||
|
|
||||||
int e1_usb_probe(struct e1_daemon *e1d);
|
int e1_usb_init(struct e1_daemon *e1d);
|
||||||
|
|
Loading…
Reference in New Issue