void API_EXPORTED libusb_exit(struct libusb_context *ctx) { usbi_dbg(""); USBI_GET_CONTEXT(ctx); if (ctx == usbi_default_context) { usbi_mutex_static_lock(&default_context_lock); if (--default_context_refcnt > 0) { usbi_dbg("not destroying default context"); usbi_mutex_static_unlock(&default_context_lock); return; } usbi_dbg("destroying default context"); usbi_default_context = NULL; usbi_mutex_static_unlock(&default_context_lock); } if (!list_empty(&ctx->open_devs)) usbi_warn(ctx, "application left some devices open"); usbi_io_exit(ctx); if (usbi_backend->exit) usbi_backend->exit(); usbi_mutex_destroy(&ctx->open_devs_lock); usbi_mutex_destroy(&ctx->usb_devs_lock); free(ctx); }
void linux_udev_hotplug_poll(void) { struct udev_device* udev_dev; usbi_mutex_static_lock(&linux_hotplug_lock); do { udev_dev = udev_monitor_receive_device(udev_monitor); if (udev_dev) { usbi_dbg("Handling hotplug event from hotplug_poll"); udev_hotplug_event(udev_dev); } } while (udev_dev); usbi_mutex_static_unlock(&linux_hotplug_lock); }
static void *linux_udev_event_thread_main(void *arg) { struct udev_device* udev_dev; struct pollfd fds = {.fd = udev_monitor_fd, .events = POLLIN}; usbi_dbg("udev event thread entering."); while (1 == poll(&fds, 1, -1)) { if (NULL == udev_monitor || POLLIN != fds.revents) { break; } usbi_mutex_static_lock(&linux_hotplug_lock); udev_dev = udev_monitor_receive_device(udev_monitor); if (udev_dev) udev_hotplug_event(udev_dev); usbi_mutex_static_unlock(&linux_hotplug_lock); } usbi_dbg("udev event thread exiting"); return NULL; }
int API_EXPORTED libusb_init(libusb_context **context) { char *dbg = getenv("LIBUSB_DEBUG"); struct libusb_context *ctx; int r = 0; usbi_mutex_static_lock(&default_context_lock); if (!context && usbi_default_context) { usbi_dbg("reusing default context"); default_context_refcnt++; usbi_mutex_static_unlock(&default_context_lock); return 0; } ctx = malloc(sizeof(*ctx)); if (!ctx) { r = LIBUSB_ERROR_NO_MEM; goto err_unlock; } memset(ctx, 0, sizeof(*ctx)); if (dbg) { ctx->debug = atoi(dbg); if (ctx->debug) ctx->debug_fixed = 1; } usbi_dbg("libusb-%d.%d.%d%s%s%s", libusb_version_internal.major, libusb_version_internal.minor, libusb_version_internal.micro, libusb_version_internal.rc, libusb_version_internal.describe[0] ? " git:" : "", libusb_version_internal.describe); if (usbi_backend->init) { r = usbi_backend->init(ctx); if (r) goto err_free_ctx; } usbi_mutex_init(&ctx->usb_devs_lock, NULL); usbi_mutex_init(&ctx->open_devs_lock, NULL); list_init(&ctx->usb_devs); list_init(&ctx->open_devs); r = usbi_io_init(ctx); if (r < 0) { if (usbi_backend->exit) usbi_backend->exit(); goto err_destroy_mutex; } if (context) { *context = ctx; } else if (!usbi_default_context) { usbi_dbg("created default context"); usbi_default_context = ctx; default_context_refcnt++; } usbi_mutex_static_unlock(&default_context_lock); return 0; err_destroy_mutex: usbi_mutex_destroy(&ctx->open_devs_lock); usbi_mutex_destroy(&ctx->usb_devs_lock); err_free_ctx: free(ctx); err_unlock: usbi_mutex_static_unlock(&default_context_lock); return r; }
static int linux_netlink_read_message(void) { unsigned char buffer[1024]; struct iovec iov = {.iov_base = buffer, .iov_len = sizeof(buffer)}; struct msghdr meh = { .msg_iov=&iov, .msg_iovlen=1, .msg_name=&snl, .msg_namelen=sizeof(snl) }; const char *sys_name = NULL; uint8_t busnum, devaddr; int detached, r; size_t len; /* read netlink message */ memset(buffer, 0, sizeof(buffer)); len = recvmsg(linux_netlink_socket, &meh, 0); if (len < 32) { if (errno != EAGAIN) usbi_dbg("error recieving message from netlink"); return -1; } /* TODO -- authenticate this message is from the kernel or udevd */ r = linux_netlink_parse(buffer, len, &detached, &sys_name, &busnum, &devaddr); if (r) return r; usbi_dbg("netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s", busnum, devaddr, sys_name, detached ? "yes" : "no"); /* signal device is available (or not) to all contexts */ if (detached) linux_hotplug_disconnected(busnum, devaddr, sys_name); else linux_hotplug_enumerate(busnum, devaddr, sys_name); return 0; } static void *linux_netlink_event_thread_main(void *arg) { struct pollfd fds = {.fd = linux_netlink_socket, .events = POLLIN}; /* silence compiler warning */ (void) arg; while (1 == poll(&fds, 1, -1)) { if (POLLIN != fds.revents) { break; } usbi_mutex_static_lock(&linux_hotplug_lock); linux_netlink_read_message(); usbi_mutex_static_unlock(&linux_hotplug_lock); } return NULL; } void linux_netlink_hotplug_poll(void) { int r; usbi_mutex_static_lock(&linux_hotplug_lock); do { r = linux_netlink_read_message(); } while (r == 0); usbi_mutex_static_unlock(&linux_hotplug_lock); }