void usbi_hotplug_match(struct libusb_device *dev, libusb_hotplug_event event) { struct libusb_hotplug_callback *hotplug_cb, *next; struct libusb_context *ctx = dev->ctx; int ret; usbi_mutex_lock(&ctx->hotplug_cbs_lock); list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { usbi_mutex_unlock(&ctx->hotplug_cbs_lock); ret = usbi_hotplug_match_cb (dev, event, hotplug_cb); usbi_mutex_lock(&ctx->hotplug_cbs_lock); if (ret) { list_del(&hotplug_cb->list); free(hotplug_cb); } } usbi_mutex_unlock(&ctx->hotplug_cbs_lock); /* loop through and disconnect all open handles for this device */ if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) { struct libusb_device_handle *handle; usbi_mutex_lock(&ctx->open_devs_lock); list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { if (dev == handle->dev) { usbi_handle_disconnect (handle); } } usbi_mutex_unlock(&ctx->open_devs_lock); } }
void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event) { struct libusb_hotplug_callback *hotplug_cb, *next; int ret; usbi_mutex_lock(&ctx->hotplug_cbs_lock); list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { usbi_mutex_unlock(&ctx->hotplug_cbs_lock); ret = usbi_hotplug_match_cb (ctx, dev, event, hotplug_cb); usbi_mutex_lock(&ctx->hotplug_cbs_lock); if (ret) { list_del(&hotplug_cb->list); free(hotplug_cb); } } usbi_mutex_unlock(&ctx->hotplug_cbs_lock); /* the backend is expected to call the callback for each active transfer */ }
int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, libusb_hotplug_event events, libusb_hotplug_flag flags, int vendor_id, int product_id, int dev_class, libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *handle) { libusb_hotplug_callback *new_callback; static int handle_id = 1; /* check for hotplug support */ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { return LIBUSB_ERROR_NOT_SUPPORTED; } /* check for sane values */ if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) || (LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) || (LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) || !cb_fn) { return LIBUSB_ERROR_INVALID_PARAM; } USBI_GET_CONTEXT(ctx); new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback)); if (!new_callback) { return LIBUSB_ERROR_NO_MEM; } new_callback->ctx = ctx; new_callback->vendor_id = vendor_id; new_callback->product_id = product_id; new_callback->dev_class = dev_class; new_callback->flags = flags; new_callback->events = events; new_callback->cb = cb_fn; new_callback->user_data = user_data; new_callback->needs_free = 0; usbi_mutex_lock(&ctx->hotplug_cbs_lock); /* protect the handle by the context hotplug lock. it doesn't matter if the same handle * is used for different contexts only that the handle is unique for this context */ new_callback->handle = handle_id++; list_add(&new_callback->list, &ctx->hotplug_cbs); usbi_mutex_unlock(&ctx->hotplug_cbs_lock); if (flags & LIBUSB_HOTPLUG_ENUMERATE) { int i, len; struct libusb_device **devs; len = (int) libusb_get_device_list(ctx, &devs); if (len < 0) { libusb_hotplug_deregister_callback(ctx, new_callback->handle); return len; } for (i = 0; i < len; i++) { usbi_hotplug_match_cb(ctx, devs[i], LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, new_callback); } libusb_free_device_list(devs, 1); } if (handle) { *handle = new_callback->handle; } return LIBUSB_SUCCESS; }