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 */
|
||||
rv = e1_usb_probe(e1d);
|
||||
rv = e1_usb_init(e1d);
|
||||
if (rv != 0) {
|
||||
LOGP(DE1D, LOGL_ERROR, "Failed to prove usb devices\n");
|
||||
}
|
||||
|
|
|
@ -422,7 +422,7 @@ int main(int argc, char **argv)
|
|||
e1gen_init();
|
||||
|
||||
/* probe devices */
|
||||
rv = e1_usb_probe(e1d);
|
||||
rv = e1_usb_init(e1d);
|
||||
if (rv != 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
e1_usb_probe(struct e1_daemon *e1d)
|
||||
static int
|
||||
_libusb_hotplug_cb(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event, void *user_data)
|
||||
{
|
||||
struct libusb_device **dev_list;
|
||||
ssize_t n_dev;
|
||||
int i, ret;
|
||||
struct libusb_device_descriptor desc;
|
||||
struct e1_daemon *e1d = user_data;
|
||||
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) {
|
||||
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");
|
||||
return -EIO;
|
||||
}
|
||||
libosmocore_160_workaround();
|
||||
}
|
||||
|
||||
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;
|
||||
if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
|
||||
ret = libusb_hotplug_register_callback(g_usb, events, LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
|
||||
LIBUSB_HOTPLUG_MATCH_ANY, _libusb_hotplug_cb, e1d, NULL);
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue