aboutsummaryrefslogtreecommitdiff
path: root/libusb/libusbi.h
diff options
context:
space:
mode:
Diffstat (limited to 'libusb/libusbi.h')
-rw-r--r--libusb/libusbi.h153
1 files changed, 141 insertions, 12 deletions
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 491114b..b1fc88c 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -83,6 +83,34 @@
#define PTR_ALIGN(v) \
(((v) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1))
+/* Atomic operations
+ *
+ * Useful for reference counting or when accessing a value without a lock
+ *
+ * The following atomic operations are defined:
+ * usbi_atomic_load() - Atomically read a variable's value
+ * usbi_atomic_store() - Atomically write a new value value to a variable
+ * usbi_atomic_inc() - Atomically increment a variable's value and return the new value
+ * usbi_atomic_dec() - Atomically decrement a variable's value and return the new value
+ *
+ * All of these operations are ordered with each other, thus the effects of
+ * any one operation is guaranteed to be seen by any other operation.
+ */
+#ifdef _MSC_VER
+typedef volatile LONG usbi_atomic_t;
+#define usbi_atomic_load(a) (*(a))
+#define usbi_atomic_store(a, v) (*(a)) = (v)
+#define usbi_atomic_inc(a) InterlockedIncrement((a))
+#define usbi_atomic_dec(a) InterlockedDecrement((a))
+#else
+#include <stdatomic.h>
+typedef atomic_long usbi_atomic_t;
+#define usbi_atomic_load(a) atomic_load((a))
+#define usbi_atomic_store(a, v) atomic_store((a), (v))
+#define usbi_atomic_inc(a) (atomic_fetch_add((a), 1) + 1)
+#define usbi_atomic_dec(a) (atomic_fetch_add((a), -1) - 1)
+#endif
+
/* Internal abstractions for event handling and thread synchronization */
#if defined(PLATFORM_POSIX)
#include "os/events_posix.h"
@@ -289,22 +317,23 @@ void usbi_log(struct libusb_context *ctx, enum libusb_log_level level,
#define usbi_err(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_ERROR, __VA_ARGS__)
#define usbi_warn(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_WARNING, __VA_ARGS__)
#define usbi_info(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_INFO, __VA_ARGS__)
-#define usbi_dbg(...) _usbi_log(NULL, LIBUSB_LOG_LEVEL_DEBUG, __VA_ARGS__)
+#define usbi_dbg(ctx ,...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_DEBUG, __VA_ARGS__)
#else /* ENABLE_LOGGING */
#define usbi_err(ctx, ...) UNUSED(ctx)
#define usbi_warn(ctx, ...) UNUSED(ctx)
#define usbi_info(ctx, ...) UNUSED(ctx)
-#define usbi_dbg(...) do {} while (0)
+#define usbi_dbg(ctx, ...) do {} while (0)
#endif /* ENABLE_LOGGING */
#define DEVICE_CTX(dev) ((dev)->ctx)
-#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev))
-#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle))
+#define HANDLE_CTX(handle) ((handle) ? DEVICE_CTX((handle)->dev) : NULL)
#define ITRANSFER_CTX(itransfer) \
- (TRANSFER_CTX(USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)))
+ ((itransfer)->dev ? DEVICE_CTX((itransfer)->dev) : NULL)
+#define TRANSFER_CTX(transfer) \
+ (ITRANSFER_CTX(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)))
#define IS_EPIN(ep) (0 != ((ep) & LIBUSB_ENDPOINT_IN))
#define IS_EPOUT(ep) (!IS_EPIN(ep))
@@ -340,6 +369,9 @@ struct libusb_context {
libusb_hotplug_callback_handle next_hotplug_cb_handle;
usbi_mutex_t hotplug_cbs_lock;
+ /* A flag to indicate that the context is ready for hotplug notifications */
+ usbi_atomic_t hotplug_ready;
+
/* this is a list of in-flight transfer handles, sorted by timeout
* expiration. URBs to timeout the soonest are placed at the beginning of
* the list, URBs that will time out later are placed after, and urbs with
@@ -404,13 +436,26 @@ struct libusb_context {
};
extern struct libusb_context *usbi_default_context;
+extern struct libusb_context *usbi_fallback_context;
extern struct list_head active_contexts_list;
extern usbi_mutex_static_t active_contexts_lock;
static inline struct libusb_context *usbi_get_context(struct libusb_context *ctx)
{
- return ctx ? ctx : usbi_default_context;
+ static int warned = 0;
+
+ if (!ctx) {
+ ctx = usbi_default_context;
+ }
+ if (!ctx) {
+ ctx = usbi_fallback_context;
+ if (ctx && warned == 0) {
+ usbi_err(ctx, "API misuse! Using non-default context as implicit default.");
+ warned = 1;
+ }
+ }
+ return ctx;
}
enum usbi_event_flags {
@@ -450,10 +495,7 @@ static inline void usbi_end_event_handling(struct libusb_context *ctx)
}
struct libusb_device {
- /* lock protects refcnt, everything else is finalized at initialization
- * time */
- usbi_mutex_t lock;
- int refcnt;
+ usbi_atomic_t refcnt;
struct libusb_context *ctx;
struct libusb_device *parent_dev;
@@ -467,7 +509,7 @@ struct libusb_device {
unsigned long session_data;
struct libusb_device_descriptor device_descriptor;
- int attached;
+ usbi_atomic_t attached;
};
struct libusb_device_handle {
@@ -534,6 +576,10 @@ struct usbi_transfer {
uint32_t state_flags; /* Protected by usbi_transfer->lock */
uint32_t timeout_flags; /* Protected by the flying_stransfers_lock */
+ /* The device reference is held until destruction for logging
+ * even after dev_handle is set to NULL. */
+ struct libusb_device *dev;
+
/* this lock is held during libusb_submit_transfer() and
* libusb_cancel_transfer() (allowing the OS backend to prevent duplicate
* cancellation, submission-during-cancellation, etc). the OS backend
@@ -664,8 +710,75 @@ union usbi_bos_desc_buf {
uint16_t align; /* Force 2-byte alignment */
};
+enum usbi_hotplug_flags {
+ /* This callback is interested in device arrivals */
+ USBI_HOTPLUG_DEVICE_ARRIVED = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
+
+ /* This callback is interested in device removals */
+ USBI_HOTPLUG_DEVICE_LEFT = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
+
+ /* IMPORTANT: The values for the below entries must start *after*
+ * the highest value of the above entries!!!
+ */
+
+ /* The vendor_id field is valid for matching */
+ USBI_HOTPLUG_VENDOR_ID_VALID = (1U << 3),
+
+ /* The product_id field is valid for matching */
+ USBI_HOTPLUG_PRODUCT_ID_VALID = (1U << 4),
+
+ /* The dev_class field is valid for matching */
+ USBI_HOTPLUG_DEV_CLASS_VALID = (1U << 5),
+
+ /* This callback has been unregistered and needs to be freed */
+ USBI_HOTPLUG_NEEDS_FREE = (1U << 6),
+};
+
+struct usbi_hotplug_callback {
+ /* Flags that control how this callback behaves */
+ uint8_t flags;
+
+ /* Vendor ID to match (if flags says this is valid) */
+ uint16_t vendor_id;
+
+ /* Product ID to match (if flags says this is valid) */
+ uint16_t product_id;
+
+ /* Device class to match (if flags says this is valid) */
+ uint8_t dev_class;
+
+ /* Callback function to invoke for matching event/device */
+ libusb_hotplug_callback_fn cb;
+
+ /* Handle for this callback (used to match on deregister) */
+ libusb_hotplug_callback_handle handle;
+
+ /* User data that will be passed to the callback function */
+ void *user_data;
+
+ /* List this callback is registered in (ctx->hotplug_cbs) */
+ struct list_head list;
+};
+
+struct usbi_hotplug_message {
+ /* The hotplug event that occurred */
+ libusb_hotplug_event event;
+
+ /* The device for which this hotplug event occurred */
+ struct libusb_device *device;
+
+ /* List this message is contained in (ctx->hotplug_msgs) */
+ struct list_head list;
+};
+
/* shared data and functions */
+void usbi_hotplug_init(struct libusb_context *ctx);
+void usbi_hotplug_exit(struct libusb_context *ctx);
+void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
+ libusb_hotplug_event event);
+void usbi_hotplug_process(struct libusb_context *ctx, struct list_head *hotplug_msgs);
+
int usbi_io_init(struct libusb_context *ctx);
void usbi_io_exit(struct libusb_context *ctx);
@@ -696,6 +809,13 @@ int usbi_add_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle
short poll_events);
void usbi_remove_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle);
+struct usbi_option {
+ int is_set;
+ union {
+ int ival;
+ } arg;
+};
+
/* OS event abstraction */
int usbi_create_event(usbi_event_t *event);
@@ -793,7 +913,8 @@ struct usbi_os_backend {
* data structures for later, etc.
*
* This function is called when a libusb user initializes the library
- * prior to use.
+ * prior to use. Mutual exclusion with other init and exit calls is
+ * guaranteed when this function is called.
*
* Return 0 on success, or a LIBUSB_ERROR code on failure.
*/
@@ -803,6 +924,8 @@ struct usbi_os_backend {
* that was set up by init.
*
* This function is called when the user deinitializes the library.
+ * Mutual exclusion with other init and exit calls is guaranteed when
+ * this function is called.
*/
void (*exit)(struct libusb_context *ctx);
@@ -1365,6 +1488,12 @@ extern const struct usbi_os_backend usbi_backend;
#define for_each_removed_event_source_safe(ctx, e, n) \
for_each_safe_helper(e, n, &(ctx)->removed_event_sources, struct usbi_event_source)
+#define for_each_hotplug_cb(ctx, c) \
+ for_each_helper(c, &(ctx)->hotplug_cbs, struct usbi_hotplug_callback)
+
+#define for_each_hotplug_cb_safe(ctx, c, n) \
+ for_each_safe_helper(c, n, &(ctx)->hotplug_cbs, struct usbi_hotplug_callback)
+
#ifdef __cplusplus
}
#endif