USB_HOST_ERROR_UNKNOWN = TIZEN_ERROR_UNKNOWN, /**< Other error */
} usb_host_error_e;
+/**
+ * @ingroup CAPI_USB_HOST_HOTPLUG_MODULE
+ * @brief Enumeration of hotplug event types.
+ * @since_tizen 4.0
+ */
+typedef enum {
+ USB_HOST_HOTPLUG_EVENT_ATTACH, /**< Device was connected */
+ USB_HOST_HOTPLUG_EVENT_DETACH, /**< Device was disconnected */
+ USB_HOST_HOTPLUG_EVENT_ANY, /**< Any event */
+} usb_host_hotplug_event_e;
+
/**
* @ingroup CAPI_USB_HOST_MODULE
* @brief Context handle to USB host.
*/
typedef struct usb_host_endpoint_s *usb_host_endpoint_h;
+/**
+ * @ingroup CAPI_USB_HOST_HOTPLUG_MODULE
+ * @brief USB hotplug callback handle.
+ * @details This handle is used for managing registered hotplug callbacks.
+ * @since_tizen 4.0
+ */
+typedef struct usb_host_hotplug_s *usb_host_hotplug_h;
+
+/**
+ * @ingroup CAPI_USB_HOST_HOTPLUG_MODULE
+ * @brief Device connected/disconnected event handler.
+ * @details The device handle should be unreffed with usb_host_unref_device()
+ * when no longer needed.
+ * @since_tizen 4.0
+ * @param[in] dev Device which was connected/disconnected
+ * @param[in] user_data User data pointer passed on callback registration
+ */
+typedef void (*usb_host_hotplug_cb)(usb_host_device_h dev, void *user_data);
+
/* Library initialization and cleanup */
/**
int usb_host_transfer(usb_host_endpoint_h ep, unsigned char *data, int length,
int *transferred, unsigned int timeout);
+/**
+ * @ingroup CAPI_USB_HOST_HOTPLUG_MODULE
+ * @brief Registers a callback function to be invoked when a device is connected or disconnected.
+ * @since_tizen 4.0
+ * @param[in] ctx Context handle
+ * @param[in] cb The callback function to be registered
+ * @param[in] event Event that will trigger registered callback
+ * @param[in] user_data The user data to be passed to the callback function
+ * @param[out] handle Handle of the registered callback
+ * @return 0 on success, negative error code on error
+ * @retval #USB_HOST_ERROR_NONE Successful
+ * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported
+ * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed
+ * @retval #USB_HOST_ERROR_OUT_OF_MEMORY Out of memory
+ */
+int usb_host_set_hotplug_cb(usb_host_context_h ctx, usb_host_hotplug_cb cb, usb_host_hotplug_event_e event, void *user_data, usb_host_hotplug_h *handle);
+
+/**
+ * @ingroup CAPI_USB_HOST_HOTPLUG_MODULE
+ * @brief Unregisters the hotplug callback function.
+ * @since_tizen 4.0
+ * @param[in] handle Handle of the callback to be unregistered
+ * @return 0 on success, negative error code on error
+ * @retval #USB_HOST_ERROR_NONE Successful
+ * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed
+ * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported
+ */
+int usb_host_unset_hotplug_cb(usb_host_hotplug_h handle);
+
#ifdef __cplusplus
}
#endif
#include <stdlib.h>
#include <sys/queue.h>
#include <system_info.h>
+#include <poll.h>
#include "usb_host.h"
#include "uref.h"
//LCOV_EXCL_STOP
}
+static gboolean usb_host_poll_cb(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+ usb_host_context_h ctx = data;
+ _I("usb_host_poll_cb");
+
+ if (libusb_handle_events(ctx->lusb_ctx) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static int add_fd_watch(int fd, short events, void *user_data)
+{
+ GIOChannel *ch;
+ usb_host_context_h ctx = user_data;
+ GIOCondition condition = 0;
+ guint fd_handler;
+
+ if (events & POLLIN)
+ condition |= G_IO_IN;
+ if (events & POLLOUT)
+ condition |= G_IO_OUT;
+
+ ch = g_io_channel_unix_new(fd);
+ if (!ch) {
+ _E("Failed to create gio channel"); //LCOV_EXCL_LINE
+ return USB_HOST_ERROR_OUT_OF_MEMORY;
+ }
+
+ fd_handler = g_io_add_watch(ch, condition, usb_host_poll_cb, ctx);
+
+ pthread_mutex_lock(&ctx->channel_list_lock);
+ _I("added fd %d to poll", fd);
+ ctx->gio_channels = g_list_append(ctx->gio_channels, ch);
+ pthread_mutex_unlock(&ctx->channel_list_lock);
+
+ return USB_HOST_ERROR_NONE;
+}
+
+static void fd_added_cb(int fd, short events, void *user_data)
+{
+ add_fd_watch(fd, events, user_data);
+}
+
+static void fd_removed_cb(int fd, void *user_data)
+{
+ GIOChannel *ch;
+ usb_host_context_h ctx = user_data;
+ GList *l, *next;
+ int rfd;
+
+ pthread_mutex_lock(&ctx->channel_list_lock);
+ l = ctx->gio_channels;
+ while (l != NULL) {
+ ch = l->data;
+ next = l->next;
+ rfd = g_io_channel_unix_get_fd(ch);
+ if (fd == rfd) {
+ g_io_channel_unref(ch);
+ ctx->gio_channels = g_list_delete_link(ctx->gio_channels, l);
+ }
+
+ l = next;
+ }
+ pthread_mutex_unlock(&ctx->channel_list_lock);
+
+ _I("removed fd %d", fd);
+}
+
int usb_host_create(usb_host_context_h *ctx)
{
int ret = USB_HOST_ERROR_OUT_OF_MEMORY;
int count = 10;
+ int i;
struct usb_host_context_s *_ctx;
+ const struct libusb_pollfd **pollfds = NULL;
+ GList *l, *next;
+ GIOChannel *ch;
if (!usb_host_feature_enabled())
return USB_HOST_ERROR_NOT_SUPPORTED;
goto out; //LCOV_EXCL_LINE System Error
}
+ _ctx->gio_channels = NULL;
+
do {
ret = libusb_init(&(_ctx->lusb_ctx));
count--;
if (ret < 0) {
_E("Failed to init libusb (%d)", ret); //LCOV_EXCL_LINE
+ ret = translate_error(ret);
goto free_ctx; //LCOV_EXCL_LINE
}
+ ret = pthread_mutex_init(&_ctx->channel_list_lock, NULL);
+ if (ret != 0) {
+ _E("Failed to init mutex (%d)", ret); //LCOV_EXCL_LINE
+ goto free_ctx;
+ }
+
+ libusb_set_pollfd_notifiers(_ctx->lusb_ctx, fd_added_cb, fd_removed_cb, _ctx);
+ pollfds = libusb_get_pollfds(_ctx->lusb_ctx);
+ if (!pollfds) {
+ _E("Failed to get file descriptors for polling"); //LCOV_EXCL_LINE
+ ret = USB_HOST_ERROR_OUT_OF_MEMORY;
+ goto free_ctx;
+ }
+
+ for (i = 0; pollfds[i]; ++i) {
+ ret = add_fd_watch(pollfds[i]->fd, pollfds[i]->events, _ctx);
+ if (ret < 0)
+ goto free_ctx;
+ }
+
*ctx = _ctx;
+ free(pollfds);
return USB_HOST_ERROR_NONE;
//LCOV_EXCL_START System Error
free_ctx:
+ free(pollfds);
+ l = _ctx->gio_channels;
+ while (l != NULL) {
+ ch = l->data;
+ next = l->next;
+ g_io_channel_unref(ch);
+ l = next;
+ }
+
+ g_list_free(_ctx->gio_channels);
free(_ctx);
- ret = translate_error(ret);
out:
return ret;
//LCOV_EXCL_STOP
int usb_host_destroy(usb_host_context_h context)
{
+ GIOChannel *ch;
+ GList *l, *next;
+
if (!usb_host_feature_enabled())
return USB_HOST_ERROR_NOT_SUPPORTED;
return USB_HOST_ERROR_INVALID_PARAMETER;
}
+ l = context->gio_channels;
+ while (l != NULL) {
+ ch = l->data;
+ next = l->next;
+ g_io_channel_unref(ch);
+ l = next;
+ }
+
+ g_list_free(context->gio_channels);
+ pthread_mutex_destroy(&context->channel_list_lock);
libusb_exit(context->lusb_ctx);
free(context);
return USB_HOST_ERROR_NOT_SUPPORTED;
}
}
+
+static int lusb_hotplug_cb(libusb_context *ctx, libusb_device *lusb_device, libusb_hotplug_event event, void *user_data)
+{
+ struct usb_host_hotplug_s *data = user_data;
+ usb_host_device_h dev;
+
+ dev = alloc_device(lusb_device);
+ if (!dev) {
+ _E("Could not allocate device");
+ return 1;
+ }
+
+ data->cb(dev, data->user_data);
+
+ return 0;
+}
+
+int usb_host_set_hotplug_cb(usb_host_context_h ctx, usb_host_hotplug_cb cb, usb_host_hotplug_event_e event, void *user_data, usb_host_hotplug_h *handle)
+{
+ struct usb_host_hotplug_s *data;
+ libusb_hotplug_callback_handle lusb_handle;
+ int ret;
+ libusb_hotplug_event lusb_events = 0;
+
+ if (!usb_host_feature_enabled())
+ return USB_HOST_ERROR_NOT_SUPPORTED;
+
+ if (!cb)
+ return USB_HOST_ERROR_INVALID_PARAMETER;
+
+ data = calloc(1, sizeof(*data));
+ if (data == NULL) {
+ _E("Failed to alloc memory");
+ return USB_HOST_ERROR_OUT_OF_MEMORY;
+ }
+
+ data->ctx = ctx;
+ data->cb = cb;
+ data->user_data = user_data;
+
+ switch (event) {
+ case USB_HOST_HOTPLUG_EVENT_ATTACH:
+ lusb_events = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED;
+ break;
+ case USB_HOST_HOTPLUG_EVENT_DETACH:
+ lusb_events = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT;
+ break;
+ case USB_HOST_HOTPLUG_EVENT_ANY:
+ lusb_events = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT;
+ break;
+ }
+
+ ret = libusb_hotplug_register_callback(ctx->lusb_ctx, lusb_events,
+ 0, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
+ LIBUSB_HOTPLUG_MATCH_ANY, lusb_hotplug_cb, data, &lusb_handle);
+
+ if (ret != LIBUSB_SUCCESS) {
+ ret = translate_error(ret);
+ goto out;
+ }
+
+ data->lusb_handle = lusb_handle;
+ *handle = data;
+
+ return USB_HOST_ERROR_NONE;
+
+out:
+ free(data);
+ return ret;
+}
+
+int usb_host_unset_hotplug_cb(usb_host_hotplug_h handle)
+{
+ if (!usb_host_feature_enabled())
+ return USB_HOST_ERROR_NOT_SUPPORTED;
+
+ if (!handle)
+ return USB_HOST_ERROR_INVALID_PARAMETER;
+
+ libusb_hotplug_deregister_callback(handle->ctx->lusb_ctx, handle->lusb_handle);
+ free(handle);
+
+ return USB_HOST_ERROR_NONE;
+}