Externals: Update libusb to 1.0.23-rc1

Now has support for isochronous transfers in the WinUSB backend,
which may or may not work better than the UsbDk backend.
This commit is contained in:
Léo Lam committed 2019-05-27 20:09:55 +02:00
1 parent 42de5b9a10
commit 1b9617c85c
163 files changed
+19633 -7732

No files matched your search

+9 -7
View File
@@ -13,10 +13,12 @@ DARWIN_USB_SRC = os/darwin_usb.h os/darwin_usb.c
OPENBSD_USB_SRC = os/openbsd_usb.c
NETBSD_USB_SRC = os/netbsd_usb.c
SUNOS_USB_SRC = os/sunos_usb.c os/sunos_usb.h
WINDOWS_COMMON_SRC = os/windows_nt_common.h os/windows_nt_common.c \
os/windows_common.h libusb-1.0.rc libusb-1.0.def
WINDOWS_USB_SRC = os/windows_winusb.h os/windows_winusb.c os/windows_usbdk.h \
os/windows_usbdk.c $(COMMON_WINDOWS_SRC)
WINDOWS_USB_SRC = libusb-1.0.def libusb-1.0.rc \
os/windows_common.h \
os/windows_nt_common.h os/windows_nt_common.c \
os/windows_nt_shared_types.h \
os/windows_usbdk.h os/windows_usbdk.c \
os/windows_winusb.h os/windows_winusb.c
WINCE_USB_SRC = os/wince_usb.h os/wince_usb.c
HAIKU_USB_SRC = os/haiku_usb.h os/haiku_usb_backend.cpp \
os/haiku_usb_raw.h os/haiku_usb_raw.cpp os/haiku_pollfs.cpp
@@ -25,8 +27,8 @@ EXTRA_DIST = $(POSIX_POLL_SRC) $(POSIX_THREADS_SRC) \
$(WINDOWS_POLL_SRC) $(WINDOWS_THREADS_SRC) \
$(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) \
$(OPENBSD_USB_SRC) $(NETBSD_USB_SRC) \
$(WINDOWS_COMMON_SRC) $(WINDOWS_USB_SRC) $(WINDOWS_USBDK_SRC) \
$(WINCE_USB_SRC) $(HAIKU_USB_SRC) \
$(WINDOWS_USB_SRC) $(WINCE_USB_SRC) \
$(HAIKU_USB_SRC) \
os/linux_udev.c os/linux_netlink.c
if OS_LINUX
@@ -63,7 +65,7 @@ libusb_1_0_la_LIBADD = libusb_haiku.la
endif
if OS_WINDOWS
OS_SRC = $(WINDOWS_USB_SRC) $(WINDOWS_COMMON_SRC)
OS_SRC = $(WINDOWS_USB_SRC)
.rc.lo:
$(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@
+432 -251
View File
File diff suppressed because it is too large. Load diff
+27 -25
View File
@@ -62,7 +62,7 @@ int usbi_parse_descriptor(const unsigned char *source, const char *descriptor,
if (host_endian) {
memcpy(dp, sp, 2);
} else {
w = (sp[1] << 8) | sp[0];
w = (uint16_t)((sp[1] << 8) | sp[0]);
*((uint16_t *)dp) = w;
}
sp += 2;
@@ -74,8 +74,8 @@ int usbi_parse_descriptor(const unsigned char *source, const char *descriptor,
if (host_endian) {
memcpy(dp, sp, 4);
} else {
d = (sp[3] << 24) | (sp[2] << 16) |
(sp[1] << 8) | sp[0];
d = (uint32_t)((sp[3] << 24) | (sp[2] << 16) |
(sp[1] << 8) | sp[0]);
*((uint32_t *)dp) = d;
}
sp += 4;
@@ -168,13 +168,13 @@ static int parse_endpoint(struct libusb_context *ctx,
/* Copy any unknown descriptors into a storage area for drivers */
/* to later parse */
len = (int)(buffer - begin);
if (!len) {
if (len <= 0) {
endpoint->extra = NULL;
endpoint->extra_length = 0;
return parsed;
}
extra = malloc(len);
extra = malloc((size_t)len);
endpoint->extra = extra;
if (!extra) {
endpoint->extra_length = 0;
@@ -230,7 +230,7 @@ static int parse_interface(libusb_context *ctx,
(struct libusb_interface_descriptor *) usb_interface->altsetting;
altsetting = usbi_reallocf(altsetting,
sizeof(struct libusb_interface_descriptor) *
(usb_interface->num_altsetting + 1));
((size_t)usb_interface->num_altsetting + 1));
if (!altsetting) {
r = LIBUSB_ERROR_NO_MEM;
goto err;
@@ -307,8 +307,8 @@ static int parse_interface(libusb_context *ctx,
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (len) {
ifp->extra = malloc(len);
if (len > 0) {
ifp->extra = malloc((size_t)len);
if (!ifp->extra) {
r = LIBUSB_ERROR_NO_MEM;
goto err;
@@ -333,7 +333,7 @@ static int parse_interface(libusb_context *ctx,
goto err;
if (r == 0) {
ifp->bNumEndpoints = (uint8_t)i;
break;;
break;
}
buffer += r;
@@ -453,10 +453,10 @@ static int parse_configuration(struct libusb_context *ctx,
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (len) {
if (len > 0) {
/* FIXME: We should realloc and append here */
if (!config->extra_length) {
config->extra = malloc(len);
config->extra = malloc((size_t)len);
if (!config->extra) {
r = LIBUSB_ERROR_NO_MEM;
goto err;
@@ -492,7 +492,7 @@ static int raw_desc_to_config(struct libusb_context *ctx,
{
struct libusb_config_descriptor *_config = malloc(sizeof(*_config));
int r;
if (!_config)
return LIBUSB_ERROR_NO_MEM;
@@ -504,7 +504,7 @@ static int raw_desc_to_config(struct libusb_context *ctx,
} else if (r > 0) {
usbi_warn(ctx, "still %d bytes of descriptor data left", r);
}
*config = _config;
return LIBUSB_SUCCESS;
}
@@ -513,7 +513,7 @@ int usbi_device_cache_descriptor(libusb_device *dev)
{
int r, host_endian = 0;
r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor,
r = usbi_backend.get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor,
&host_endian);
if (r < 0)
return r;
@@ -572,7 +572,7 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
int host_endian = 0;
int r;
r = usbi_backend->get_active_config_descriptor(dev, tmp,
r = usbi_backend.get_active_config_descriptor(dev, tmp,
LIBUSB_DT_CONFIG_SIZE, &host_endian);
if (r < 0)
return r;
@@ -587,7 +587,7 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
if (!buf)
return LIBUSB_ERROR_NO_MEM;
r = usbi_backend->get_active_config_descriptor(dev, buf,
r = usbi_backend.get_active_config_descriptor(dev, buf,
_config.wTotalLength, &host_endian);
if (r >= 0)
r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
@@ -625,7 +625,7 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
if (config_index >= dev->num_configurations)
return LIBUSB_ERROR_NOT_FOUND;
r = usbi_backend->get_config_descriptor(dev, config_index, tmp,
r = usbi_backend.get_config_descriptor(dev, config_index, tmp,
LIBUSB_DT_CONFIG_SIZE, &host_endian);
if (r < 0)
return r;
@@ -640,7 +640,7 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
if (!buf)
return LIBUSB_ERROR_NO_MEM;
r = usbi_backend->get_config_descriptor(dev, config_index, buf,
r = usbi_backend.get_config_descriptor(dev, config_index, buf,
_config.wTotalLength, &host_endian);
if (r >= 0)
r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
@@ -663,7 +663,7 @@ int usbi_get_config_index_by_value(struct libusb_device *dev,
for (i = 0; i < dev->num_configurations; i++) {
unsigned char tmp[6];
int host_endian;
int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp),
int r = usbi_backend.get_config_descriptor(dev, i, tmp, sizeof(tmp),
&host_endian);
if (r < 0) {
*idx = -1;
@@ -702,8 +702,8 @@ int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev,
int r, idx, host_endian;
unsigned char *buf = NULL;
if (usbi_backend->get_config_descriptor_by_value) {
r = usbi_backend->get_config_descriptor_by_value(dev,
if (usbi_backend.get_config_descriptor_by_value) {
r = usbi_backend.get_config_descriptor_by_value(dev,
bConfigurationValue, &buf, &host_endian);
if (r < 0)
return r;
@@ -1060,7 +1060,8 @@ int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor(
* It is safe to call this function with a NULL ss_usb_device_cap
* parameter, in which case the function simply returns.
*
* \param ss_usb_device_cap the USB 2.0 Extension descriptor to free
* \param ss_usb_device_cap the SuperSpeed USB Device Capability descriptor
* to free
*/
void API_EXPORTED libusb_free_ss_usb_device_capability_descriptor(
struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap)
@@ -1117,7 +1118,7 @@ int API_EXPORTED libusb_get_container_id_descriptor(struct libusb_context *ctx,
* It is safe to call this function with a NULL container_id parameter,
* in which case the function simply returns.
*
* \param container_id the USB 2.0 Extension descriptor to free
* \param container_id the Container ID descriptor to free
*/
void API_EXPORTED libusb_free_container_id_descriptor(
struct libusb_container_id_descriptor *container_id)
@@ -1163,7 +1164,7 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha
if (r < 4)
return LIBUSB_ERROR_IO;
langid = tbuf[2] | (tbuf[3] << 8);
langid = (uint16_t)(tbuf[2] | (tbuf[3] << 8));
r = libusb_get_string_descriptor(dev_handle, desc_index, langid, tbuf,
sizeof(tbuf));
@@ -1176,7 +1177,8 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha
if (tbuf[0] > r)
return LIBUSB_ERROR_IO;
for (di = 0, si = 2; si < tbuf[0]; si += 2) {
di = 0;
for (si = 2; si < tbuf[0]; si += 2) {
if (di >= (length - 1))
break;
+73 -50
View File
@@ -154,36 +154,30 @@ int main (void) {
\endcode
*/
static int usbi_hotplug_match_cb (struct libusb_context *ctx,
static int usbi_hotplug_match_cb(struct libusb_context *ctx,
struct libusb_device *dev, libusb_hotplug_event event,
struct libusb_hotplug_callback *hotplug_cb)
{
/* Handle lazy deregistration of callback */
if (hotplug_cb->needs_free) {
/* Free callback */
return 1;
}
if (!(hotplug_cb->events & event)) {
if (!(hotplug_cb->flags & event)) {
return 0;
}
if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->vendor_id &&
if ((hotplug_cb->flags & USBI_HOTPLUG_VENDOR_ID_VALID) &&
hotplug_cb->vendor_id != dev->device_descriptor.idVendor) {
return 0;
}
if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->product_id &&
if ((hotplug_cb->flags & USBI_HOTPLUG_PRODUCT_ID_VALID) &&
hotplug_cb->product_id != dev->device_descriptor.idProduct) {
return 0;
}
if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->dev_class &&
if ((hotplug_cb->flags & USBI_HOTPLUG_DEV_CLASS_VALID) &&
hotplug_cb->dev_class != dev->device_descriptor.bDeviceClass) {
return 0;
}
return hotplug_cb->cb (ctx, dev, event, hotplug_cb->user_data);
return hotplug_cb->cb(ctx, dev, event, hotplug_cb->user_data);
}
void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
@@ -195,8 +189,13 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) {
/* process deregistration in usbi_hotplug_deregister() */
continue;
}
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
ret = usbi_hotplug_match_cb (ctx, dev, event, hotplug_cb);
ret = usbi_hotplug_match_cb(ctx, dev, event, hotplug_cb);
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
if (ret) {
@@ -206,15 +205,13 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
}
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
/* the backend is expected to call the callback for each active transfer */
}
void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event)
{
int pending_events;
libusb_hotplug_message *message = calloc(1, sizeof(*message));
struct libusb_hotplug_message *message = calloc(1, sizeof(*message));
if (!message) {
usbi_err(ctx, "error allocating hotplug message");
@@ -240,59 +237,70 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
libusb_hotplug_callback_fn cb_fn, void *user_data,
libusb_hotplug_callback_handle *callback_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;
}
struct libusb_hotplug_callback *new_callback;
/* check for sane values */
if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
if ((!events || (~(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) & events)) ||
(flags && (~LIBUSB_HOTPLUG_ENUMERATE & flags)) ||
(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;
}
/* check for hotplug support */
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
return LIBUSB_ERROR_NOT_SUPPORTED;
}
USBI_GET_CONTEXT(ctx);
new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback));
new_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->flags = (uint8_t)events;
if (LIBUSB_HOTPLUG_MATCH_ANY != vendor_id) {
new_callback->flags |= USBI_HOTPLUG_VENDOR_ID_VALID;
new_callback->vendor_id = (uint16_t)vendor_id;
}
if (LIBUSB_HOTPLUG_MATCH_ANY != product_id) {
new_callback->flags |= USBI_HOTPLUG_PRODUCT_ID_VALID;
new_callback->product_id = (uint16_t)product_id;
}
if (LIBUSB_HOTPLUG_MATCH_ANY != dev_class) {
new_callback->flags |= USBI_HOTPLUG_DEV_CLASS_VALID;
new_callback->dev_class = (uint8_t)dev_class;
}
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++;
/* protect the handle by the context hotplug lock */
new_callback->handle = ctx->next_hotplug_cb_handle++;
/* handle the unlikely case of overflow */
if (ctx->next_hotplug_cb_handle < 0)
ctx->next_hotplug_cb_handle = 1;
list_add(&new_callback->list, &ctx->hotplug_cbs);
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
usbi_dbg("new hotplug cb %p with handle %d", new_callback, new_callback->handle);
if (flags & LIBUSB_HOTPLUG_ENUMERATE) {
int i, len;
if ((flags & LIBUSB_HOTPLUG_ENUMERATE) && (events & LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)) {
ssize_t i, len;
struct libusb_device **devs;
len = (int) libusb_get_device_list(ctx, &devs);
len = libusb_get_device_list(ctx, &devs);
if (len < 0) {
libusb_hotplug_deregister_callback(ctx,
new_callback->handle);
return len;
return (int)len;
}
for (i = 0; i < len; i++) {
@@ -311,10 +319,11 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
return LIBUSB_SUCCESS;
}
void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx,
void API_EXPORTED libusb_hotplug_deregister_callback(struct libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle)
{
struct libusb_hotplug_callback *hotplug_cb;
int deregistered = 0;
/* check for hotplug support */
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
@@ -323,28 +332,42 @@ void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx
USBI_GET_CONTEXT(ctx);
usbi_dbg("deregister hotplug cb %d", callback_handle);
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list,
struct libusb_hotplug_callback) {
list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
if (callback_handle == hotplug_cb->handle) {
/* Mark this callback for deregistration */
hotplug_cb->needs_free = 1;
hotplug_cb->flags |= USBI_HOTPLUG_NEEDS_FREE;
deregistered = 1;
}
}
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
usbi_hotplug_notification(ctx, NULL, 0);
if (deregistered) {
int pending_events;
usbi_mutex_lock(&ctx->event_data_lock);
pending_events = usbi_pending_events(ctx);
ctx->event_flags |= USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
if (!pending_events)
usbi_signal_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
}
}
void usbi_hotplug_deregister_all(struct libusb_context *ctx) {
void usbi_hotplug_deregister(struct libusb_context *ctx, int forced)
{
struct libusb_hotplug_callback *hotplug_cb, *next;
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list,
struct libusb_hotplug_callback) {
list_del(&hotplug_cb->list);
free(hotplug_cb);
list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
if (forced || (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE)) {
usbi_dbg("freeing hotplug cb %p with handle %d", hotplug_cb,
hotplug_cb->handle);
list_del(&hotplug_cb->list);
free(hotplug_cb);
}
}
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
}
+34 -25
View File
@@ -19,12 +19,34 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(USBI_HOTPLUG_H)
#ifndef USBI_HOTPLUG_H
#define USBI_HOTPLUG_H
#ifndef LIBUSBI_H
#include "libusbi.h"
#endif
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),
};
/** \ingroup hotplug
* The hotplug callback structure. The user populates this structure with
@@ -32,23 +54,17 @@
* to receive notification of hotplug events.
*/
struct libusb_hotplug_callback {
/** Context this callback is associated with */
struct libusb_context *ctx;
/** Flags that control how this callback behaves */
uint8_t flags;
/** Vendor ID to match or LIBUSB_HOTPLUG_MATCH_ANY */
int vendor_id;
/** Vendor ID to match (if flags says this is valid) */
uint16_t vendor_id;
/** Product ID to match or LIBUSB_HOTPLUG_MATCH_ANY */
int product_id;
/** Product ID to match (if flags says this is valid) */
uint16_t product_id;
/** Device class to match or LIBUSB_HOTPLUG_MATCH_ANY */
int dev_class;
/** Hotplug callback flags */
libusb_hotplug_flag flags;
/** Event(s) that will trigger this callback */
libusb_hotplug_event events;
/** 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;
@@ -59,15 +75,10 @@ struct libusb_hotplug_callback {
/** User data that will be passed to the callback function */
void *user_data;
/** Callback is marked for deletion */
int needs_free;
/** List this callback is registered in (ctx->hotplug_cbs) */
struct list_head list;
};
typedef struct libusb_hotplug_callback libusb_hotplug_callback;
struct libusb_hotplug_message {
/** The hotplug event that occurred */
libusb_hotplug_event event;
@@ -79,9 +90,7 @@ struct libusb_hotplug_message {
struct list_head list;
};
typedef struct libusb_hotplug_message libusb_hotplug_message;
void usbi_hotplug_deregister_all(struct libusb_context *ctx);
void usbi_hotplug_deregister(struct libusb_context *ctx, int forced);
void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event);
void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
+83 -67
View File
@@ -27,9 +27,6 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
@@ -1147,8 +1144,8 @@ int usbi_io_init(struct libusb_context *ctx)
goto err_close_pipe;
#ifdef USBI_TIMERFD_AVAILABLE
ctx->timerfd = timerfd_create(usbi_backend->get_timerfd_clockid(),
TFD_NONBLOCK);
ctx->timerfd = timerfd_create(usbi_backend.get_timerfd_clockid(),
TFD_NONBLOCK | TFD_CLOEXEC);
if (ctx->timerfd >= 0) {
usbi_dbg("using timerfd for timeouts");
r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN);
@@ -1197,8 +1194,7 @@ void usbi_io_exit(struct libusb_context *ctx)
usbi_cond_destroy(&ctx->event_waiters_cond);
usbi_mutex_destroy(&ctx->event_data_lock);
usbi_tls_key_delete(ctx->event_handling_key);
if (ctx->pollfds)
free(ctx->pollfds);
free(ctx->pollfds);
}
static int calculate_timeout(struct usbi_transfer *transfer)
@@ -1208,10 +1204,12 @@ static int calculate_timeout(struct usbi_transfer *transfer)
unsigned int timeout =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout;
if (!timeout)
if (!timeout) {
timerclear(&transfer->timeout);
return 0;
}
r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &current_time);
r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &current_time);
if (r < 0) {
usbi_err(ITRANSFER_CTX(transfer),
"failed to read monotonic clock, errno=%d", errno);
@@ -1250,7 +1248,7 @@ static int calculate_timeout(struct usbi_transfer *transfer)
* use it on a non-isochronous endpoint. If you do this, ensure that at time
* of submission, num_iso_packets is 0 and that type is set appropriately.
*
* \param iso_packets number of isochronous packet descriptors to allocate
* \param iso_packets number of isochronous packet descriptors to allocate. Must be non-negative.
* \returns a newly allocated transfer, or NULL on error
*/
DEFAULT_VISIBILITY
@@ -1258,12 +1256,18 @@ struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(
int iso_packets)
{
struct libusb_transfer *transfer;
size_t os_alloc_size = usbi_backend->transfer_priv_size;
size_t alloc_size = sizeof(struct usbi_transfer)
size_t os_alloc_size;
size_t alloc_size;
struct usbi_transfer *itransfer;
assert(iso_packets >= 0);
os_alloc_size = usbi_backend.transfer_priv_size;
alloc_size = sizeof(struct usbi_transfer)
+ sizeof(struct libusb_transfer)
+ (sizeof(struct libusb_iso_packet_descriptor) * iso_packets)
+ (sizeof(struct libusb_iso_packet_descriptor) * (size_t)iso_packets)
+ os_alloc_size;
struct usbi_transfer *itransfer = calloc(1, alloc_size);
itransfer = calloc(1, alloc_size);
if (!itransfer)
return NULL;
@@ -1298,7 +1302,7 @@ void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer)
return;
usbi_dbg("transfer %p", transfer);
if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER && transfer->buffer)
if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
free(transfer->buffer);
itransfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
@@ -1529,7 +1533,7 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer)
*/
usbi_mutex_unlock(&ctx->flying_transfers_lock);
r = usbi_backend->submit_transfer(itransfer);
r = usbi_backend.submit_transfer(itransfer);
if (r == LIBUSB_SUCCESS) {
itransfer->state_flags |= USBI_TRANSFER_IN_FLIGHT;
/* keep a reference to this device */
@@ -1570,7 +1574,7 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer)
r = LIBUSB_ERROR_NOT_FOUND;
goto out;
}
r = usbi_backend->cancel_transfer(itransfer);
r = usbi_backend.cancel_transfer(itransfer);
if (r < 0) {
if (r != LIBUSB_ERROR_NOT_FOUND &&
r != LIBUSB_ERROR_NO_DEVICE)
@@ -1707,15 +1711,19 @@ int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer)
* function will be called the next time an event handler runs. */
void usbi_signal_transfer_completion(struct usbi_transfer *transfer)
{
struct libusb_context *ctx = ITRANSFER_CTX(transfer);
int pending_events;
libusb_device_handle *dev_handle = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->dev_handle;
usbi_mutex_lock(&ctx->event_data_lock);
pending_events = usbi_pending_events(ctx);
list_add_tail(&transfer->completed_list, &ctx->completed_transfers);
if (!pending_events)
usbi_signal_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
if (dev_handle) {
struct libusb_context *ctx = HANDLE_CTX(dev_handle);
int pending_events;
usbi_mutex_lock(&ctx->event_data_lock);
pending_events = usbi_pending_events(ctx);
list_add_tail(&transfer->completed_list, &ctx->completed_transfers);
if (!pending_events)
usbi_signal_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
}
}
/** \ingroup libusb_poll
@@ -1887,14 +1895,17 @@ int API_EXPORTED libusb_event_handler_active(libusb_context *ctx)
*/
void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx)
{
int pending_events;
USBI_GET_CONTEXT(ctx);
usbi_dbg("");
usbi_mutex_lock(&ctx->event_data_lock);
if (!usbi_pending_events(ctx)) {
ctx->event_flags |= USBI_EVENT_USER_INTERRUPT;
pending_events = usbi_pending_events(ctx);
ctx->event_flags |= USBI_EVENT_USER_INTERRUPT;
if (!pending_events)
usbi_signal_event(ctx);
}
usbi_mutex_unlock(&ctx->event_data_lock);
}
@@ -2004,7 +2015,7 @@ static int handle_timeouts_locked(struct libusb_context *ctx)
return 0;
/* get current time */
r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts);
r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts);
if (r < 0)
return r;
@@ -2077,13 +2088,19 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
struct pollfd *fds = NULL;
int i = -1;
int timeout_ms;
int special_event;
/* prevent attempts to recursively handle events (e.g. calling into
* libusb_handle_events() from within a hotplug or transfer callback) */
usbi_mutex_lock(&ctx->event_data_lock);
r = 0;
if (usbi_handling_events(ctx))
return LIBUSB_ERROR_BUSY;
usbi_start_event_handling(ctx);
r = LIBUSB_ERROR_BUSY;
else
usbi_start_event_handling(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
if (r)
return r;
/* there are certain fds that libusb uses internally, currently:
*
@@ -2105,10 +2122,8 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED) {
usbi_dbg("poll fds modified, reallocating");
if (ctx->pollfds) {
free(ctx->pollfds);
ctx->pollfds = NULL;
}
free(ctx->pollfds);
ctx->pollfds = NULL;
/* sanity check - it is invalid for a context to have fewer than the
* required internal fds (memory corruption?) */
@@ -2138,6 +2153,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
}
fds = ctx->pollfds;
nfds = ctx->pollfds_cnt;
usbi_inc_fds_ref(fds, nfds);
usbi_mutex_unlock(&ctx->event_data_lock);
timeout_ms = (int)(tv->tv_sec * 1000) + (tv->tv_usec / 1000);
@@ -2146,32 +2162,30 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
if (tv->tv_usec % 1000)
timeout_ms++;
redo_poll:
usbi_dbg("poll() %d fds with timeout in %dms", nfds, timeout_ms);
r = usbi_poll(fds, nfds, timeout_ms);
usbi_dbg("poll() returned %d", r);
if (r == 0) {
r = handle_timeouts(ctx);
goto done;
}
else if (r == -1 && errno == EINTR) {
} else if (r == -1 && errno == EINTR) {
r = LIBUSB_ERROR_INTERRUPTED;
goto done;
}
else if (r < 0) {
} else if (r < 0) {
usbi_err(ctx, "poll failed %d err=%d", r, errno);
r = LIBUSB_ERROR_IO;
goto done;
}
special_event = 0;
/* fds[0] is always the event pipe */
if (fds[0].revents) {
libusb_hotplug_message *message = NULL;
struct list_head hotplug_msgs;
struct usbi_transfer *itransfer;
int hotplug_cb_deregistered = 0;
int ret = 0;
list_init(&hotplug_msgs);
usbi_dbg("caught a fish on the event pipe");
/* take the the event data lock while processing events */
@@ -2186,6 +2200,12 @@ redo_poll:
ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT;
}
if (ctx->event_flags & USBI_EVENT_HOTPLUG_CB_DEREGISTERED) {
usbi_dbg("someone unregistered a hotplug cb");
ctx->event_flags &= ~USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
hotplug_cb_deregistered = 1;
}
/* check if someone is closing a device */
if (ctx->device_close)
usbi_dbg("someone is closing a device");
@@ -2193,9 +2213,7 @@ redo_poll:
/* check for any pending hotplug messages */
if (!list_empty(&ctx->hotplug_msgs)) {
usbi_dbg("hotplug message received");
special_event = 1;
message = list_first_entry(&ctx->hotplug_msgs, libusb_hotplug_message, list);
list_del(&message->list);
list_cut(&hotplug_msgs, &ctx->hotplug_msgs);
}
/* complete any pending transfers */
@@ -2203,7 +2221,7 @@ redo_poll:
itransfer = list_first_entry(&ctx->completed_transfers, struct usbi_transfer, completed_list);
list_del(&itransfer->completed_list);
usbi_mutex_unlock(&ctx->event_data_lock);
ret = usbi_backend->handle_transfer_completion(itransfer);
ret = usbi_backend.handle_transfer_completion(itransfer);
if (ret)
usbi_err(ctx, "backend handle_transfer_completion failed with error %d", ret);
usbi_mutex_lock(&ctx->event_data_lock);
@@ -2215,14 +2233,21 @@ redo_poll:
usbi_mutex_unlock(&ctx->event_data_lock);
/* process the hotplug message, if any */
if (message) {
if (hotplug_cb_deregistered)
usbi_hotplug_deregister(ctx, 0);
/* process the hotplug messages, if any */
while (!list_empty(&hotplug_msgs)) {
struct libusb_hotplug_message *message =
list_first_entry(&hotplug_msgs, struct libusb_hotplug_message, list);
usbi_hotplug_match(ctx, message->device, message->event);
/* the device left, dereference the device */
if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message->event)
libusb_unref_device(message->device);
list_del(&message->list);
free(message);
}
@@ -2233,7 +2258,7 @@ redo_poll:
}
if (0 == --r)
goto handled;
goto done;
}
#ifdef USBI_TIMERFD_AVAILABLE
@@ -2242,7 +2267,6 @@ redo_poll:
/* timerfd indicates that a timeout has expired */
int ret;
usbi_dbg("timerfd triggered");
special_event = 1;
ret = handle_timerfd_trigger(ctx);
if (ret < 0) {
@@ -2252,22 +2276,17 @@ redo_poll:
}
if (0 == --r)
goto handled;
goto done;
}
#endif
r = usbi_backend->handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r);
r = usbi_backend.handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r);
if (r)
usbi_err(ctx, "backend handle_events failed with error %d", r);
handled:
if (r == 0 && special_event) {
timeout_ms = 0;
goto redo_poll;
}
done:
usbi_end_event_handling(ctx);
usbi_dec_fds_ref(fds, nfds);
return r;
}
@@ -2583,7 +2602,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
return 0;
}
r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &cur_ts);
r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &cur_ts);
if (r < 0) {
usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno);
return 0;
@@ -2595,7 +2614,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
timerclear(tv);
} else {
timersub(&next_timeout, &cur_tv, tv);
usbi_dbg("next timeout in %d.%06ds", tv->tv_sec, tv->tv_usec);
usbi_dbg("next timeout in %ld.%06lds", (long)tv->tv_sec, (long)tv->tv_usec);
}
return 1;
@@ -2752,15 +2771,12 @@ out:
* Since version 1.0.20, \ref LIBUSB_API_VERSION >= 0x01000104
*
* It is legal to call this function with a NULL pollfd list. In this case,
* the function will simply return safely.
* the function will simply do nothing.
*
* \param pollfds the list of libusb_pollfd structures to free
*/
void API_EXPORTED libusb_free_pollfds(const struct libusb_pollfd **pollfds)
{
if (!pollfds)
return;
free((void *)pollfds);
}
@@ -2811,7 +2827,7 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle)
USBI_TRANSFER_TO_LIBUSB_TRANSFER(to_cancel));
usbi_mutex_lock(&to_cancel->lock);
usbi_backend->clear_transfer_priv(to_cancel);
usbi_backend.clear_transfer_priv(to_cancel);
usbi_mutex_unlock(&to_cancel->lock);
usbi_handle_transfer_completion(to_cancel, LIBUSB_TRANSFER_NO_DEVICE);
}
+10 -6
View File
@@ -126,10 +126,10 @@ EXPORTS
libusb_interrupt_transfer@24 = libusb_interrupt_transfer
libusb_kernel_driver_active
libusb_kernel_driver_active@8 = libusb_kernel_driver_active
libusb_lock_events
libusb_lock_events@4 = libusb_lock_events
libusb_lock_event_waiters
libusb_lock_event_waiters@4 = libusb_lock_event_waiters
libusb_lock_events
libusb_lock_events@4 = libusb_lock_events
libusb_open
libusb_open@8 = libusb_open
libusb_open_device_with_vid_pid
@@ -148,12 +148,16 @@ EXPORTS
libusb_set_configuration@8 = libusb_set_configuration
libusb_set_debug
libusb_set_debug@8 = libusb_set_debug
libusb_set_log_cb
libusb_set_log_cb@12 = libusb_set_log_cb
libusb_set_interface_alt_setting
libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting
libusb_setlocale
libusb_setlocale@4 = libusb_setlocale
libusb_set_option
_libusb_set_option = libusb_set_option
libusb_set_pollfd_notifiers
libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers
libusb_setlocale
libusb_setlocale@4 = libusb_setlocale
libusb_strerror
libusb_strerror@4 = libusb_strerror
libusb_submit_transfer
@@ -164,10 +168,10 @@ EXPORTS
libusb_transfer_set_stream_id@8 = libusb_transfer_set_stream_id
libusb_try_lock_events
libusb_try_lock_events@4 = libusb_try_lock_events
libusb_unlock_events
libusb_unlock_events@4 = libusb_unlock_events
libusb_unlock_event_waiters
libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters
libusb_unlock_events
libusb_unlock_events@4 = libusb_unlock_events
libusb_unref_device
libusb_unref_device@4 = libusb_unref_device
libusb_wait_for_event
+106 -48
View File
@@ -3,7 +3,7 @@
* Copyright © 2001 Johannes Erdfelt <[email protected]>
* Copyright © 2007-2008 Daniel Drake <[email protected]>
* Copyright © 2012 Pete Batard <[email protected]>
* Copyright © 2012 Nathan Hjelm <[email protected]>
* Copyright © 2012-2018 Nathan Hjelm <[email protected]>
* For more information, please visit: http://libusb.info
*
* This library is free software; you can redistribute it and/or
@@ -54,13 +54,19 @@ typedef unsigned __int32 uint32_t;
#include <sys/types.h>
#endif
#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
#if defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
#include <sys/time.h>
#endif
#include <time.h>
#include <limits.h>
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
#define ZERO_SIZED_ARRAY /* [] - valid C99 code */
#else
#define ZERO_SIZED_ARRAY 0 /* [0] - non-standard, but usually working code */
#endif
/* 'interface' might be defined as a macro on Windows, so we need to
* undefine it so as not to break the current libusb API, because
* libusb_config_descriptor has an 'interface' member
@@ -79,6 +85,8 @@ typedef unsigned __int32 uint32_t;
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
#define LIBUSB_DEPRECATED_FOR(f) \
__attribute__((deprecated("Use " #f " instead")))
#elif __GNUC__ >= 3
#define LIBUSB_DEPRECATED_FOR(f) __attribute__((deprecated))
#else
#define LIBUSB_DEPRECATED_FOR(f)
#endif /* __GNUC__ */
@@ -141,7 +149,7 @@ typedef unsigned __int32 uint32_t;
* Internally, LIBUSB_API_VERSION is defined as follows:
* (libusb major << 24) | (libusb minor << 16) | (16 bit incremental)
*/
#define LIBUSB_API_VERSION 0x01000105
#define LIBUSB_API_VERSION 0x01000107
/* The following is kept for compatibility, but will be deprecated in the future */
#define LIBUSBX_API_VERSION LIBUSB_API_VERSION
@@ -569,7 +577,7 @@ struct libusb_endpoint_descriptor {
* it will store them here, should you wish to parse them. */
const unsigned char *extra;
/** Length of the extra descriptors, in bytes. */
/** Length of the extra descriptors, in bytes. Must be non-negative. */
int extra_length;
};
@@ -619,7 +627,7 @@ struct libusb_interface_descriptor {
* it will store them here, should you wish to parse them. */
const unsigned char *extra;
/** Length of the extra descriptors, in bytes. */
/** Length of the extra descriptors, in bytes. Must be non-negative. */
int extra_length;
};
@@ -631,7 +639,8 @@ struct libusb_interface {
* by the num_altsetting field. */
const struct libusb_interface_descriptor *altsetting;
/** The number of alternate settings that belong to this interface */
/** The number of alternate settings that belong to this interface.
* Must be non-negative. */
int num_altsetting;
};
@@ -678,7 +687,7 @@ struct libusb_config_descriptor {
* descriptors, it will store them here, should you wish to parse them. */
const unsigned char *extra;
/** Length of the extra descriptors, in bytes. */
/** Length of the extra descriptors, in bytes. Must be non-negative. */
int extra_length;
};
@@ -729,13 +738,7 @@ struct libusb_bos_dev_capability_descriptor {
/** Device Capability type */
uint8_t bDevCapabilityType;
/** Device Capability data (bLength - 3 bytes) */
uint8_t dev_capability_data
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
#else
[0] /* non-standard, but usually working code */
#endif
;
uint8_t dev_capability_data[ZERO_SIZED_ARRAY];
};
/** \ingroup libusb_desc
@@ -760,13 +763,7 @@ struct libusb_bos_descriptor {
uint8_t bNumDeviceCaps;
/** bNumDeviceCap Device Capability Descriptors */
struct libusb_bos_dev_capability_descriptor *dev_capability
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
#else
[0] /* non-standard, but usually working code */
#endif
;
struct libusb_bos_dev_capability_descriptor *dev_capability[ZERO_SIZED_ARRAY];
};
/** \ingroup libusb_desc
@@ -927,7 +924,7 @@ struct libusb_version {
* sessions allows for your program to use two libraries (or dynamically
* load two modules) which both independently use libusb. This will prevent
* interference between the individual libusb users - for example
* libusb_set_debug() will not affect the other user of the library, and
* libusb_set_option() will not affect the other user of the library, and
* libusb_exit() will not destroy resources that the other user is still
* using.
*
@@ -987,6 +984,9 @@ enum libusb_speed {
/** The device is operating at super speed (5000MBit/s). */
LIBUSB_SPEED_SUPER = 4,
/** The device is operating at super speed plus (10000MBit/s). */
LIBUSB_SPEED_SUPER_PLUS = 5,
};
/** \ingroup libusb_dev
@@ -1135,19 +1135,19 @@ enum libusb_transfer_status {
* libusb_transfer.flags values */
enum libusb_transfer_flags {
/** Report short frames as errors */
LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0,
LIBUSB_TRANSFER_SHORT_NOT_OK = 1U << 0,
/** Automatically free() transfer buffer during libusb_free_transfer().
* Note that buffers allocated with libusb_dev_mem_alloc() should not
* be attempted freed in this way, since free() is not an appropriate
* way to release such memory. */
LIBUSB_TRANSFER_FREE_BUFFER = 1<<1,
LIBUSB_TRANSFER_FREE_BUFFER = 1U << 1,
/** Automatically call libusb_free_transfer() after callback returns.
* If this flag is set, it is illegal to call libusb_free_transfer()
* from your transfer callback, as this will result in a double-free
* when this flag is acted upon. */
LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2,
LIBUSB_TRANSFER_FREE_TRANSFER = 1U << 2,
/** Terminate transfers that are a multiple of the endpoint's
* wMaxPacketSize with an extra zero length packet. This is useful
@@ -1172,7 +1172,7 @@ enum libusb_transfer_flags {
*
* Available since libusb-1.0.9.
*/
LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3,
LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1U << 3,
};
/** \ingroup libusb_asyncio
@@ -1220,7 +1220,7 @@ struct libusb_transfer {
/** Type of the endpoint from \ref libusb_transfer_type */
unsigned char type;
/** Timeout for this transfer in millseconds. A value of 0 indicates no
/** Timeout for this transfer in milliseconds. A value of 0 indicates no
* timeout. */
unsigned int timeout;
@@ -1233,7 +1233,7 @@ struct libusb_transfer {
* to determine if errors occurred. */
enum libusb_transfer_status status;
/** Length of the data buffer */
/** Length of the data buffer. Must be non-negative. */
int length;
/** Actual length of data that was transferred. Read-only, and only for
@@ -1252,17 +1252,11 @@ struct libusb_transfer {
unsigned char *buffer;
/** Number of isochronous packets. Only used for I/O with isochronous
* endpoints. */
* endpoints. Must be non-negative. */
int num_iso_packets;
/** Isochronous packet descriptors, for isochronous transfers only. */
struct libusb_iso_packet_descriptor iso_packet_desc
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
#else
[0] /* non-standard, but usually working code */
#endif
;
struct libusb_iso_packet_descriptor iso_packet_desc[ZERO_SIZED_ARRAY];
};
/** \ingroup libusb_misc
@@ -1290,22 +1284,46 @@ enum libusb_capability {
* - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default)
* - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr
* - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr
* - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout, warning
* and error messages are printed to stderr
* - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout,
* warnings and errors to stderr
* - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stderr
* - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stderr
*/
enum libusb_log_level {
LIBUSB_LOG_LEVEL_NONE = 0,
LIBUSB_LOG_LEVEL_ERROR,
LIBUSB_LOG_LEVEL_WARNING,
LIBUSB_LOG_LEVEL_INFO,
LIBUSB_LOG_LEVEL_DEBUG,
LIBUSB_LOG_LEVEL_ERROR = 1,
LIBUSB_LOG_LEVEL_WARNING = 2,
LIBUSB_LOG_LEVEL_INFO = 3,
LIBUSB_LOG_LEVEL_DEBUG = 4,
};
/** \ingroup libusb_lib
* Log callback mode.
* \see libusb_set_log_cb()
*/
enum libusb_log_cb_mode {
/** Callback function handling all log mesages. */
LIBUSB_LOG_CB_GLOBAL = 1 << 0,
/** Callback function handling context related log mesages. */
LIBUSB_LOG_CB_CONTEXT = 1 << 1
};
/** \ingroup libusb_lib
* Callback function for handling log messages.
* \param ctx the context which is related to the log message, or NULL if it
* is a global log message
* \param level the log level, see \ref libusb_log_level for a description
* \param str the log message
* \see libusb_set_log_cb()
*/
typedef void (LIBUSB_CALL *libusb_log_cb)(libusb_context *ctx,
enum libusb_log_level level, const char *str);
int LIBUSB_CALL libusb_init(libusb_context **ctx);
void LIBUSB_CALL libusb_exit(libusb_context *ctx);
LIBUSB_DEPRECATED_FOR(libusb_set_option)
void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level);
void LIBUSB_CALL libusb_set_log_cb(libusb_context *ctx, libusb_log_cb cb, int mode);
const struct libusb_version * LIBUSB_CALL libusb_get_version(void);
int LIBUSB_CALL libusb_has_capability(uint32_t capability);
const char * LIBUSB_CALL libusb_error_name(int errcode);
@@ -1370,6 +1388,7 @@ int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev,
int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev,
unsigned char endpoint);
int LIBUSB_CALL libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, libusb_device_handle **dev_handle);
int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **dev_handle);
void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle);
libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle);
@@ -1892,10 +1911,10 @@ typedef int libusb_hotplug_callback_handle;
* Flags for hotplug events */
typedef enum {
/** Default value when not using any flags. */
LIBUSB_HOTPLUG_NO_FLAGS = 0,
LIBUSB_HOTPLUG_NO_FLAGS = 0U,
/** Arm the callback and fire it for all matching currently attached devices. */
LIBUSB_HOTPLUG_ENUMERATE = 1<<0,
LIBUSB_HOTPLUG_ENUMERATE = 1U << 0,
} libusb_hotplug_flag;
/** \ingroup libusb_hotplug
@@ -1905,12 +1924,12 @@ typedef enum {
* Hotplug events */
typedef enum {
/** A device has been plugged in and is ready to use */
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01,
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01U,
/** A device has left and is no longer available.
* It is the user's responsibility to call libusb_close on any handle associated with a disconnected device.
* It is safe to call libusb_get_device_descriptor on a device that has left */
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02,
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02U,
} libusb_hotplug_event;
/** \ingroup libusb_hotplug
@@ -2001,6 +2020,45 @@ int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx,
void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle);
/** \ingroup libusb_lib
* Available option values for libusb_set_option().
*/
enum libusb_option {
/** Set the log message verbosity.
*
* The default level is LIBUSB_LOG_LEVEL_NONE, which means no messages are ever
* printed. If you choose to increase the message verbosity level, ensure
* that your application does not close the stderr file descriptor.
*
* You are advised to use level LIBUSB_LOG_LEVEL_WARNING. libusb is conservative
* with its message logging and most of the time, will only log messages that
* explain error conditions and other oddities. This will help you debug
* your software.
*
* If the LIBUSB_DEBUG environment variable was set when libusb was
* initialized, this function does nothing: the message verbosity is fixed
* to the value in the environment variable.
*
* If libusb was compiled without any message logging, this function does
* nothing: you'll never get any messages.
*
* If libusb was compiled with verbose debug message logging, this function
* does nothing: you'll always get messages from all levels.
*/
LIBUSB_OPTION_LOG_LEVEL,
/** Use the UsbDk backend for a specific context, if available.
*
* This option should be set immediately after calling libusb_init(), otherwise
* unspecified behavior may occur.
*
* Only valid on Windows.
*/
LIBUSB_OPTION_USE_USBDK,
};
int LIBUSB_CALL libusb_set_option(libusb_context *ctx, enum libusb_option option, ...);
#ifdef __cplusplus
}
#endif
+141 -94
View File
@@ -24,7 +24,7 @@
#include <config.h>
#include <stdlib.h>
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
@@ -39,6 +39,20 @@
#include "libusb.h"
#include "version.h"
/* Attribute to ensure that a structure member is aligned to a natural
* pointer alignment. Used for os_priv member. */
#if defined(_MSC_VER)
#if defined(_WIN64)
#define PTR_ALIGNED __declspec(align(8))
#else
#define PTR_ALIGNED __declspec(align(4))
#endif
#elif defined(__GNUC__)
#define PTR_ALIGNED __attribute__((aligned(sizeof(void *))))
#else
#define PTR_ALIGNED
#endif
/* Inside the libusb code, mark all public functions as follows:
* return_type API_EXPORTED function_name(params) { ... }
* But if the function returns a pointer, mark it as follows:
@@ -48,6 +62,16 @@
*/
#define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY
/* Macro to decorate printf-like functions, in order to get
* compiler warnings about format string mistakes.
*/
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
#define USBI_PRINTFLIKE(formatarg, firstvararg) \
__attribute__((__format__ (__printf__, formatarg, firstvararg)))
#else
#define USBI_PRINTFLIKE(formatarg, firstvararg)
#endif
#ifdef __cplusplus
extern "C" {
#endif
@@ -139,6 +163,19 @@ static inline void list_del(struct list_head *entry)
entry->next = entry->prev = NULL;
}
static inline void list_cut(struct list_head *list, struct list_head *head)
{
if (list_empty(head))
return;
list->next = head->next;
list->next->prev = list;
list->prev = head->prev;
list->prev->next = list;
list_init(head);
}
static inline void *usbi_reallocf(void *ptr, size_t size)
{
void *ret = realloc(ptr, size);
@@ -151,6 +188,9 @@ static inline void *usbi_reallocf(void *ptr, size_t size)
const typeof( ((type *)0)->member ) *mptr = (ptr); \
(type *)( (char *)mptr - offsetof(type,member) );})
#ifndef CLAMP
#define CLAMP(val, min, max) ((val) < (min) ? (min) : ((val) > (max) ? (max) : (val)))
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
@@ -175,29 +215,33 @@ static inline void *usbi_reallocf(void *ptr, size_t size)
} while (0)
#endif
#ifdef ENABLE_LOGGING
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define snprintf usbi_snprintf
#define vsnprintf usbi_vsnprintf
int usbi_snprintf(char *dst, size_t size, const char *format, ...);
int usbi_vsnprintf(char *dst, size_t size, const char *format, va_list ap);
#define LIBUSB_PRINTF_WIN32
#endif /* defined(_MSC_VER) && (_MSC_VER < 1900) */
void usbi_log(struct libusb_context *ctx, enum libusb_log_level level,
const char *function, const char *format, ...);
const char *function, const char *format, ...) USBI_PRINTFLIKE(4, 5);
void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
const char *function, const char *format, va_list args);
const char *function, const char *format, va_list args) USBI_PRINTFLIKE(4, 0);
#if !defined(_MSC_VER) || _MSC_VER >= 1400
#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
#ifdef ENABLE_LOGGING
#define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__)
#define usbi_dbg(...) _usbi_log(NULL, LIBUSB_LOG_LEVEL_DEBUG, __VA_ARGS__)
#else
#define _usbi_log(ctx, level, ...) do { (void)(ctx); } while(0)
#define usbi_dbg(...) do {} while(0)
#endif
#define usbi_info(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_INFO, __VA_ARGS__)
#define usbi_warn(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_WARNING, __VA_ARGS__)
#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__)
#else /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
#else /* !defined(_MSC_VER) || (_MSC_VER >= 1400) */
#ifdef ENABLE_LOGGING
#define LOG_BODY(ctxt, level) \
{ \
va_list args; \
@@ -205,24 +249,26 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
usbi_log_v(ctxt, level, "", format, args); \
va_end(args); \
}
#else
#define LOG_BODY(ctxt, level) \
{ \
(void)(ctxt); \
}
#endif
static inline void usbi_info(struct libusb_context *ctx, const char *format, ...)
LOG_BODY(ctx, LIBUSB_LOG_LEVEL_INFO)
static inline void usbi_warn(struct libusb_context *ctx, const char *format, ...)
LOG_BODY(ctx, LIBUSB_LOG_LEVEL_WARNING)
static inline void usbi_err(struct libusb_context *ctx, const char *format, ...)
LOG_BODY(ctx, LIBUSB_LOG_LEVEL_ERROR)
static inline void usbi_warn(struct libusb_context *ctx, const char *format, ...)
LOG_BODY(ctx, LIBUSB_LOG_LEVEL_WARNING)
static inline void usbi_info(struct libusb_context *ctx, const char *format, ...)
LOG_BODY(ctx, LIBUSB_LOG_LEVEL_INFO)
static inline void usbi_dbg(const char *format, ...)
LOG_BODY(NULL, LIBUSB_LOG_LEVEL_DEBUG)
#endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1400) */
#else /* ENABLE_LOGGING */
#define usbi_err(ctx, ...) do { (void)ctx; } while (0)
#define usbi_warn(ctx, ...) do { (void)ctx; } while (0)
#define usbi_info(ctx, ...) do { (void)ctx; } while (0)
#define usbi_dbg(...) do {} while (0)
#endif /* ENABLE_LOGGING */
#define USBI_GET_CONTEXT(ctx) \
do { \
@@ -254,8 +300,11 @@ extern struct libusb_context *usbi_default_context;
struct pollfd;
struct libusb_context {
int debug;
#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
enum libusb_log_level debug;
int debug_fixed;
libusb_log_cb log_handler;
#endif
/* internal event pipe, used for signalling occurrence of an internal event. */
int event_pipe[2];
@@ -270,6 +319,7 @@ struct libusb_context {
/* A list of registered hotplug callbacks */
struct list_head hotplug_cbs;
libusb_hotplug_callback_handle next_hotplug_cb_handle;
usbi_mutex_t hotplug_cbs_lock;
/* this is a list of in-flight transfer handles, sorted by timeout
@@ -331,14 +381,19 @@ struct libusb_context {
#endif
struct list_head list;
PTR_ALIGNED unsigned char os_priv[ZERO_SIZED_ARRAY];
};
enum usbi_event_flags {
/* The list of pollfds has been modified */
USBI_EVENT_POLLFDS_MODIFIED = 1 << 0,
USBI_EVENT_POLLFDS_MODIFIED = 1U << 0,
/* The user has interrupted the event handler */
USBI_EVENT_USER_INTERRUPT = 1 << 1,
USBI_EVENT_USER_INTERRUPT = 1U << 1,
/* A hotplug callback deregistration is pending */
USBI_EVENT_HOTPLUG_CB_DEREGISTERED = 1U << 2,
};
/* Macros for managing event handling state */
@@ -383,17 +438,7 @@ struct libusb_device {
struct libusb_device_descriptor device_descriptor;
int attached;
unsigned char os_priv
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
#else
[0] /* non-standard, but usually working code */
#endif
#if defined(OS_SUNOS)
__attribute__ ((aligned (8)));
#else
;
#endif
PTR_ALIGNED unsigned char os_priv[ZERO_SIZED_ARRAY];
};
struct libusb_device_handle {
@@ -404,17 +449,8 @@ struct libusb_device_handle {
struct list_head list;
struct libusb_device *dev;
int auto_detach_kernel_driver;
unsigned char os_priv
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
#else
[0] /* non-standard, but usually working code */
#endif
#if defined(OS_SUNOS)
__attribute__ ((aligned (8)));
#else
;
#endif
PTR_ALIGNED unsigned char os_priv[ZERO_SIZED_ARRAY];
};
enum {
@@ -459,24 +495,24 @@ struct usbi_transfer {
enum usbi_transfer_state_flags {
/* Transfer successfully submitted by backend */
USBI_TRANSFER_IN_FLIGHT = 1 << 0,
USBI_TRANSFER_IN_FLIGHT = 1U << 0,
/* Cancellation was requested via libusb_cancel_transfer() */
USBI_TRANSFER_CANCELLING = 1 << 1,
USBI_TRANSFER_CANCELLING = 1U << 1,
/* Operation on the transfer failed because the device disappeared */
USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 2,
USBI_TRANSFER_DEVICE_DISAPPEARED = 1U << 2,
};
enum usbi_transfer_timeout_flags {
/* Set by backend submit_transfer() if the OS handles timeout */
USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 0,
USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1U << 0,
/* The transfer timeout has been handled */
USBI_TRANSFER_TIMEOUT_HANDLED = 1 << 1,
USBI_TRANSFER_TIMEOUT_HANDLED = 1U << 1,
/* The transfer timeout was successfully processed */
USBI_TRANSFER_TIMED_OUT = 1 << 2,
USBI_TRANSFER_TIMED_OUT = 1U << 2,
};
#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \
@@ -488,9 +524,10 @@ enum usbi_transfer_timeout_flags {
static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer)
{
assert(transfer->num_iso_packets >= 0);
return ((unsigned char *)transfer) + sizeof(struct usbi_transfer)
+ sizeof(struct libusb_transfer)
+ (transfer->num_iso_packets
+ ((size_t)transfer->num_iso_packets
* sizeof(struct libusb_iso_packet_descriptor));
}
@@ -540,19 +577,6 @@ int usbi_clear_event(struct libusb_context *ctx);
#include "os/poll_windows.h"
#endif
#if (defined(OS_WINDOWS) || defined(OS_WINCE)) && !defined(__GNUC__)
#define snprintf _snprintf
#define vsnprintf _vsnprintf
int usbi_gettimeofday(struct timeval *tp, void *tzp);
#define LIBUSB_GETTIMEOFDAY_WIN32
#define HAVE_USBI_GETTIMEOFDAY
#else
#ifdef HAVE_GETTIMEOFDAY
#define usbi_gettimeofday(tv, tz) gettimeofday((tv), (tz))
#define HAVE_USBI_GETTIMEOFDAY
#endif
#endif
struct usbi_pollfd {
/* must come first */
struct libusb_pollfd pollfd;
@@ -573,13 +597,7 @@ void usbi_remove_pollfd(struct libusb_context *ctx, int fd);
struct discovered_devs {
size_t len;
size_t capacity;
struct libusb_device *devices
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
#else
[0] /* non-standard, but usually working code */
#endif
;
struct libusb_device *devices[ZERO_SIZED_ARRAY];
};
struct discovered_devs *discovered_devs_append(
@@ -612,7 +630,17 @@ struct usbi_os_backend {
*
* This function is called when the user deinitializes the library.
*/
void (*exit)(void);
void (*exit)(struct libusb_context *ctx);
/* Set a backend-specific option. Optional.
*
* This function is called when the user calls libusb_set_option() and
* the option is not handled by the core library.
*
* Return 0 on success, or a LIBUSB_ERROR code on failure.
*/
int (*set_option)(struct libusb_context *ctx, enum libusb_option option,
va_list args);
/* Enumerate all the USB devices on the system, returning them in a list
* of discovered devices.
@@ -685,6 +713,34 @@ struct usbi_os_backend {
*/
void (*hotplug_poll)(void);
/* Wrap a platform-specific device handle for I/O and other USB
* operations. The device handle is preallocated for you.
*
* Your backend should allocate any internal resources required for I/O
* and other operations so that those operations can happen (hopefully)
* without hiccup. This is also a good place to inform libusb that it
* should monitor certain file descriptors related to this device -
* see the usbi_add_pollfd() function.
*
* Your backend should also initialize the device structure
* (dev_handle->dev), which is NULL at the beginning of the call.
*
* This function should not generate any bus I/O and should not block.
*
* This function is called when the user attempts to wrap an existing
* platform-specific device handle for a device.
*
* Return:
* - 0 on success
* - LIBUSB_ERROR_ACCESS if the user has insufficient permissions
* - another LIBUSB_ERROR code on other failure
*
* Do not worry about freeing the handle on failed open, the upper layers
* do this for you.
*/
int (*wrap_sys_device)(struct libusb_context *ctx,
struct libusb_device_handle *dev_handle, intptr_t sys_dev);
/* Open a device for I/O and other USB operations. The device handle
* is preallocated for you, you can retrieve the device in question
* through handle->dev.
@@ -1115,6 +1171,11 @@ struct usbi_os_backend {
clockid_t (*get_timerfd_clockid)(void);
#endif
/* Number of bytes to reserve for per-context private backend data.
* This private data area is accessible through the "os_priv" field of
* struct libusb_context. */
size_t context_priv_size;
/* Number of bytes to reserve for per-device private backend data.
* This private data area is accessible through the "os_priv" field of
* struct libusb_device. */
@@ -1132,21 +1193,7 @@ struct usbi_os_backend {
size_t transfer_priv_size;
};
#if defined(OS_WINDOWS)
extern const struct usbi_os_backend * usbi_backend;
#else
extern const struct usbi_os_backend * const usbi_backend;
#endif
extern const struct usbi_os_backend linux_usbfs_backend;
extern const struct usbi_os_backend darwin_backend;
extern const struct usbi_os_backend openbsd_backend;
extern const struct usbi_os_backend netbsd_backend;
extern const struct usbi_os_backend windows_backend;
extern const struct usbi_os_backend usbdk_backend;
extern const struct usbi_os_backend wince_backend;
extern const struct usbi_os_backend haiku_usb_raw_backend;
extern const struct usbi_os_backend sunos_backend;
extern const struct usbi_os_backend usbi_backend;
extern struct list_head active_contexts_list;
extern usbi_mutex_static_t active_contexts_lock;
+399 -241
View File
File diff suppressed because it is too large. Load diff
+55 -16
View File
@@ -1,6 +1,7 @@
/*
* darwin backend for libusb 1.0
* Copyright © 2008-2015 Nathan Hjelm <[email protected]>
* Copyright © 2008-2019 Nathan Hjelm <[email protected]>
* Copyright © 2019 Google LLC. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,6 +21,8 @@
#if !defined(LIBUSB_DARWIN_H)
#define LIBUSB_DARWIN_H
#include <stdbool.h>
#include "libusbi.h"
#include <IOKit/IOTypes.h>
@@ -28,37 +31,58 @@
#include <IOKit/IOCFPlugIn.h>
/* IOUSBInterfaceInferface */
#if defined (kIOUSBInterfaceInterfaceID700) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
/* New in OS 10.12.0. */
#if defined (kIOUSBInterfaceInterfaceID800) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
#define usb_interface_t IOUSBInterfaceInterface800
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID800
#define InterfaceVersion 800
/* New in OS 10.10.0. */
#elif defined (kIOUSBInterfaceInterfaceID700) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 101000)
#define usb_interface_t IOUSBInterfaceInterface700
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID700
#define InterfaceVersion 700
#elif defined (kIOUSBInterfaceInterfaceID550) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
/* New in OS 10.9.0. */
#elif defined (kIOUSBInterfaceInterfaceID650) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
#define usb_interface_t IOUSBInterfaceInterface650
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID650
#define InterfaceVersion 650
/* New in OS 10.8.2 but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBInterfaceInterfaceID550) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
#define usb_interface_t IOUSBInterfaceInterface550
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID550
#define InterfaceVersion 550
#elif defined (kIOUSBInterfaceInterfaceID500)
/* New in OS 10.7.3 but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBInterfaceInterfaceID500) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
#define usb_interface_t IOUSBInterfaceInterface500
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID500
#define InterfaceVersion 500
#elif defined (kIOUSBInterfaceInterfaceID300)
/* New in OS 10.5.0. */
#elif defined (kIOUSBInterfaceInterfaceID300) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
#define usb_interface_t IOUSBInterfaceInterface300
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300
#define InterfaceVersion 300
#elif defined (kIOUSBInterfaceInterfaceID245)
/* New in OS 10.4.5 (or 10.4.6?) but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBInterfaceInterfaceID245) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
#define usb_interface_t IOUSBInterfaceInterface245
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245
#define InterfaceVersion 245
#elif defined (kIOUSBInterfaceInterfaceID220)
/* New in OS 10.4.0. */
#elif defined (kIOUSBInterfaceInterfaceID220) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1040)
#define usb_interface_t IOUSBInterfaceInterface220
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
@@ -66,43 +90,57 @@
#else
#error "IOUSBFamily is too old. Please upgrade your OS"
#error "IOUSBFamily is too old. Please upgrade your SDK and/or deployment target"
#endif
/* IOUSBDeviceInterface */
#if defined (kIOUSBDeviceInterfaceID500) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
/* New in OS 10.9.0. */
#if defined (kIOUSBDeviceInterfaceID650) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
#define usb_device_t IOUSBDeviceInterface650
#define DeviceInterfaceID kIOUSBDeviceInterfaceID650
#define DeviceVersion 650
/* New in OS 10.7.3 but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBDeviceInterfaceID500) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
#define usb_device_t IOUSBDeviceInterface500
#define DeviceInterfaceID kIOUSBDeviceInterfaceID500
#define DeviceVersion 500
#elif defined (kIOUSBDeviceInterfaceID320)
/* New in OS 10.5.4 but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBDeviceInterfaceID320) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)
#define usb_device_t IOUSBDeviceInterface320
#define DeviceInterfaceID kIOUSBDeviceInterfaceID320
#define DeviceVersion 320
#elif defined (kIOUSBDeviceInterfaceID300)
/* New in OS 10.5.0. */
#elif defined (kIOUSBDeviceInterfaceID300) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
#define usb_device_t IOUSBDeviceInterface300
#define DeviceInterfaceID kIOUSBDeviceInterfaceID300
#define DeviceVersion 300
#elif defined (kIOUSBDeviceInterfaceID245)
/* New in OS 10.4.5 (or 10.4.6?) but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBDeviceInterfaceID245) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
#define usb_device_t IOUSBDeviceInterface245
#define DeviceInterfaceID kIOUSBDeviceInterfaceID245
#define DeviceVersion 245
#elif defined (kIOUSBDeviceInterfaceID220)
/* New in OS 10.2.3 but can't test deployment target to that granularity, so round up. */
#elif defined (kIOUSBDeviceInterfaceID197) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1030)
#define usb_device_t IOUSBDeviceInterface197
#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
#define DeviceVersion 197
#else
#error "IOUSBFamily is too old. Please upgrade your OS"
#error "IOUSBFamily is too old. Please upgrade your SDK and/or deployment target"
#endif
@@ -120,13 +158,14 @@ struct darwin_cached_device {
UInt32 location;
UInt64 parent_session;
UInt64 session;
UInt16 address;
USBDeviceAddress address;
char sys_path[21];
usb_device_t **device;
int open_count;
UInt8 first_config, active_config, port;
int can_enumerate;
int refcount;
bool in_reenumerate;
};
struct darwin_device_priv {
@@ -134,7 +173,7 @@ struct darwin_device_priv {
};
struct darwin_device_handle_priv {
int is_open;
bool is_open;
CFRunLoopSourceRef cfSource;
struct darwin_interface {
+6 -6
View File
@@ -243,7 +243,7 @@ USBDeviceHandle::~USBDeviceHandle()
if (fRawFD > 0)
close(fRawFD);
for(int i = 0; i < 32; i++) {
if (fClaimedInterfaces & (1 << i))
if (fClaimedInterfaces & (1U << i))
ReleaseInterface(i);
}
delete_sem(fTransfersSem);
@@ -256,7 +256,7 @@ USBDeviceHandle::ClaimInterface(int inumber)
{
int status = fUSBDevice->ClaimInterface(inumber);
if (status == LIBUSB_SUCCESS)
fClaimedInterfaces |= (1 << inumber);
fClaimedInterfaces |= (1U << inumber);
return status;
}
@@ -264,7 +264,7 @@ int
USBDeviceHandle::ReleaseInterface(int inumber)
{
fUSBDevice->ReleaseInterface(inumber);
fClaimedInterfaces &= ~(1 << inumber);
fClaimedInterfaces &= ~(1U << inumber);
return LIBUSB_SUCCESS;
}
@@ -388,15 +388,15 @@ int USBDevice::ClaimInterface(int interface)
{
if (interface > ActiveConfiguration()->number_interfaces)
return LIBUSB_ERROR_NOT_FOUND;
if (fClaimedInterfaces & (1 << interface))
if (fClaimedInterfaces & (1U << interface))
return LIBUSB_ERROR_BUSY;
fClaimedInterfaces |= (1 << interface);
fClaimedInterfaces |= (1U << interface);
return LIBUSB_SUCCESS;
}
int USBDevice::ReleaseInterface(int interface)
{
fClaimedInterfaces &= ~(1 << interface);
fClaimedInterfaces &= ~(1U << interface);
return LIBUSB_SUCCESS;
}
+49 -46
View File
@@ -29,6 +29,9 @@
USBRoster gUsbRoster;
int32 gInitCount = 0;
static int haiku_get_config_descriptor(struct libusb_device *, uint8_t,
unsigned char *, size_t, int *);
static int
haiku_init(struct libusb_context *ctx)
{
@@ -38,8 +41,9 @@ haiku_init(struct libusb_context *ctx)
}
static void
haiku_exit(void)
haiku_exit(struct libusb_context *ctx)
{
UNUSED(ctx);
if (atomic_add(&gInitCount, -1) == 1)
gUsbRoster.Stop();
}
@@ -82,12 +86,7 @@ static int
haiku_get_active_config_descriptor(struct libusb_device *device, unsigned char *buffer, size_t len, int *host_endian)
{
USBDevice *dev = *((USBDevice **)device->os_priv);
const usb_configuration_descriptor *act_config = dev->ActiveConfiguration();
if (len > act_config->total_length)
return LIBUSB_ERROR_OVERFLOW;
memcpy(buffer, act_config, len);
*host_endian = 0;
return LIBUSB_SUCCESS;
return haiku_get_config_descriptor(device, dev->ActiveConfigurationIndex(), buffer, len, host_endian);
}
static int
@@ -99,8 +98,9 @@ haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index,
usbi_err(DEVICE_CTX(device), "failed getting configuration descriptor");
return LIBUSB_ERROR_INVALID_PARAM;
}
if (len > config->total_length)
if (len > config->total_length) {
len = config->total_length;
}
memcpy(buffer, config, len);
*host_endian = 0;
return len;
@@ -195,56 +195,59 @@ haiku_clock_gettime(int clkid, struct timespec *tp)
return LIBUSB_ERROR_INVALID_PARAM;
}
const struct usbi_os_backend haiku_usb_raw_backend = {
/*.name =*/ "Haiku usbfs",
/*.caps =*/ 0,
/*.init =*/ haiku_init,
/*.exit =*/ haiku_exit,
/*.get_device_list =*/ NULL,
/*.hotplug_poll =*/ NULL,
/*.open =*/ haiku_open,
/*.close =*/ haiku_close,
/*.get_device_descriptor =*/ haiku_get_device_descriptor,
/*.get_active_config_descriptor =*/ haiku_get_active_config_descriptor,
/*.get_config_descriptor =*/ haiku_get_config_descriptor,
/*.get_config_descriptor_by_value =*/ NULL,
const struct usbi_os_backend usbi_backend = {
.name = "Haiku usbfs",
.caps = 0,
.init = haiku_init,
.exit = haiku_exit,
.set_option = NULL,
.get_device_list = NULL,
.hotplug_poll = NULL,
.wrap_sys_device = NULL,
.open = haiku_open,
.close = haiku_close,
.get_device_descriptor = haiku_get_device_descriptor,
.get_active_config_descriptor = haiku_get_active_config_descriptor,
.get_config_descriptor = haiku_get_config_descriptor,
.get_config_descriptor_by_value = NULL,
/*.get_configuration =*/ NULL,
/*.set_configuration =*/ haiku_set_configuration,
/*.claim_interface =*/ haiku_claim_interface,
/*.release_interface =*/ haiku_release_interface,
.get_configuration = NULL,
.set_configuration = haiku_set_configuration,
.claim_interface = haiku_claim_interface,
.release_interface = haiku_release_interface,
/*.set_interface_altsetting =*/ haiku_set_altsetting,
/*.clear_halt =*/ NULL,
/*.reset_device =*/ NULL,
.set_interface_altsetting = haiku_set_altsetting,
.clear_halt = NULL,
.reset_device = NULL,
/*.alloc_streams =*/ NULL,
/*.free_streams =*/ NULL,
.alloc_streams = NULL,
.free_streams = NULL,
/*.dev_mem_alloc =*/ NULL,
/*.dev_mem_free =*/ NULL,
.dev_mem_alloc = NULL,
.dev_mem_free = NULL,
/*.kernel_driver_active =*/ NULL,
/*.detach_kernel_driver =*/ NULL,
/*.attach_kernel_driver =*/ NULL,
.kernel_driver_active = NULL,
.detach_kernel_driver = NULL,
.attach_kernel_driver = NULL,
/*.destroy_device =*/ NULL,
.destroy_device = NULL,
/*.submit_transfer =*/ haiku_submit_transfer,
/*.cancel_transfer =*/ haiku_cancel_transfer,
/*.clear_transfer_priv =*/ haiku_clear_transfer_priv,
.submit_transfer = haiku_submit_transfer,
.cancel_transfer = haiku_cancel_transfer,
.clear_transfer_priv = haiku_clear_transfer_priv,
/*.handle_events =*/ NULL,
/*.handle_transfer_completion =*/ haiku_handle_transfer_completion,
.handle_events = NULL,
.handle_transfer_completion = haiku_handle_transfer_completion,
/*.clock_gettime =*/ haiku_clock_gettime,
.clock_gettime = haiku_clock_gettime,
#ifdef USBI_TIMERFD_AVAILABLE
/*.get_timerfd_clockid =*/ NULL,
.get_timerfd_clockid = NULL,
#endif
/*.device_priv_size =*/ sizeof(USBDevice *),
/*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *),
/*.transfer_priv_size =*/ sizeof(USBTransfer *),
.context_priv_size = 0,
.device_priv_size = sizeof(USBDevice *),
.device_handle_priv_size = sizeof(USBDeviceHandle *),
.transfer_priv_size = sizeof(USBTransfer *),
};
+37 -28
View File
@@ -45,24 +45,33 @@
#define NL_GROUP_KERNEL 1
#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 0
#endif
#ifndef SOCK_NONBLOCK
#define SOCK_NONBLOCK 0
#endif
static int linux_netlink_socket = -1;
static int netlink_control_pipe[2] = { -1, -1 };
static pthread_t libusb_linux_event_thread;
static void *linux_netlink_event_thread_main(void *arg);
static int set_fd_cloexec_nb(int fd)
static int set_fd_cloexec_nb(int fd, int socktype)
{
int flags;
#if defined(FD_CLOEXEC)
flags = fcntl(fd, F_GETFD);
if (flags == -1) {
usbi_err(NULL, "failed to get netlink fd flags (%d)", errno);
return -1;
}
/* Make sure the netlink socket file descriptor is marked as CLOEXEC */
if (!(socktype & SOCK_CLOEXEC)) {
flags = fcntl(fd, F_GETFD);
if (flags == -1) {
usbi_err(NULL, "failed to get netlink fd flags (%d)", errno);
return -1;
}
if (!(flags & FD_CLOEXEC)) {
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
usbi_err(NULL, "failed to set netlink fd flags (%d)", errno);
return -1;
@@ -70,13 +79,14 @@ static int set_fd_cloexec_nb(int fd)
}
#endif
flags = fcntl(fd, F_GETFL);
if (flags == -1) {
usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno);
return -1;
}
/* Make sure the netlink socket is non-blocking */
if (!(socktype & SOCK_NONBLOCK)) {
flags = fcntl(fd, F_GETFL);
if (flags == -1) {
usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno);
return -1;
}
if (!(flags & O_NONBLOCK)) {
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
usbi_err(NULL, "failed to set netlink fd status flags (%d)", errno);
return -1;
@@ -89,21 +99,15 @@ static int set_fd_cloexec_nb(int fd)
int linux_netlink_start_event_monitor(void)
{
struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL };
int socktype = SOCK_RAW;
int socktype = SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC;
int opt = 1;
int ret;
#if defined(SOCK_CLOEXEC)
socktype |= SOCK_CLOEXEC;
#endif
#if defined(SOCK_NONBLOCK)
socktype |= SOCK_NONBLOCK;
#endif
linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
if (linux_netlink_socket == -1 && errno == EINVAL) {
usbi_dbg("failed to create netlink socket of type %d, attempting SOCK_RAW", socktype);
linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
socktype = SOCK_RAW;
linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
}
if (linux_netlink_socket == -1) {
@@ -111,7 +115,7 @@ int linux_netlink_start_event_monitor(void)
goto err;
}
ret = set_fd_cloexec_nb(linux_netlink_socket);
ret = set_fd_cloexec_nb(linux_netlink_socket, socktype);
if (ret == -1)
goto err_close_socket;
@@ -162,7 +166,7 @@ int linux_netlink_stop_event_monitor(void)
/* Write some dummy data to the control pipe and
* wait for the thread to exit */
r = usbi_write(netlink_control_pipe[1], &dummy, sizeof(dummy));
r = write(netlink_control_pipe[1], &dummy, sizeof(dummy));
if (r <= 0)
usbi_warn(NULL, "netlink control pipe signal failed");
@@ -356,7 +360,8 @@ static int linux_netlink_read_message(void)
static void *linux_netlink_event_thread_main(void *arg)
{
char dummy;
ssize_t r;
int r;
ssize_t nb;
struct pollfd fds[] = {
{ .fd = netlink_control_pipe[0],
.events = POLLIN },
@@ -368,11 +373,15 @@ static void *linux_netlink_event_thread_main(void *arg)
usbi_dbg("netlink event thread entering");
while (poll(fds, 2, -1) >= 0) {
while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) {
if (r < 0) {
/* temporary failure */
continue;
}
if (fds[0].revents & POLLIN) {
/* activity on control pipe, read the byte and exit */
r = usbi_read(netlink_control_pipe[0], &dummy, sizeof(dummy));
if (r <= 0)
nb = read(netlink_control_pipe[0], &dummy, sizeof(dummy));
if (nb <= 0)
usbi_warn(NULL, "netlink control pipe read failed");
break;
}
+32 -10
View File
@@ -82,17 +82,33 @@ int linux_udev_start_event_monitor(void)
udev_monitor_fd = udev_monitor_get_fd(udev_monitor);
#if defined(FD_CLOEXEC)
/* Make sure the udev file descriptor is marked as CLOEXEC */
r = fcntl(udev_monitor_fd, F_GETFD);
if (r == -1) {
usbi_err(NULL, "geting udev monitor fd flags (%d)", errno);
goto err_free_monitor;
}
if (!(r & FD_CLOEXEC)) {
if (fcntl(udev_monitor_fd, F_SETFD, r | FD_CLOEXEC) == -1) {
usbi_err(NULL, "setting udev monitor fd flags (%d)", errno);
goto err_free_monitor;
}
}
#endif
/* Some older versions of udev are not non-blocking by default,
* so make sure this is set */
r = fcntl(udev_monitor_fd, F_GETFL);
if (r == -1) {
usbi_err(NULL, "getting udev monitor fd flags (%d)", errno);
usbi_err(NULL, "getting udev monitor fd status flags (%d)", errno);
goto err_free_monitor;
}
r = fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK);
if (r) {
usbi_err(NULL, "setting udev monitor fd flags (%d)", errno);
goto err_free_monitor;
if (!(r & O_NONBLOCK)) {
if (fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK) == -1) {
usbi_err(NULL, "setting udev monitor fd status flags (%d)", errno);
goto err_free_monitor;
}
}
r = usbi_pipe(udev_control_pipe);
@@ -134,7 +150,7 @@ int linux_udev_stop_event_monitor(void)
/* Write some dummy data to the control pipe and
* wait for the thread to exit */
r = usbi_write(udev_control_pipe[1], &dummy, sizeof(dummy));
r = write(udev_control_pipe[1], &dummy, sizeof(dummy));
if (r <= 0) {
usbi_warn(NULL, "udev control pipe signal failed");
}
@@ -162,6 +178,7 @@ static void *linux_udev_event_thread_main(void *arg)
{
char dummy;
int r;
ssize_t nb;
struct udev_device* udev_dev;
struct pollfd fds[] = {
{.fd = udev_control_pipe[0],
@@ -172,11 +189,15 @@ static void *linux_udev_event_thread_main(void *arg)
usbi_dbg("udev event thread entering.");
while (poll(fds, 2, -1) >= 0) {
while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) {
if (r < 0) {
/* temporary failure */
continue;
}
if (fds[0].revents & POLLIN) {
/* activity on control pipe, read the byte and exit */
r = usbi_read(udev_control_pipe[0], &dummy, sizeof(dummy));
if (r <= 0) {
nb = read(udev_control_pipe[0], &dummy, sizeof(dummy));
if (nb <= 0) {
usbi_warn(NULL, "udev control pipe read failed");
}
break;
@@ -211,7 +232,7 @@ static int udev_device_info(struct libusb_context *ctx, int detached,
}
return linux_get_device_address(ctx, detached, busnum, devaddr,
dev_node, *sys_name);
dev_node, *sys_name, -1);
}
static void udev_hotplug_event(struct udev_device* udev_dev)
@@ -270,6 +291,7 @@ int linux_udev_scan_devices(struct libusb_context *ctx)
udev_enumerate_scan_devices(enumerator);
devices = udev_enumerate_get_list_entry(enumerator);
entry = NULL;
udev_list_entry_foreach(entry, devices) {
const char *path = udev_list_entry_get_name(entry);
uint8_t busnum = 0, devaddr = 0;
+316 -156
View File
@@ -81,6 +81,19 @@ static const char *usbfs_path = NULL;
/* use usbdev*.* device names in /dev instead of the usbfs bus directories */
static int usbdev_names = 0;
/* Linux has changed the maximum length of an individual isochronous packet
* over time. Initially this limit was 1,023 bytes, but Linux 2.6.18
* (commit 3612242e527eb47ee4756b5350f8bdf791aa5ede) increased this value to
* 8,192 bytes to support higher bandwidth devices. Linux 3.10
* (commit e2e2f0ea1c935edcf53feb4c4c8fdb4f86d57dd9) further increased this
* value to 49,152 bytes to support super speed devices.
*/
static unsigned int max_iso_packet_len = 0;
/* Linux 2.6.23 adds support for O_CLOEXEC when opening files, which marks the
* close-on-exec flag in the underlying file descriptor. */
static int supports_flag_cloexec = -1;
/* Linux 2.6.32 adds support for a bulk continuation URB flag. this basically
* allows us to mark URBs as being part of a specific logical transfer when
* we submit them to the kernel. then, on any error except a cancellation, all
@@ -136,6 +149,12 @@ static int detach_kernel_driver_and_claim(struct libusb_device_handle *, int);
static int linux_default_scan_devices (struct libusb_context *ctx);
#endif
struct kernel_version {
int major;
int minor;
int sublevel;
};
struct linux_device_priv {
char *sysfs_dir;
unsigned char *descriptors;
@@ -146,6 +165,7 @@ struct linux_device_priv {
struct linux_device_handle_priv {
int fd;
int fd_removed;
int fd_keep;
uint32_t caps;
};
@@ -180,6 +200,16 @@ struct linux_transfer_priv {
int iso_packet_offset;
};
static int _open(const char *path, int flags)
{
#if defined(O_CLOEXEC)
if (supports_flag_cloexec)
return open(path, flags | O_CLOEXEC);
else
#endif
return open(path, flags);
}
static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
{
struct libusb_context *ctx = DEVICE_CTX(dev);
@@ -194,7 +224,7 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
snprintf(path, PATH_MAX, "%s/%03d/%03d",
usbfs_path, dev->bus_number, dev->device_address);
fd = open(path, mode);
fd = _open(path, mode);
if (fd != -1)
return fd; /* Success */
@@ -205,7 +235,7 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
/* Wait 10ms for USB device path creation.*/
nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000UL}, NULL);
fd = open(path, mode);
fd = _open(path, mode);
if (fd != -1)
return fd; /* Success */
}
@@ -311,8 +341,10 @@ static const char *find_usbfs_path(void)
/* On udev based systems without any usb-devices /dev/bus/usb will not
* exist. So if we've not found anything and we're using udev for hotplug
* simply assume /dev/bus/usb rather then making libusb_init fail. */
#if defined(USE_UDEV)
* simply assume /dev/bus/usb rather then making libusb_init fail.
* Make the same assumption for Android where SELinux policies might block us
* from reading /dev on newer devices. */
#if defined(USE_UDEV) || defined(__ANDROID__)
if (ret == NULL)
ret = "/dev/bus/usb";
#endif
@@ -342,39 +374,59 @@ static clockid_t find_monotonic_clock(void)
return CLOCK_REALTIME;
}
static int kernel_version_ge(int major, int minor, int sublevel)
static int get_kernel_version(struct libusb_context *ctx,
struct kernel_version *ver)
{
struct utsname uts;
int atoms, kmajor, kminor, ksublevel;
int atoms;
if (uname(&uts) < 0)
return -1;
atoms = sscanf(uts.release, "%d.%d.%d", &kmajor, &kminor, &ksublevel);
if (atoms < 1)
if (uname(&uts) < 0) {
usbi_err(ctx, "uname failed, errno %d", errno);
return -1;
}
if (kmajor > major)
atoms = sscanf(uts.release, "%d.%d.%d", &ver->major, &ver->minor, &ver->sublevel);
if (atoms < 1) {
usbi_err(ctx, "failed to parse uname release '%s'", uts.release);
return -1;
}
if (atoms < 2)
ver->minor = -1;
if (atoms < 3)
ver->sublevel = -1;
usbi_dbg("reported kernel version is %s", uts.release);
return 0;
}
static int kernel_version_ge(const struct kernel_version *ver,
int major, int minor, int sublevel)
{
if (ver->major > major)
return 1;
if (kmajor < major)
else if (ver->major < major)
return 0;
/* kmajor == major */
if (atoms < 2)
if (ver->minor == -1 && ver->sublevel == -1)
return 0 == minor && 0 == sublevel;
if (kminor > minor)
else if (ver->minor > minor)
return 1;
if (kminor < minor)
else if (ver->minor < minor)
return 0;
/* kminor == minor */
if (atoms < 3)
if (ver->sublevel == -1)
return 0 == sublevel;
return ksublevel >= sublevel;
return ver->sublevel >= sublevel;
}
static int op_init(struct libusb_context *ctx)
{
struct kernel_version kversion;
struct stat statbuf;
int r;
@@ -387,13 +439,17 @@ static int op_init(struct libusb_context *ctx)
if (monotonic_clkid == -1)
monotonic_clkid = find_monotonic_clock();
if (get_kernel_version(ctx, &kversion) < 0)
return LIBUSB_ERROR_OTHER;
if (supports_flag_cloexec == -1) {
/* O_CLOEXEC flag available from Linux 2.6.23 */
supports_flag_cloexec = kernel_version_ge(&kversion,2,6,23);
}
if (supports_flag_bulk_continuation == -1) {
/* bulk continuation URB flag available from Linux 2.6.32 */
supports_flag_bulk_continuation = kernel_version_ge(2,6,32);
if (supports_flag_bulk_continuation == -1) {
usbi_err(ctx, "error checking for bulk continuation support");
return LIBUSB_ERROR_OTHER;
}
supports_flag_bulk_continuation = kernel_version_ge(&kversion,2,6,32);
}
if (supports_flag_bulk_continuation)
@@ -401,32 +457,31 @@ static int op_init(struct libusb_context *ctx)
if (-1 == supports_flag_zero_packet) {
/* zero length packet URB flag fixed since Linux 2.6.31 */
supports_flag_zero_packet = kernel_version_ge(2,6,31);
if (-1 == supports_flag_zero_packet) {
usbi_err(ctx, "error checking for zero length packet support");
return LIBUSB_ERROR_OTHER;
}
supports_flag_zero_packet = kernel_version_ge(&kversion,2,6,31);
}
if (supports_flag_zero_packet)
usbi_dbg("zero length packet flag supported");
if (!max_iso_packet_len) {
if (kernel_version_ge(&kversion,3,10,0))
max_iso_packet_len = 49152;
else if (kernel_version_ge(&kversion,2,6,18))
max_iso_packet_len = 8192;
else
max_iso_packet_len = 1023;
}
usbi_dbg("max iso packet length is (likely) %u bytes", max_iso_packet_len);
if (-1 == sysfs_has_descriptors) {
/* sysfs descriptors has all descriptors since Linux 2.6.26 */
sysfs_has_descriptors = kernel_version_ge(2,6,26);
if (-1 == sysfs_has_descriptors) {
usbi_err(ctx, "error checking for sysfs descriptors");
return LIBUSB_ERROR_OTHER;
}
sysfs_has_descriptors = kernel_version_ge(&kversion,2,6,26);
}
if (-1 == sysfs_can_relate_devices) {
/* sysfs has busnum since Linux 2.6.22 */
sysfs_can_relate_devices = kernel_version_ge(2,6,22);
if (-1 == sysfs_can_relate_devices) {
usbi_err(ctx, "error checking for sysfs busnum");
return LIBUSB_ERROR_OTHER;
}
sysfs_can_relate_devices = kernel_version_ge(&kversion,2,6,22);
}
if (sysfs_can_relate_devices || sysfs_has_descriptors) {
@@ -463,8 +518,9 @@ static int op_init(struct libusb_context *ctx)
return r;
}
static void op_exit(void)
static void op_exit(struct libusb_context *ctx)
{
UNUSED(ctx);
usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
assert(init_count != 0);
if (!--init_count) {
@@ -478,8 +534,10 @@ static int linux_start_event_monitor(void)
{
#if defined(USE_UDEV)
return linux_udev_start_event_monitor();
#else
#elif !defined(__ANDROID__)
return linux_netlink_start_event_monitor();
#else
return LIBUSB_SUCCESS;
#endif
}
@@ -487,20 +545,22 @@ static int linux_stop_event_monitor(void)
{
#if defined(USE_UDEV)
return linux_udev_stop_event_monitor();
#else
#elif !defined(__ANDROID__)
return linux_netlink_stop_event_monitor();
#else
return LIBUSB_SUCCESS;
#endif
}
static int linux_scan_devices(struct libusb_context *ctx)
{
int ret;
int ret = 0;
usbi_mutex_static_lock(&linux_hotplug_lock);
#if defined(USE_UDEV)
ret = linux_udev_scan_devices(ctx);
#else
#elif !defined(__ANDROID__)
ret = linux_default_scan_devices(ctx);
#endif
@@ -513,7 +573,7 @@ static void op_hotplug_poll(void)
{
#if defined(USE_UDEV)
linux_udev_hotplug_poll();
#else
#elif !defined(__ANDROID__)
linux_netlink_hotplug_poll();
#endif
}
@@ -526,7 +586,7 @@ static int _open_sysfs_attr(struct libusb_device *dev, const char *attr)
snprintf(filename, PATH_MAX, "%s/%s/%s",
SYSFS_DEVICE_PATH, priv->sysfs_dir, attr);
fd = open(filename, O_RDONLY);
fd = _open(filename, O_RDONLY);
if (fd < 0) {
usbi_err(DEVICE_CTX(dev),
"open %s failed ret=%d errno=%d", filename, fd, errno);
@@ -542,12 +602,12 @@ static int __read_sysfs_attr(struct libusb_context *ctx,
{
char filename[PATH_MAX];
FILE *f;
int r, value;
int fd, r, value;
snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH,
devname, attr);
f = fopen(filename, "r");
if (f == NULL) {
fd = _open(filename, O_RDONLY);
if (fd == -1) {
if (errno == ENOENT) {
/* File doesn't exist. Assume the device has been
disconnected (see trac ticket #70). */
@@ -557,6 +617,13 @@ static int __read_sysfs_attr(struct libusb_context *ctx,
return LIBUSB_ERROR_IO;
}
f = fdopen(fd, "r");
if (f == NULL) {
usbi_err(ctx, "fdopen %s failed errno=%d", filename, errno);
close(fd);
return LIBUSB_ERROR_OTHER;
}
r = fscanf(f, "%d", &value);
fclose(f);
if (r != 1) {
@@ -576,7 +643,7 @@ static int op_get_device_descriptor(struct libusb_device *dev,
{
struct linux_device_priv *priv = _device_priv(dev);
*host_endian = sysfs_has_descriptors ? 0 : 1;
*host_endian = (priv->sysfs_dir && sysfs_has_descriptors) ? 0 : 1;
memcpy(buffer, priv->descriptors, DEVICE_DESC_LENGTH);
return 0;
@@ -627,14 +694,23 @@ static int sysfs_get_active_config(struct libusb_device *dev, int *config)
int linux_get_device_address (struct libusb_context *ctx, int detached,
uint8_t *busnum, uint8_t *devaddr,const char *dev_node,
const char *sys_name)
const char *sys_name, int fd)
{
char proc_path[PATH_MAX], fd_path[PATH_MAX];
int sysfs_attr;
ssize_t r;
usbi_dbg("getting address for device: %s detached: %d", sys_name, detached);
/* can't use sysfs to read the bus and device number if the
* device has been detached */
if (!sysfs_can_relate_devices || detached || NULL == sys_name) {
if (NULL == dev_node && fd >= 0) {
/* try to retrieve the device node from fd */
snprintf(proc_path, PATH_MAX, "/proc/self/fd/%d", fd);
r = readlink(proc_path, fd_path, PATH_MAX);
if (r > 0)
dev_node = fd_path;
}
if (NULL == dev_node) {
return LIBUSB_ERROR_OTHER;
}
@@ -644,6 +720,8 @@ int linux_get_device_address (struct libusb_context *ctx, int detached,
sscanf (dev_node, "/dev/bus/usb/%hhu/%hhu", busnum, devaddr);
} else if (!strncmp(dev_node, "/proc/bus/usb", 13)) {
sscanf (dev_node, "/proc/bus/usb/%hhu/%hhu", busnum, devaddr);
} else {
return LIBUSB_ERROR_OTHER;
}
return LIBUSB_SUCCESS;
@@ -696,9 +774,11 @@ static int seek_to_next_descriptor(struct libusb_context *ctx,
}
/* Return offset to next config */
static int seek_to_next_config(struct libusb_context *ctx,
static int seek_to_next_config(struct libusb_device *dev,
unsigned char *buffer, int size)
{
struct libusb_context *ctx = DEVICE_CTX(dev);
struct linux_device_priv *priv = _device_priv(dev);
struct libusb_config_descriptor config;
if (size == 0)
@@ -725,7 +805,7 @@ static int seek_to_next_config(struct libusb_context *ctx,
* config descriptor with verified bLength fields, with descriptors
* with an invalid bLength removed.
*/
if (sysfs_has_descriptors) {
if (priv->sysfs_dir && sysfs_has_descriptors) {
int next = seek_to_next_descriptor(ctx, LIBUSB_DT_CONFIG,
buffer, size);
if (next == LIBUSB_ERROR_NOT_FOUND)
@@ -754,7 +834,6 @@ static int seek_to_next_config(struct libusb_context *ctx,
static int op_get_config_descriptor_by_value(struct libusb_device *dev,
uint8_t value, unsigned char **buffer, int *host_endian)
{
struct libusb_context *ctx = DEVICE_CTX(dev);
struct linux_device_priv *priv = _device_priv(dev);
unsigned char *descriptors = priv->descriptors;
int size = priv->descriptors_len;
@@ -770,7 +849,7 @@ static int op_get_config_descriptor_by_value(struct libusb_device *dev,
/* Seek till the config is found, or till "EOF" */
while (1) {
int next = seek_to_next_config(ctx, descriptors, size);
int next = seek_to_next_config(dev, descriptors, size);
if (next < 0)
return next;
config = (struct libusb_config_descriptor *)descriptors;
@@ -786,16 +865,16 @@ static int op_get_config_descriptor_by_value(struct libusb_device *dev,
static int op_get_active_config_descriptor(struct libusb_device *dev,
unsigned char *buffer, size_t len, int *host_endian)
{
struct linux_device_priv *priv = _device_priv(dev);
int r, config;
unsigned char *config_desc;
if (sysfs_can_relate_devices) {
if (priv->sysfs_dir && sysfs_can_relate_devices) {
r = sysfs_get_active_config(dev, &config);
if (r < 0)
return r;
} else {
/* Use cached bConfigurationValue */
struct linux_device_priv *priv = _device_priv(dev);
config = priv->active_config;
}
if (config == -1)
@@ -806,7 +885,7 @@ static int op_get_active_config_descriptor(struct libusb_device *dev,
if (r < 0)
return r;
len = MIN(len, r);
len = MIN(len, (size_t)r);
memcpy(buffer, config_desc, len);
return len;
}
@@ -827,7 +906,7 @@ static int op_get_config_descriptor(struct libusb_device *dev,
/* Seek till the config is found, or till "EOF" */
for (i = 0; ; i++) {
r = seek_to_next_config(DEVICE_CTX(dev), descriptors, size);
r = seek_to_next_config(dev, descriptors, size);
if (r < 0)
return r;
if (i == config_index)
@@ -836,7 +915,7 @@ static int op_get_config_descriptor(struct libusb_device *dev,
descriptors += r;
}
len = MIN(len, r);
len = MIN(len, (size_t)r);
memcpy(buffer, descriptors, len);
return len;
}
@@ -886,7 +965,7 @@ static int usbfs_get_active_config(struct libusb_device *dev, int fd)
}
static int initialize_device(struct libusb_device *dev, uint8_t busnum,
uint8_t devaddr, const char *sysfs_dir)
uint8_t devaddr, const char *sysfs_dir, int wrapped_fd)
{
struct linux_device_priv *priv = _device_priv(dev);
struct libusb_context *ctx = DEVICE_CTX(dev);
@@ -911,6 +990,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
case 12: dev->speed = LIBUSB_SPEED_FULL; break;
case 480: dev->speed = LIBUSB_SPEED_HIGH; break;
case 5000: dev->speed = LIBUSB_SPEED_SUPER; break;
case 10000: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break;
default:
usbi_warn(DEVICE_CTX(dev), "Unknown device speed: %d Mbps", speed);
}
@@ -918,10 +998,18 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
}
/* cache descriptors in memory */
if (sysfs_has_descriptors)
if (sysfs_dir && sysfs_has_descriptors) {
fd = _open_sysfs_attr(dev, "descriptors");
else
} else if (wrapped_fd < 0) {
fd = _get_usbfs_fd(dev, O_RDONLY, 0);
} else {
fd = wrapped_fd;
r = lseek(fd, 0, SEEK_SET);
if (r < 0) {
usbi_err(ctx, "seek failed ret=%d errno=%d", r, errno);
return LIBUSB_ERROR_IO;
}
}
if (fd < 0)
return fd;
@@ -930,11 +1018,12 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
priv->descriptors = usbi_reallocf(priv->descriptors,
descriptors_size);
if (!priv->descriptors) {
close(fd);
if (fd != wrapped_fd)
close(fd);
return LIBUSB_ERROR_NO_MEM;
}
/* usbfs has holes in the file */
if (!sysfs_has_descriptors) {
if (!(sysfs_dir && sysfs_has_descriptors)) {
memset(priv->descriptors + priv->descriptors_len,
0, descriptors_size - priv->descriptors_len);
}
@@ -943,13 +1032,15 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
if (r < 0) {
usbi_err(ctx, "read descriptor failed ret=%d errno=%d",
fd, errno);
close(fd);
if (fd != wrapped_fd)
close(fd);
return LIBUSB_ERROR_IO;
}
priv->descriptors_len += r;
} while (priv->descriptors_len == descriptors_size);
close(fd);
if (fd != wrapped_fd)
close(fd);
if (priv->descriptors_len < DEVICE_DESC_LENGTH) {
usbi_err(ctx, "short descriptor read (%d)",
@@ -957,11 +1048,14 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
return LIBUSB_ERROR_IO;
}
if (sysfs_can_relate_devices)
if (sysfs_dir && sysfs_can_relate_devices)
return LIBUSB_SUCCESS;
/* cache active config */
fd = _get_usbfs_fd(dev, O_RDWR, 1);
if (wrapped_fd < 0)
fd = _get_usbfs_fd(dev, O_RDWR, 1);
else
fd = wrapped_fd;
if (fd < 0) {
/* cannot send a control message to determine the active
* config. just assume the first one is active. */
@@ -981,7 +1075,8 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
}
r = usbfs_get_active_config(dev, fd);
close(fd);
if (wrapped_fd < 0)
close(fd);
return r;
}
@@ -1029,9 +1124,11 @@ retry:
usbi_mutex_lock(&ctx->usb_devs_lock);
list_for_each_entry(it, &ctx->usb_devs, list, struct libusb_device) {
struct linux_device_priv *priv = _device_priv(it);
if (0 == strcmp (priv->sysfs_dir, parent_sysfs_dir)) {
dev->parent_dev = libusb_ref_device(it);
break;
if (priv->sysfs_dir) {
if (0 == strcmp (priv->sysfs_dir, parent_sysfs_dir)) {
dev->parent_dev = libusb_ref_device(it);
break;
}
}
}
usbi_mutex_unlock(&ctx->usb_devs_lock);
@@ -1080,7 +1177,7 @@ int linux_enumerate_device(struct libusb_context *ctx,
if (!dev)
return LIBUSB_ERROR_NO_MEM;
r = initialize_device(dev, busnum, devaddr, sysfs_dir);
r = initialize_device(dev, busnum, devaddr, sysfs_dir, -1);
if (r < 0)
goto out;
r = usbi_sanitize_device(dev);
@@ -1223,7 +1320,7 @@ static int sysfs_scan_device(struct libusb_context *ctx, const char *devname)
uint8_t busnum, devaddr;
int ret;
ret = linux_get_device_address (ctx, 0, &busnum, &devaddr, NULL, devname);
ret = linux_get_device_address (ctx, 0, &busnum, &devaddr, NULL, devname, -1);
if (LIBUSB_SUCCESS != ret) {
return ret;
}
@@ -1237,11 +1334,12 @@ static int sysfs_get_device_list(struct libusb_context *ctx)
{
DIR *devices = opendir(SYSFS_DEVICE_PATH);
struct dirent *entry;
int r = LIBUSB_ERROR_IO;
int num_devices = 0;
int num_enumerated = 0;
if (!devices) {
usbi_err(ctx, "opendir devices failed errno=%d", errno);
return r;
return LIBUSB_ERROR_IO;
}
while ((entry = readdir(devices))) {
@@ -1249,16 +1347,23 @@ static int sysfs_get_device_list(struct libusb_context *ctx)
|| strchr(entry->d_name, ':'))
continue;
num_devices++;
if (sysfs_scan_device(ctx, entry->d_name)) {
usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
continue;
}
r = 0;
num_enumerated++;
}
closedir(devices);
return r;
/* successful if at least one device was enumerated or no devices were found */
if (num_enumerated || !num_devices)
return LIBUSB_SUCCESS;
else
return LIBUSB_ERROR_IO;
}
static int linux_default_scan_devices (struct libusb_context *ctx)
@@ -1280,28 +1385,14 @@ static int linux_default_scan_devices (struct libusb_context *ctx)
}
#endif
static int op_open(struct libusb_device_handle *handle)
static int initialize_handle(struct libusb_device_handle *handle, int fd)
{
struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
int r;
hpriv->fd = _get_usbfs_fd(handle->dev, O_RDWR, 0);
if (hpriv->fd < 0) {
if (hpriv->fd == LIBUSB_ERROR_NO_DEVICE) {
/* device will still be marked as attached if hotplug monitor thread
* hasn't processed remove event yet */
usbi_mutex_static_lock(&linux_hotplug_lock);
if (handle->dev->attached) {
usbi_dbg("open failed with no device, but device still attached");
linux_device_disconnected(handle->dev->bus_number,
handle->dev->device_address);
}
usbi_mutex_static_unlock(&linux_hotplug_lock);
}
return hpriv->fd;
}
hpriv->fd = fd;
r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps);
r = ioctl(fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps);
if (r < 0) {
if (errno == ENOTTY)
usbi_dbg("getcap not available");
@@ -1314,9 +1405,82 @@ static int op_open(struct libusb_device_handle *handle)
hpriv->caps |= USBFS_CAP_BULK_CONTINUATION;
}
r = usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
}
static int op_wrap_sys_device(struct libusb_context *ctx,
struct libusb_device_handle *handle, intptr_t sys_dev)
{
struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
int fd = (int)sys_dev;
uint8_t busnum, devaddr;
struct usbfs_connectinfo ci;
struct libusb_device *dev;
int r;
r = linux_get_device_address(ctx, 1, &busnum, &devaddr, NULL, NULL, fd);
if (r < 0) {
r = ioctl(fd, IOCTL_USBFS_CONNECTINFO, &ci);
if (r < 0) {
usbi_err(ctx, "connectinfo failed (%d)", errno);
return LIBUSB_ERROR_IO;
}
/* There is no ioctl to get the bus number. We choose 0 here
* as linux starts numbering buses from 1. */
busnum = 0;
devaddr = ci.devnum;
}
/* Session id is unused as we do not add the device to the list of
* connected devices. */
usbi_dbg("allocating new device for fd %d", fd);
dev = usbi_alloc_device(ctx, 0);
if (!dev)
return LIBUSB_ERROR_NO_MEM;
r = initialize_device(dev, busnum, devaddr, NULL, fd);
if (r < 0)
close(hpriv->fd);
goto out;
r = usbi_sanitize_device(dev);
if (r < 0)
goto out;
/* Consider the device as connected, but do not add it to the managed
* device list. */
dev->attached = 1;
handle->dev = dev;
r = initialize_handle(handle, fd);
hpriv->fd_keep = 1;
out:
if (r < 0)
libusb_unref_device(dev);
return r;
}
static int op_open(struct libusb_device_handle *handle)
{
int fd, r;
fd = _get_usbfs_fd(handle->dev, O_RDWR, 0);
if (fd < 0) {
if (fd == LIBUSB_ERROR_NO_DEVICE) {
/* device will still be marked as attached if hotplug monitor thread
* hasn't processed remove event yet */
usbi_mutex_static_lock(&linux_hotplug_lock);
if (handle->dev->attached) {
usbi_dbg("open failed with no device, but device still attached");
linux_device_disconnected(handle->dev->bus_number,
handle->dev->device_address);
}
usbi_mutex_static_unlock(&linux_hotplug_lock);
}
return fd;
}
r = initialize_handle(handle, fd);
if (r < 0)
close(fd);
return r;
}
@@ -1327,21 +1491,23 @@ static void op_close(struct libusb_device_handle *dev_handle)
/* fd may have already been removed by POLLERR condition in op_handle_events() */
if (!hpriv->fd_removed)
usbi_remove_pollfd(HANDLE_CTX(dev_handle), hpriv->fd);
close(hpriv->fd);
if (!hpriv->fd_keep)
close(hpriv->fd);
}
static int op_get_configuration(struct libusb_device_handle *handle,
int *config)
{
struct linux_device_priv *priv = _device_priv(handle->dev);
int r;
if (sysfs_can_relate_devices) {
if (priv->sysfs_dir && sysfs_can_relate_devices) {
r = sysfs_get_active_config(handle->dev, config);
} else {
r = usbfs_get_active_config(handle->dev,
_device_handle_priv(handle)->fd);
if (r == LIBUSB_SUCCESS)
*config = _device_priv(handle->dev)->active_config;
*config = priv->active_config;
}
if (r < 0)
return r;
@@ -1683,10 +1849,7 @@ static int detach_kernel_driver_and_claim(struct libusb_device_handle *handle,
strcpy(dc.driver, "usbfs");
dc.flags = USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER;
r = ioctl(fd, IOCTL_USBFS_DISCONNECT_CLAIM, &dc);
if (r == 0 || (r != 0 && errno != ENOTTY)) {
if (r == 0)
return 0;
if (r != 0 && errno != ENOTTY) {
switch (errno) {
case EBUSY:
return LIBUSB_ERROR_BUSY;
@@ -1698,7 +1861,8 @@ static int detach_kernel_driver_and_claim(struct libusb_device_handle *handle,
usbi_err(HANDLE_CTX(handle),
"disconnect-and-claim failed errno %d", errno);
return LIBUSB_ERROR_OTHER;
}
} else if (r == 0)
return 0;
/* Fallback code for kernels which don't support the
disconnect-and-claim ioctl */
@@ -1971,38 +2135,43 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
struct linux_device_handle_priv *dpriv =
_device_handle_priv(transfer->dev_handle);
struct usbfs_urb **urbs;
size_t alloc_size;
int num_packets = transfer->num_iso_packets;
int i;
int this_urb_len = 0;
int num_urbs = 1;
int packet_offset = 0;
int num_packets_remaining;
int i, j;
int num_urbs;
unsigned int packet_len;
unsigned int total_len = 0;
unsigned char *urb_buffer = transfer->buffer;
/* usbfs places arbitrary limits on iso URBs. this limit has changed
* at least three times, and it's difficult to accurately detect which
* limit this running kernel might impose. so we attempt to submit
* whatever the user has provided. if the kernel rejects the request
* due to its size, we return an error indicating such to the user.
*/
if (num_packets < 1)
return LIBUSB_ERROR_INVALID_PARAM;
/* calculate how many URBs we need */
/* usbfs places arbitrary limits on iso URBs. this limit has changed
* at least three times, but we attempt to detect this limit during
* init and check it here. if the kernel rejects the request due to
* its size, we return an error indicating such to the user.
*/
for (i = 0; i < num_packets; i++) {
unsigned int space_remaining = MAX_ISO_BUFFER_LENGTH - this_urb_len;
packet_len = transfer->iso_packet_desc[i].length;
if (packet_len > space_remaining) {
num_urbs++;
this_urb_len = packet_len;
/* check that we can actually support this packet length */
if (this_urb_len > MAX_ISO_BUFFER_LENGTH)
return LIBUSB_ERROR_INVALID_PARAM;
} else {
this_urb_len += packet_len;
if (packet_len > max_iso_packet_len) {
usbi_warn(TRANSFER_CTX(transfer),
"iso packet length of %u bytes exceeds maximum of %u bytes",
packet_len, max_iso_packet_len);
return LIBUSB_ERROR_INVALID_PARAM;
}
total_len += packet_len;
}
usbi_dbg("need %d %dk URBs for transfer", num_urbs, MAX_ISO_BUFFER_LENGTH / 1024);
if (transfer->length < (int)total_len)
return LIBUSB_ERROR_INVALID_PARAM;
/* usbfs limits the number of iso packets per URB */
num_urbs = (num_packets + (MAX_ISO_PACKETS_PER_URB - 1)) / MAX_ISO_PACKETS_PER_URB;
usbi_dbg("need %d urbs for new transfer with length %d", num_urbs,
transfer->length);
urbs = calloc(num_urbs, sizeof(*urbs));
if (!urbs)
@@ -2015,31 +2184,15 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
tpriv->iso_packet_offset = 0;
/* allocate + initialize each URB with the correct number of packets */
for (i = 0; i < num_urbs; i++) {
num_packets_remaining = num_packets;
for (i = 0, j = 0; i < num_urbs; i++) {
int num_packets_in_urb = MIN(num_packets_remaining, MAX_ISO_PACKETS_PER_URB);
struct usbfs_urb *urb;
unsigned int space_remaining_in_urb = MAX_ISO_BUFFER_LENGTH;
int urb_packet_offset = 0;
unsigned char *urb_buffer_orig = urb_buffer;
int j;
size_t alloc_size;
int k;
/* swallow up all the packets we can fit into this URB */
while (packet_offset < transfer->num_iso_packets) {
packet_len = transfer->iso_packet_desc[packet_offset].length;
if (packet_len <= space_remaining_in_urb) {
/* throw it in */
urb_packet_offset++;
packet_offset++;
space_remaining_in_urb -= packet_len;
urb_buffer += packet_len;
} else {
/* it can't fit, save it for the next URB */
break;
}
}
alloc_size = sizeof(*urb)
+ (urb_packet_offset * sizeof(struct usbfs_iso_packet_desc));
+ (num_packets_in_urb * sizeof(struct usbfs_iso_packet_desc));
urb = calloc(1, alloc_size);
if (!urb) {
free_iso_urbs(tpriv);
@@ -2048,10 +2201,10 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
urbs[i] = urb;
/* populate packet lengths */
for (j = 0, k = packet_offset - urb_packet_offset;
k < packet_offset; k++, j++) {
packet_len = transfer->iso_packet_desc[k].length;
urb->iso_frame_desc[j].length = packet_len;
for (k = 0; k < num_packets_in_urb; j++, k++) {
packet_len = transfer->iso_packet_desc[j].length;
urb->buffer_length += packet_len;
urb->iso_frame_desc[k].length = packet_len;
}
urb->usercontext = itransfer;
@@ -2059,8 +2212,11 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
/* FIXME: interface for non-ASAP data? */
urb->flags = USBFS_URB_ISO_ASAP;
urb->endpoint = transfer->endpoint;
urb->number_of_packets = urb_packet_offset;
urb->buffer = urb_buffer_orig;
urb->number_of_packets = num_packets_in_urb;
urb->buffer = urb_buffer;
urb_buffer += urb->buffer_length;
num_packets_remaining -= num_packets_in_urb;
}
/* submit URBs */
@@ -2073,6 +2229,10 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
usbi_warn(TRANSFER_CTX(transfer),
"submiturb failed, transfer too large");
r = LIBUSB_ERROR_INVALID_PARAM;
} else if (errno == EMSGSIZE) {
usbi_warn(TRANSFER_CTX(transfer),
"submiturb failed, iso packet length too large");
r = LIBUSB_ERROR_INVALID_PARAM;
} else {
usbi_err(TRANSFER_CTX(transfer),
"submiturb failed error %d errno=%d", r, errno);
@@ -2211,7 +2371,6 @@ static void op_clear_transfer_priv(struct usbi_transfer *itransfer)
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
/* urbs can be freed also in submit_transfer so lock mutex first */
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
case LIBUSB_TRANSFER_TYPE_BULK:
@@ -2557,7 +2716,7 @@ static int reap_for_handle(struct libusb_device_handle *handle)
{
struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
int r;
struct usbfs_urb *urb;
struct usbfs_urb *urb = NULL;
struct usbi_transfer *itransfer;
struct libusb_transfer *transfer;
@@ -2683,7 +2842,7 @@ static clockid_t op_get_timerfd_clockid(void)
}
#endif
const struct usbi_os_backend linux_usbfs_backend = {
const struct usbi_os_backend usbi_backend = {
.name = "Linux usbfs",
.caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER,
.init = op_init,
@@ -2695,6 +2854,7 @@ const struct usbi_os_backend linux_usbfs_backend = {
.get_config_descriptor = op_get_config_descriptor,
.get_config_descriptor_by_value = op_get_config_descriptor_by_value,
.wrap_sys_device = op_wrap_sys_device,
.open = op_open,
.close = op_close,
.get_configuration = op_get_configuration,
+3 -2
View File
@@ -81,10 +81,11 @@ struct usbfs_iso_packet_desc {
unsigned int status;
};
#define MAX_ISO_BUFFER_LENGTH 49152 * 128
#define MAX_BULK_BUFFER_LENGTH 16384
#define MAX_CTRL_BUFFER_LENGTH 4096
#define MAX_ISO_PACKETS_PER_URB 128
struct usbfs_urb {
unsigned char type;
unsigned char endpoint;
@@ -186,7 +187,7 @@ void linux_device_disconnected(uint8_t busnum, uint8_t devaddr);
int linux_get_device_address (struct libusb_context *ctx, int detached,
uint8_t *busnum, uint8_t *devaddr, const char *dev_node,
const char *sys_name);
const char *sys_name, int fd);
int linux_enumerate_device(struct libusb_context *ctx,
uint8_t busnum, uint8_t devaddr, const char *sysfs_dir);
+8 -3
View File
@@ -86,11 +86,12 @@ static int _sync_control_transfer(struct usbi_transfer *);
static int _sync_gen_transfer(struct usbi_transfer *);
static int _access_endpoint(struct libusb_transfer *);
const struct usbi_os_backend netbsd_backend = {
const struct usbi_os_backend usbi_backend = {
"Synchronous NetBSD backend",
0,
NULL, /* init() */
NULL, /* exit() */
NULL, /* set_option() */
netbsd_get_device_list,
NULL, /* hotplug_poll */
netbsd_open,
@@ -131,6 +132,7 @@ const struct usbi_os_backend netbsd_backend = {
netbsd_handle_transfer_completion,
netbsd_clock_gettime,
0, /* context_priv_size */
sizeof(struct device_priv),
sizeof(struct handle_priv),
0, /* transfer_priv_size */
@@ -212,8 +214,9 @@ error:
int
netbsd_open(struct libusb_device_handle *handle)
{
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
int i;
dpriv->fd = open(dpriv->devnode, O_RDWR);
if (dpriv->fd < 0) {
@@ -222,6 +225,9 @@ netbsd_open(struct libusb_device_handle *handle)
return _errno_to_libusb(errno);
}
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
hpriv->endpoints[i] = -1;
usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd);
return (LIBUSB_SUCCESS);
@@ -230,7 +236,6 @@ netbsd_open(struct libusb_device_handle *handle)
void
netbsd_close(struct libusb_device_handle *handle)
{
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
usbi_dbg("close: fd %d", dpriv->fd);
+3 -3
View File
@@ -89,11 +89,12 @@ static int _access_endpoint(struct libusb_transfer *);
static int _bus_open(int);
const struct usbi_os_backend openbsd_backend = {
const struct usbi_os_backend usbi_backend = {
"Synchronous OpenBSD backend",
0,
NULL, /* init() */
NULL, /* exit() */
NULL, /* set_option() */
obsd_get_device_list,
NULL, /* hotplug_poll */
obsd_open,
@@ -134,6 +135,7 @@ const struct usbi_os_backend openbsd_backend = {
obsd_handle_transfer_completion,
obsd_clock_gettime,
0, /* context_priv_size */
sizeof(struct device_priv),
sizeof(struct handle_priv),
0, /* transfer_priv_size */
@@ -246,7 +248,6 @@ obsd_get_device_list(struct libusb_context * ctx,
int
obsd_open(struct libusb_device_handle *handle)
{
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
char devnode[16];
@@ -270,7 +271,6 @@ obsd_open(struct libusb_device_handle *handle)
void
obsd_close(struct libusb_device_handle *handle)
{
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
if (dpriv->devname) {
+36 -5
View File
@@ -29,25 +29,56 @@
int usbi_pipe(int pipefd[2])
{
#if defined(HAVE_PIPE2)
int ret = pipe2(pipefd, O_CLOEXEC);
#else
int ret = pipe(pipefd);
#endif
if (ret != 0) {
usbi_err(NULL, "failed to create pipe (%d)", errno);
return ret;
}
#if !defined(HAVE_PIPE2) && defined(FD_CLOEXEC)
ret = fcntl(pipefd[0], F_GETFD);
if (ret == -1) {
usbi_err(NULL, "failed to get pipe fd flags (%d)", errno);
goto err_close_pipe;
}
ret = fcntl(pipefd[0], F_SETFD, ret | FD_CLOEXEC);
if (ret == -1) {
usbi_err(NULL, "failed to set pipe fd flags (%d)", errno);
goto err_close_pipe;
}
ret = fcntl(pipefd[1], F_GETFD);
if (ret == -1) {
usbi_err(NULL, "failed to get pipe fd flags (%d)", errno);
goto err_close_pipe;
}
ret = fcntl(pipefd[1], F_SETFD, ret | FD_CLOEXEC);
if (ret == -1) {
usbi_err(NULL, "failed to set pipe fd flags (%d)", errno);
goto err_close_pipe;
}
#endif
ret = fcntl(pipefd[1], F_GETFL);
if (ret == -1) {
usbi_dbg("Failed to get pipe fd flags: %d", errno);
usbi_err(NULL, "failed to get pipe fd status flags (%d)", errno);
goto err_close_pipe;
}
ret = fcntl(pipefd[1], F_SETFL, ret | O_NONBLOCK);
if (ret != 0) {
usbi_dbg("Failed to set non-blocking on new pipe: %d", errno);
if (ret == -1) {
usbi_err(NULL, "failed to set pipe fd status flags (%d)", errno);
goto err_close_pipe;
}
return 0;
err_close_pipe:
usbi_close(pipefd[0]);
usbi_close(pipefd[1]);
close(pipefd[0]);
close(pipefd[1]);
return ret;
}
+3
View File
@@ -8,4 +8,7 @@
int usbi_pipe(int pipefd[2]);
#define usbi_inc_fds_ref(x, y)
#define usbi_dec_fds_ref(x, y)
#endif /* LIBUSB_POLL_POSIX_H */
+263 -584
View File
@@ -1,9 +1,6 @@
/*
* poll_windows: poll compatibility wrapper for Windows
* Copyright © 2012-2013 RealVNC Ltd.
* Copyright © 2009-2010 Pete Batard <[email protected]>
* With contributions from Michael Plante, Orin Eman et al.
* Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
* Copyright © 2017 Chris Dickens <[email protected]>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -31,9 +28,6 @@
* - obtain a Windows HANDLE to a file or device that has been opened in
* OVERLAPPED mode
* - call usbi_create_fd with this handle to obtain a custom fd.
* Note that if you need simultaneous R/W access, you need to call create_fd
* twice, once in RW_READ and once in RW_WRITE mode to obtain 2 separate
* pollable fds
* - leave the core functions call the poll routine and flag POLLIN/POLLOUT
*
* The pipe pollable synchronous I/O works using the overlapped event associated
@@ -42,465 +36,176 @@
*/
#include <config.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "libusbi.h"
// Uncomment to debug the polling layer
//#define DEBUG_POLL_WINDOWS
#if defined(DEBUG_POLL_WINDOWS)
#define poll_dbg usbi_dbg
#else
// MSVC++ < 2005 cannot use a variadic argument and non MSVC
// compilers produce warnings if parenthesis are omitted.
#if defined(_MSC_VER) && (_MSC_VER < 1400)
#define poll_dbg
#else
#define poll_dbg(...)
#endif
#endif
#if defined(_PREFAST_)
#pragma warning(disable:28719)
#endif
#define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0)
#include "windows_common.h"
// public fd data
const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, NULL, NULL, RW_NONE};
struct winfd poll_fd[MAX_FDS];
// internal fd data
struct {
CRITICAL_SECTION mutex; // lock for fds
// Additional variables for XP CancelIoEx partial emulation
HANDLE original_handle;
DWORD thread_id;
} _poll_fd[MAX_FDS];
const struct winfd INVALID_WINFD = { -1, NULL };
// globals
BOOLEAN is_polling_set = FALSE;
LONG pipe_number = 0;
static volatile LONG compat_spinlock = 0;
// private data
struct file_descriptor {
enum fd_type { FD_TYPE_PIPE, FD_TYPE_TRANSFER } type;
OVERLAPPED overlapped;
int refcount;
};
#if !defined(_WIN32_WCE)
// CancelIoEx, available on Vista and later only, provides the ability to cancel
// a single transfer (OVERLAPPED) when used. As it may not be part of any of the
// platform headers, we hook into the Kernel32 system DLL directly to seek it.
static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
#define Use_Duplicate_Handles (pCancelIoEx == NULL)
static usbi_mutex_static_t fd_table_lock = USBI_MUTEX_INITIALIZER;
static struct file_descriptor *fd_table[MAX_FDS];
static inline void setup_cancel_io(void)
static struct file_descriptor *create_fd(enum fd_type type)
{
HMODULE hKernel32 = GetModuleHandleA("KERNEL32");
if (hKernel32 != NULL) {
pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
GetProcAddress(hKernel32, "CancelIoEx");
}
usbi_dbg("Will use CancelIo%s for I/O cancellation",
Use_Duplicate_Handles?"":"Ex");
}
static inline BOOL cancel_io(int _index)
{
if ((_index < 0) || (_index >= MAX_FDS)) {
return FALSE;
}
if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
|| (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
return TRUE;
}
if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
// Cancel outstanding transfer via the specific callback
(*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
return TRUE;
}
if (pCancelIoEx != NULL) {
return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped);
}
if (_poll_fd[_index].thread_id == GetCurrentThreadId()) {
return CancelIo(poll_fd[_index].handle);
}
usbi_warn(NULL, "Unable to cancel I/O that was started from another thread");
return FALSE;
}
#else
#define Use_Duplicate_Handles FALSE
static __inline void setup_cancel_io()
{
// No setup needed on WinCE
}
static __inline BOOL cancel_io(int _index)
{
if ((_index < 0) || (_index >= MAX_FDS)) {
return FALSE;
}
if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
|| (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
return TRUE;
}
if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
// Cancel outstanding transfer via the specific callback
(*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
}
return TRUE;
}
#endif
// Init
void init_polling(void)
{
int i;
while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
SleepEx(0, TRUE);
}
if (!is_polling_set) {
setup_cancel_io();
for (i=0; i<MAX_FDS; i++) {
poll_fd[i] = INVALID_WINFD;
_poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
_poll_fd[i].thread_id = 0;
InitializeCriticalSection(&_poll_fd[i].mutex);
}
is_polling_set = TRUE;
}
InterlockedExchange((LONG *)&compat_spinlock, 0);
}
// Internal function to retrieve the table index (and lock the fd mutex)
static int _fd_to_index_and_lock(int fd)
{
int i;
if (fd < 0)
return -1;
for (i=0; i<MAX_FDS; i++) {
if (poll_fd[i].fd == fd) {
EnterCriticalSection(&_poll_fd[i].mutex);
// fd might have changed before we got to critical
if (poll_fd[i].fd != fd) {
LeaveCriticalSection(&_poll_fd[i].mutex);
continue;
}
return i;
}
}
return -1;
}
static OVERLAPPED *create_overlapped(void)
{
OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
if (overlapped == NULL) {
struct file_descriptor *fd = calloc(1, sizeof(*fd));
if (fd == NULL)
return NULL;
fd->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (fd->overlapped.hEvent == NULL) {
free(fd);
return NULL;
}
overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(overlapped->hEvent == NULL) {
free (overlapped);
return NULL;
}
return overlapped;
fd->type = type;
fd->refcount = 1;
return fd;
}
static void free_overlapped(OVERLAPPED *overlapped)
static void free_fd(struct file_descriptor *fd)
{
if (overlapped == NULL)
return;
if ( (overlapped->hEvent != 0)
&& (overlapped->hEvent != INVALID_HANDLE_VALUE) ) {
CloseHandle(overlapped->hEvent);
}
free(overlapped);
}
void exit_polling(void)
{
int i;
while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
SleepEx(0, TRUE);
}
if (is_polling_set) {
is_polling_set = FALSE;
for (i=0; i<MAX_FDS; i++) {
// Cancel any async I/O (handle can be invalid)
cancel_io(i);
// If anything was pending on that I/O, it should be
// terminating, and we should be able to access the fd
// mutex lock before too long
EnterCriticalSection(&_poll_fd[i].mutex);
free_overlapped(poll_fd[i].overlapped);
if (Use_Duplicate_Handles) {
// Close duplicate handle
if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
CloseHandle(poll_fd[i].handle);
}
}
poll_fd[i] = INVALID_WINFD;
LeaveCriticalSection(&_poll_fd[i].mutex);
DeleteCriticalSection(&_poll_fd[i].mutex);
}
}
InterlockedExchange((LONG *)&compat_spinlock, 0);
CloseHandle(fd->overlapped.hEvent);
free(fd);
}
/*
* Create a fake pipe.
* As libusb only uses pipes for signaling, all we need from a pipe is an
* event. To that extent, we create a single wfd and overlapped as a means
* to access that event.
*/
int usbi_pipe(int filedes[2])
{
int i;
OVERLAPPED* overlapped;
CHECK_INIT_POLLING;
overlapped = create_overlapped();
if (overlapped == NULL) {
return -1;
}
// The overlapped must have status pending for signaling to work in poll
overlapped->Internal = STATUS_PENDING;
overlapped->InternalHigh = 0;
for (i=0; i<MAX_FDS; i++) {
if (poll_fd[i].fd < 0) {
EnterCriticalSection(&_poll_fd[i].mutex);
// fd might have been allocated before we got to critical
if (poll_fd[i].fd >= 0) {
LeaveCriticalSection(&_poll_fd[i].mutex);
continue;
}
// Use index as the unique fd number
poll_fd[i].fd = i;
// Read end of the "pipe"
filedes[0] = poll_fd[i].fd;
// We can use the same handle for both ends
filedes[1] = filedes[0];
poll_fd[i].handle = DUMMY_HANDLE;
poll_fd[i].overlapped = overlapped;
// There's no polling on the write end, so we just use READ for our needs
poll_fd[i].rw = RW_READ;
_poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
LeaveCriticalSection(&_poll_fd[i].mutex);
return 0;
}
}
free_overlapped(overlapped);
return -1;
}
/*
* Create both an fd and an OVERLAPPED from an open Windows handle, so that
* it can be used with our polling function
* Create both an fd and an OVERLAPPED, so that it can be used with our
* polling function
* The handle MUST support overlapped transfers (usually requires CreateFile
* with FILE_FLAG_OVERLAPPED)
* Return a pollable file descriptor struct, or INVALID_WINFD on error
*
* Note that the fd returned by this function is a per-transfer fd, rather
* than a per-session fd and cannot be used for anything else but our
* custom functions (the fd itself points to the NUL: device)
* custom functions.
* if you plan to do R/W on the same handle, you MUST create 2 fds: one for
* read and one for write. Using a single R/W fd is unsupported and will
* produce unexpected results
*/
struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer *itransfer, cancel_transfer *cancel_fn)
struct winfd usbi_create_fd(void)
{
int i;
struct winfd wfd = INVALID_WINFD;
OVERLAPPED* overlapped = NULL;
CHECK_INIT_POLLING;
if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) {
return INVALID_WINFD;
}
wfd.itransfer = itransfer;
wfd.cancel_fn = cancel_fn;
if ((access_mode != RW_READ) && (access_mode != RW_WRITE)) {
usbi_warn(NULL, "only one of RW_READ or RW_WRITE are supported. "
"If you want to poll for R/W simultaneously, create multiple fds from the same handle.");
return INVALID_WINFD;
}
if (access_mode == RW_READ) {
wfd.rw = RW_READ;
} else {
wfd.rw = RW_WRITE;
}
overlapped = create_overlapped();
if(overlapped == NULL) {
return INVALID_WINFD;
}
for (i=0; i<MAX_FDS; i++) {
if (poll_fd[i].fd < 0) {
EnterCriticalSection(&_poll_fd[i].mutex);
// fd might have been removed before we got to critical
if (poll_fd[i].fd >= 0) {
LeaveCriticalSection(&_poll_fd[i].mutex);
continue;
}
// Use index as the unique fd number
wfd.fd = i;
// Attempt to emulate some of the CancelIoEx behaviour on platforms
// that don't have it
if (Use_Duplicate_Handles) {
_poll_fd[i].thread_id = GetCurrentThreadId();
if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
&wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
usbi_dbg("could not duplicate handle for CancelIo - using original one");
wfd.handle = handle;
// Make sure we won't close the original handle on fd deletion then
_poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
} else {
_poll_fd[i].original_handle = handle;
}
} else {
wfd.handle = handle;
}
wfd.overlapped = overlapped;
memcpy(&poll_fd[i], &wfd, sizeof(struct winfd));
LeaveCriticalSection(&_poll_fd[i].mutex);
return wfd;
}
}
free_overlapped(overlapped);
return INVALID_WINFD;
}
static void _free_index(int _index)
{
// Cancel any async IO (Don't care about the validity of our handles for this)
cancel_io(_index);
// close the duplicate handle (if we have an actual duplicate)
if (Use_Duplicate_Handles) {
if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) {
CloseHandle(poll_fd[_index].handle);
}
_poll_fd[_index].original_handle = INVALID_HANDLE_VALUE;
_poll_fd[_index].thread_id = 0;
}
free_overlapped(poll_fd[_index].overlapped);
poll_fd[_index] = INVALID_WINFD;
}
/*
* Release a pollable file descriptor.
*
* Note that the associated Windows handle is not closed by this call
*/
void usbi_free_fd(struct winfd *wfd)
{
int _index;
CHECK_INIT_POLLING;
_index = _fd_to_index_and_lock(wfd->fd);
if (_index < 0) {
return;
}
_free_index(_index);
*wfd = INVALID_WINFD;
LeaveCriticalSection(&_poll_fd[_index].mutex);
}
/*
* The functions below perform various conversions between fd, handle and OVERLAPPED
*/
struct winfd fd_to_winfd(int fd)
{
int i;
struct file_descriptor *fd;
struct winfd wfd;
CHECK_INIT_POLLING;
if (fd < 0)
fd = create_fd(FD_TYPE_TRANSFER);
if (fd == NULL)
return INVALID_WINFD;
for (i=0; i<MAX_FDS; i++) {
if (poll_fd[i].fd == fd) {
EnterCriticalSection(&_poll_fd[i].mutex);
// fd might have been deleted before we got to critical
if (poll_fd[i].fd != fd) {
LeaveCriticalSection(&_poll_fd[i].mutex);
continue;
}
memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
LeaveCriticalSection(&_poll_fd[i].mutex);
return wfd;
}
usbi_mutex_static_lock(&fd_table_lock);
for (wfd.fd = 0; wfd.fd < MAX_FDS; wfd.fd++) {
if (fd_table[wfd.fd] != NULL)
continue;
fd_table[wfd.fd] = fd;
break;
}
return INVALID_WINFD;
usbi_mutex_static_unlock(&fd_table_lock);
if (wfd.fd == MAX_FDS) {
free_fd(fd);
return INVALID_WINFD;
}
wfd.overlapped = &fd->overlapped;
return wfd;
}
struct winfd handle_to_winfd(HANDLE handle)
int usbi_inc_fds_ref(struct pollfd *fds, unsigned int nfds)
{
int i;
struct winfd wfd;
CHECK_INIT_POLLING;
if ((handle == 0) || (handle == INVALID_HANDLE_VALUE))
return INVALID_WINFD;
for (i=0; i<MAX_FDS; i++) {
if (poll_fd[i].handle == handle) {
EnterCriticalSection(&_poll_fd[i].mutex);
// fd might have been deleted before we got to critical
if (poll_fd[i].handle != handle) {
LeaveCriticalSection(&_poll_fd[i].mutex);
continue;
}
memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
LeaveCriticalSection(&_poll_fd[i].mutex);
return wfd;
}
int n;
usbi_mutex_static_lock(&fd_table_lock);
for (n = 0; n < nfds; ++n) {
fd_table[fds[n].fd]->refcount++;
}
return INVALID_WINFD;
usbi_mutex_static_unlock(&fd_table_lock);
}
struct winfd overlapped_to_winfd(OVERLAPPED* overlapped)
int usbi_dec_fds_ref(struct pollfd *fds, unsigned int nfds)
{
int i;
struct winfd wfd;
int n;
struct file_descriptor *fd;
CHECK_INIT_POLLING;
if (overlapped == NULL)
return INVALID_WINFD;
for (i=0; i<MAX_FDS; i++) {
if (poll_fd[i].overlapped == overlapped) {
EnterCriticalSection(&_poll_fd[i].mutex);
// fd might have been deleted before we got to critical
if (poll_fd[i].overlapped != overlapped) {
LeaveCriticalSection(&_poll_fd[i].mutex);
continue;
usbi_mutex_static_lock(&fd_table_lock);
for (n = 0; n < nfds; ++n) {
fd = fd_table[fds[n].fd];
fd->refcount--;
if (fd->refcount == 0)
{
if (fd->type == FD_TYPE_PIPE) {
// InternalHigh is our reference count
fd->overlapped.InternalHigh--;
if (fd->overlapped.InternalHigh == 0)
free_fd(fd);
}
memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
LeaveCriticalSection(&_poll_fd[i].mutex);
return wfd;
else {
free_fd(fd);
}
fd_table[fds[n].fd] = NULL;
}
}
return INVALID_WINFD;
usbi_mutex_static_unlock(&fd_table_lock);
}
static int check_pollfds(struct pollfd *fds, unsigned int nfds,
HANDLE *wait_handles, DWORD *nb_wait_handles)
{
struct file_descriptor *fd;
unsigned int n;
int nready = 0;
usbi_mutex_static_lock(&fd_table_lock);
for (n = 0; n < nfds; ++n) {
fds[n].revents = 0;
// Keep it simple - only allow either POLLIN *or* POLLOUT
assert((fds[n].events == POLLIN) || (fds[n].events == POLLOUT));
if ((fds[n].events != POLLIN) && (fds[n].events != POLLOUT)) {
fds[n].revents = POLLNVAL;
nready++;
continue;
}
if ((fds[n].fd >= 0) && (fds[n].fd < MAX_FDS))
fd = fd_table[fds[n].fd];
else
fd = NULL;
assert(fd != NULL);
if (fd == NULL) {
fds[n].revents = POLLNVAL;
nready++;
continue;
}
if (HasOverlappedIoCompleted(&fd->overlapped)
&& (WaitForSingleObject(fd->overlapped.hEvent, 0) == WAIT_OBJECT_0)) {
fds[n].revents = fds[n].events;
nready++;
} else if (wait_handles != NULL) {
if (*nb_wait_handles == MAXIMUM_WAIT_OBJECTS) {
usbi_warn(NULL, "too many HANDLEs to wait on");
continue;
}
wait_handles[*nb_wait_handles] = fd->overlapped.hEvent;
(*nb_wait_handles)++;
}
}
usbi_mutex_static_unlock(&fd_table_lock);
return nready;
}
/*
* POSIX poll equivalent, using Windows OVERLAPPED
* Currently, this function only accepts one of POLLIN or POLLOUT per fd
@@ -508,143 +213,121 @@ struct winfd overlapped_to_winfd(OVERLAPPED* overlapped)
*/
int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
{
unsigned i;
int _index, object_index, triggered;
HANDLE *handles_to_wait_on;
int *handle_to_index;
DWORD nb_handles_to_wait_on = 0;
HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
DWORD nb_wait_handles = 0;
DWORD ret;
int nready;
CHECK_INIT_POLLING;
triggered = 0;
handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE)); // +1 for fd_update
handle_to_index = (int*) calloc(nfds, sizeof(int));
if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) {
errno = ENOMEM;
triggered = -1;
goto poll_exit;
}
for (i = 0; i < nfds; ++i) {
fds[i].revents = 0;
// Only one of POLLIN or POLLOUT can be selected with this version of poll (not both)
if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) {
fds[i].revents |= POLLERR;
errno = EACCES;
usbi_warn(NULL, "unsupported set of events");
triggered = -1;
goto poll_exit;
}
_index = _fd_to_index_and_lock(fds[i].fd);
poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events);
if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
|| (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) {
fds[i].revents |= POLLNVAL | POLLERR;
errno = EBADF;
if (_index >= 0) {
LeaveCriticalSection(&_poll_fd[_index].mutex);
}
usbi_warn(NULL, "invalid fd");
triggered = -1;
goto poll_exit;
}
// IN or OUT must match our fd direction
if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) {
fds[i].revents |= POLLNVAL | POLLERR;
errno = EBADF;
usbi_warn(NULL, "attempted POLLIN on fd without READ access");
LeaveCriticalSection(&_poll_fd[_index].mutex);
triggered = -1;
goto poll_exit;
}
if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) {
fds[i].revents |= POLLNVAL | POLLERR;
errno = EBADF;
usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access");
LeaveCriticalSection(&_poll_fd[_index].mutex);
triggered = -1;
goto poll_exit;
}
// The following macro only works if overlapped I/O was reported pending
if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped))
|| (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) {
poll_dbg(" completed");
// checks above should ensure this works:
fds[i].revents = fds[i].events;
triggered++;
} else {
handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent;
handle_to_index[nb_handles_to_wait_on] = i;
nb_handles_to_wait_on++;
}
LeaveCriticalSection(&_poll_fd[_index].mutex);
}
nready = check_pollfds(fds, nfds, wait_handles, &nb_wait_handles);
// If nothing was triggered, wait on all fds that require it
if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) {
if (timeout < 0) {
poll_dbg("starting infinite wait for %u handles...", (unsigned int)nb_handles_to_wait_on);
} else {
poll_dbg("starting %d ms wait for %u handles...", timeout, (unsigned int)nb_handles_to_wait_on);
}
ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on,
FALSE, (timeout<0)?INFINITE:(DWORD)timeout);
object_index = ret-WAIT_OBJECT_0;
if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) {
poll_dbg(" completed after wait");
i = handle_to_index[object_index];
_index = _fd_to_index_and_lock(fds[i].fd);
fds[i].revents = fds[i].events;
triggered++;
if (_index >= 0) {
LeaveCriticalSection(&_poll_fd[_index].mutex);
}
} else if (ret == WAIT_TIMEOUT) {
poll_dbg(" timed out");
triggered = 0; // 0 = timeout
} else {
errno = EIO;
triggered = -1; // error
if ((nready == 0) && (nb_wait_handles != 0) && (timeout != 0)) {
ret = WaitForMultipleObjects(nb_wait_handles, wait_handles,
FALSE, (timeout < 0) ? INFINITE : (DWORD)timeout);
if (ret < (WAIT_OBJECT_0 + nb_wait_handles)) {
nready = check_pollfds(fds, nfds, NULL, NULL);
} else if (ret != WAIT_TIMEOUT) {
if (ret == WAIT_FAILED)
usbi_err(NULL, "WaitForMultipleObjects failed: %u", (unsigned int)GetLastError());
nready = -1;
}
}
poll_exit:
if (handles_to_wait_on != NULL) {
free(handles_to_wait_on);
}
if (handle_to_index != NULL) {
free(handle_to_index);
}
return triggered;
return nready;
}
/*
* close a fake pipe fd
* close a fake file descriptor
*/
int usbi_close(int fd)
int usbi_close(int _fd)
{
int _index;
int r = -1;
struct file_descriptor *fd;
CHECK_INIT_POLLING;
if (_fd < 0 || _fd >= MAX_FDS)
goto err_badfd;
_index = _fd_to_index_and_lock(fd);
usbi_mutex_static_lock(&fd_table_lock);
fd = fd_table[_fd];
fd->refcount--;
if(fd->refcount==0)
{ fd_table[_fd] = NULL;
if (_index < 0) {
errno = EBADF;
} else {
free_overlapped(poll_fd[_index].overlapped);
poll_fd[_index] = INVALID_WINFD;
LeaveCriticalSection(&_poll_fd[_index].mutex);
if (fd->type == FD_TYPE_PIPE) {
// InternalHigh is our reference count
fd->overlapped.InternalHigh--;
if (fd->overlapped.InternalHigh == 0)
free_fd(fd);
}
else {
free_fd(fd);
}
}
return r;
usbi_mutex_static_unlock(&fd_table_lock);
if (fd == NULL)
goto err_badfd;
return 0;
err_badfd:
errno = EBADF;
return -1;
}
/*
* Create a fake pipe.
* As libusb only uses pipes for signaling, all we need from a pipe is an
* event. To that extent, we create a single wfd and overlapped as a means
* to access that event.
*/
int usbi_pipe(int filedes[2])
{
struct file_descriptor *fd;
int r_fd = -1, w_fd = -1;
int i;
fd = create_fd(FD_TYPE_PIPE);
if (fd == NULL) {
errno = ENOMEM;
return -1;
}
// Use InternalHigh as a reference count
fd->overlapped.Internal = STATUS_PENDING;
fd->overlapped.InternalHigh = 2;
usbi_mutex_static_lock(&fd_table_lock);
do {
for (i = 0; i < MAX_FDS; i++) {
if (fd_table[i] != NULL)
continue;
if (r_fd == -1) {
r_fd = i;
} else if (w_fd == -1) {
w_fd = i;
break;
}
}
if (i == MAX_FDS)
break;
fd_table[r_fd] = fd;
fd_table[w_fd] = fd;
} while (0);
usbi_mutex_static_unlock(&fd_table_lock);
if (i == MAX_FDS) {
free_fd(fd);
errno = EMFILE;
return -1;
}
filedes[0] = r_fd;
filedes[1] = w_fd;
return 0;
}
/*
@@ -652,35 +335,37 @@ int usbi_close(int fd)
*/
ssize_t usbi_write(int fd, const void *buf, size_t count)
{
int _index;
int error = EBADF;
UNUSED(buf);
CHECK_INIT_POLLING;
if (fd < 0 || fd >= MAX_FDS)
goto err_out;
if (count != sizeof(unsigned char)) {
usbi_err(NULL, "this function should only used for signaling");
return -1;
error = EINVAL;
goto err_out;
}
_index = _fd_to_index_and_lock(fd);
if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) {
errno = EBADF;
if (_index >= 0) {
LeaveCriticalSection(&_poll_fd[_index].mutex);
}
return -1;
usbi_mutex_static_lock(&fd_table_lock);
if ((fd_table[fd] != NULL) && (fd_table[fd]->type == FD_TYPE_PIPE)) {
assert(fd_table[fd]->overlapped.Internal == STATUS_PENDING);
assert(fd_table[fd]->overlapped.InternalHigh == 2);
fd_table[fd]->overlapped.Internal = STATUS_WAIT_0;
SetEvent(fd_table[fd]->overlapped.hEvent);
error = 0;
}
usbi_mutex_static_unlock(&fd_table_lock);
poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, (unsigned int)GetCurrentThreadId());
SetEvent(poll_fd[_index].overlapped->hEvent);
poll_fd[_index].overlapped->Internal = STATUS_WAIT_0;
// If two threads write on the pipe at the same time, we need to
// process two separate reads => use the overlapped as a counter
poll_fd[_index].overlapped->InternalHigh++;
if (error)
goto err_out;
LeaveCriticalSection(&_poll_fd[_index].mutex);
return sizeof(unsigned char);
err_out:
errno = error;
return -1;
}
/*
@@ -688,41 +373,35 @@ ssize_t usbi_write(int fd, const void *buf, size_t count)
*/
ssize_t usbi_read(int fd, void *buf, size_t count)
{
int _index;
ssize_t r = -1;
int error = EBADF;
UNUSED(buf);
CHECK_INIT_POLLING;
if (fd < 0 || fd >= MAX_FDS)
goto err_out;
if (count != sizeof(unsigned char)) {
usbi_err(NULL, "this function should only used for signaling");
return -1;
error = EINVAL;
goto err_out;
}
_index = _fd_to_index_and_lock(fd);
if (_index < 0) {
errno = EBADF;
return -1;
usbi_mutex_static_lock(&fd_table_lock);
if ((fd_table[fd] != NULL) && (fd_table[fd]->type == FD_TYPE_PIPE)) {
assert(fd_table[fd]->overlapped.Internal == STATUS_WAIT_0);
assert(fd_table[fd]->overlapped.InternalHigh == 2);
fd_table[fd]->overlapped.Internal = STATUS_PENDING;
ResetEvent(fd_table[fd]->overlapped.hEvent);
error = 0;
}
usbi_mutex_static_unlock(&fd_table_lock);
if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) {
usbi_warn(NULL, "waiting for event failed: %u", (unsigned int)GetLastError());
errno = EIO;
goto out;
}
if (error)
goto err_out;
poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, (unsigned int)GetCurrentThreadId());
poll_fd[_index].overlapped->InternalHigh--;
// Don't reset unless we don't have any more events to process
if (poll_fd[_index].overlapped->InternalHigh <= 0) {
ResetEvent(poll_fd[_index].overlapped->hEvent);
poll_fd[_index].overlapped->Internal = STATUS_PENDING;
}
return sizeof(unsigned char);
r = sizeof(unsigned char);
out:
LeaveCriticalSection(&_poll_fd[_index].mutex);
return r;
err_out:
errno = error;
return -1;
}
+11 -42
View File
@@ -2,6 +2,7 @@
* Windows compat: POSIX compatibility wrapper
* Copyright © 2012-2013 RealVNC Ltd.
* Copyright © 2009-2010 Pete Batard <[email protected]>
* Copyright © 2016-2018 Chris Dickens <[email protected]>
* With contributions from Michael Plante, Orin Eman et al.
* Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
*
@@ -40,21 +41,6 @@
#define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2)
/* Windows versions */
enum windows_version {
WINDOWS_CE = -2,
WINDOWS_UNDEFINED = -1,
WINDOWS_UNSUPPORTED = 0,
WINDOWS_XP = 0x51,
WINDOWS_2003 = 0x52, // Also XP x64
WINDOWS_VISTA = 0x60,
WINDOWS_7 = 0x61,
WINDOWS_8 = 0x62,
WINDOWS_8_1_OR_LATER = 0x63,
WINDOWS_MAX
};
extern int windows_version;
#define MAX_FDS 256
#define POLLIN 0x0001 /* There is data to read */
@@ -65,45 +51,28 @@ extern int windows_version;
#define POLLNVAL 0x0020 /* Invalid request: fd not open */
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
// access modes
enum rw_type {
RW_NONE,
RW_READ,
RW_WRITE,
};
// fd struct that can be used for polling on Windows
typedef int cancel_transfer(struct usbi_transfer *itransfer);
struct winfd {
int fd; // what's exposed to libusb core
HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it
OVERLAPPED* overlapped; // what will report our I/O status
struct usbi_transfer *itransfer; // Associated transfer, or NULL if completed
cancel_transfer *cancel_fn; // Function pointer to cancel transfer API
enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH)
int fd; // what's exposed to libusb core
OVERLAPPED *overlapped; // what will report our I/O status
};
extern const struct winfd INVALID_WINFD;
struct winfd usbi_create_fd(void);
int usbi_pipe(int pipefd[2]);
int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout);
ssize_t usbi_write(int fd, const void *buf, size_t count);
ssize_t usbi_read(int fd, void *buf, size_t count);
int usbi_close(int fd);
void init_polling(void);
void exit_polling(void);
struct winfd usbi_create_fd(HANDLE handle, int access_mode,
struct usbi_transfer *transfer, cancel_transfer *cancel_fn);
void usbi_free_fd(struct winfd* winfd);
struct winfd fd_to_winfd(int fd);
struct winfd handle_to_winfd(HANDLE handle);
struct winfd overlapped_to_winfd(OVERLAPPED* overlapped);
int usbi_inc_fds_ref(struct pollfd *fds, unsigned int nfds);
int usbi_dec_fds_ref(struct pollfd *fds, unsigned int nfds);
/*
* Timeval operations
+518 -115
View File
@@ -21,6 +21,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/list.h>
#include <sys/stat.h>
#include <strings.h>
#include <errno.h>
@@ -28,21 +29,34 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wait.h>
#include <unistd.h>
#include <aio.h>
#include <libdevinfo.h>
#include <sys/nvpair.h>
#include <sys/devctl.h>
#include <sys/usb/clients/ugen/usb_ugen.h>
#include <errno.h>
#include <sys/usb/usba.h>
#include <sys/pci.h>
#include "libusbi.h"
#include "sunos_usb.h"
#define UPDATEDRV_PATH "/usr/sbin/update_drv"
#define UPDATEDRV "update_drv"
typedef list_t string_list_t;
typedef struct string_node {
char *string;
list_node_t link;
} string_node_t;
/*
* Backend functions
*/
static int sunos_init(struct libusb_context *);
static void sunos_exit(void);
static void sunos_exit(struct libusb_context *);
static int sunos_get_device_list(struct libusb_context *,
struct discovered_devs **);
static int sunos_open(struct libusb_device_handle *);
@@ -67,6 +81,162 @@ static int sunos_cancel_transfer(struct usbi_transfer *);
static void sunos_clear_transfer_priv(struct usbi_transfer *);
static int sunos_handle_transfer_completion(struct usbi_transfer *);
static int sunos_clock_gettime(int, struct timespec *);
static int sunos_kernel_driver_active(struct libusb_device_handle *, int interface);
static int sunos_detach_kernel_driver (struct libusb_device_handle *dev, int interface_number);
static int sunos_attach_kernel_driver (struct libusb_device_handle *dev, int interface_number);
static int sunos_usb_open_ep0(sunos_dev_handle_priv_t *hpriv, sunos_dev_priv_t *dpriv);
static int sunos_usb_ioctl(struct libusb_device *dev, int cmd);
static struct devctl_iocdata iocdata;
static int sunos_get_link(di_devlink_t devlink, void *arg)
{
walk_link_t *larg = (walk_link_t *)arg;
const char *p;
const char *q;
if (larg->path) {
char *content = (char *)di_devlink_content(devlink);
char *start = strstr(content, "/devices/");
start += strlen("/devices");
usbi_dbg("%s", start);
/* line content must have minor node */
if (start == NULL ||
strncmp(start, larg->path, larg->len) != 0 ||
start[larg->len] != ':')
return (DI_WALK_CONTINUE);
}
p = di_devlink_path(devlink);
q = strrchr(p, '/');
usbi_dbg("%s", q);
*(larg->linkpp) = strndup(p, strlen(p) - strlen(q));
return (DI_WALK_TERMINATE);
}
static int sunos_physpath_to_devlink(
const char *node_path, const char *match, char **link_path)
{
walk_link_t larg;
di_devlink_handle_t hdl;
*link_path = NULL;
larg.linkpp = link_path;
if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
usbi_dbg("di_devlink_init failure");
return (-1);
}
larg.len = strlen(node_path);
larg.path = (char *)node_path;
(void) di_devlink_walk(hdl, match, NULL, DI_PRIMARY_LINK,
(void *)&larg, sunos_get_link);
(void) di_devlink_fini(&hdl);
if (*link_path == NULL) {
usbi_dbg("there is no devlink for this path");
return (-1);
}
return 0;
}
static int
sunos_usb_ioctl(struct libusb_device *dev, int cmd)
{
int fd;
nvlist_t *nvlist;
char *end;
char *phypath;
char *hubpath;
char path_arg[PATH_MAX];
sunos_dev_priv_t *dpriv;
devctl_ap_state_t devctl_ap_state;
dpriv = (sunos_dev_priv_t *)dev->os_priv;
phypath = dpriv->phypath;
end = strrchr(phypath, '/');
if (end == NULL)
return (-1);
hubpath = strndup(phypath, end - phypath);
if (hubpath == NULL)
return (-1);
end = strrchr(hubpath, '@');
if (end == NULL) {
free(hubpath);
return (-1);
}
end++;
usbi_dbg("unitaddr: %s", end);
nvlist_alloc(&nvlist, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
nvlist_add_int32(nvlist, "port", dev->port_number);
//find the hub path
snprintf(path_arg, sizeof(path_arg), "/devices%s:hubd", hubpath);
usbi_dbg("ioctl hub path: %s", path_arg);
fd = open(path_arg, O_RDONLY);
if (fd < 0) {
usbi_err(DEVICE_CTX(dev), "open failed: %d (%s)", errno, strerror(errno));
nvlist_free(nvlist);
free(hubpath);
return (-1);
}
memset(&iocdata, 0, sizeof(iocdata));
memset(&devctl_ap_state, 0, sizeof(devctl_ap_state));
nvlist_pack(nvlist, (char **)&iocdata.nvl_user, &iocdata.nvl_usersz, NV_ENCODE_NATIVE, 0);
iocdata.cmd = DEVCTL_AP_GETSTATE;
iocdata.flags = 0;
iocdata.c_nodename = "hub";
iocdata.c_unitaddr = end;
iocdata.cpyout_buf = &devctl_ap_state;
usbi_dbg("%p, %d", iocdata.nvl_user, iocdata.nvl_usersz);
errno = 0;
if (ioctl(fd, DEVCTL_AP_GETSTATE, &iocdata) == -1) {
usbi_err(DEVICE_CTX(dev), "ioctl failed: fd %d, cmd %x, errno %d (%s)",
fd, DEVCTL_AP_GETSTATE, errno, strerror(errno));
} else {
usbi_dbg("dev rstate: %d", devctl_ap_state.ap_rstate);
usbi_dbg("dev ostate: %d", devctl_ap_state.ap_ostate);
}
errno = 0;
iocdata.cmd = cmd;
if (ioctl(fd, (int)cmd, &iocdata) != 0) {
usbi_err(DEVICE_CTX(dev), "ioctl failed: fd %d, cmd %x, errno %d (%s)",
fd, cmd, errno, strerror(errno));
sleep(2);
}
close(fd);
free(iocdata.nvl_user);
nvlist_free(nvlist);
free(hubpath);
return (-errno);
}
static int
sunos_kernel_driver_active(struct libusb_device_handle *dev, int interface)
{
sunos_dev_priv_t *dpriv;
dpriv = (sunos_dev_priv_t *)dev->dev->os_priv;
usbi_dbg("%s", dpriv->ugenpath);
return (dpriv->ugenpath == NULL);
}
/*
* Private functions
@@ -79,20 +249,239 @@ static int sunos_init(struct libusb_context *ctx)
return (LIBUSB_SUCCESS);
}
static void sunos_exit(void)
static void sunos_exit(struct libusb_context *ctx)
{
usbi_dbg("");
}
static string_list_t *
sunos_new_string_list(void)
{
string_list_t *list;
list = calloc(1, sizeof(*list));
if (list != NULL)
list_create(list, sizeof(string_node_t),
offsetof(string_node_t, link));
return (list);
}
static int
sunos_append_to_string_list(string_list_t *list, const char *arg)
{
string_node_t *np;
np = calloc(1, sizeof(*np));
if (!np)
return (-1);
np->string = strdup(arg);
if (!np->string) {
free(np);
return (-1);
}
list_insert_tail(list, np);
return (0);
}
static void
sunos_free_string_list(string_list_t *list)
{
string_node_t *np;
while ((np = list_remove_head(list)) != NULL) {
free(np->string);
free(np);
}
free(list);
}
static char **
sunos_build_argv_list(string_list_t *list)
{
char **argv_list;
string_node_t *np;
int n;
n = 1; /* Start at 1 for NULL terminator */
for (np = list_head(list); np != NULL; np = list_next(list, np))
n++;
argv_list = calloc(n, sizeof(char *));
if (argv_list == NULL)
return NULL;
n = 0;
for (np = list_head(list); np != NULL; np = list_next(list, np))
argv_list[n++] = np->string;
return (argv_list);
}
static int
sunos_exec_command(struct libusb_context *ctx, const char *path,
string_list_t *list)
{
pid_t pid;
int status;
int waitstat;
int exit_status;
char **argv_list;
argv_list = sunos_build_argv_list(list);
if (argv_list == NULL)
return (-1);
pid = fork();
if (pid == 0) {
/* child */
execv(path, argv_list);
_exit(127);
} else if (pid > 0) {
/* parent */
do {
waitstat = waitpid(pid, &status, 0);
} while ((waitstat == -1 && errno == EINTR) ||
(waitstat == 0 && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (waitstat == 0) {
if (WIFEXITED(status))
exit_status = WEXITSTATUS(status);
else
exit_status = WTERMSIG(status);
} else {
usbi_err(ctx, "waitpid failed: errno %d (%s)", errno, strerror(errno));
exit_status = -1;
}
} else {
/* fork failed */
usbi_err(ctx, "fork failed: errno %d (%s)", errno, strerror(errno));
exit_status = -1;
}
free(argv_list);
return (exit_status);
}
static int
sunos_detach_kernel_driver(struct libusb_device_handle *dev_handle,
int interface_number)
{
struct libusb_context *ctx = HANDLE_CTX(dev_handle);
string_list_t *list;
char path_arg[PATH_MAX];
sunos_dev_priv_t *dpriv;
int r;
dpriv = (sunos_dev_priv_t *)dev_handle->dev->os_priv;
snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
usbi_dbg("%s", path_arg);
list = sunos_new_string_list();
if (list == NULL)
return (LIBUSB_ERROR_NO_MEM);
/* attach ugen driver */
r = 0;
r |= sunos_append_to_string_list(list, UPDATEDRV);
r |= sunos_append_to_string_list(list, "-a"); /* add rule */
r |= sunos_append_to_string_list(list, "-i"); /* specific device */
r |= sunos_append_to_string_list(list, path_arg); /* physical path */
r |= sunos_append_to_string_list(list, "ugen");
if (r) {
sunos_free_string_list(list);
return (LIBUSB_ERROR_NO_MEM);
}
r = sunos_exec_command(ctx, UPDATEDRV_PATH, list);
sunos_free_string_list(list);
if (r < 0)
return (LIBUSB_ERROR_OTHER);
/* reconfigure the driver node */
r = 0;
r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
if (r)
usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
snprintf(path_arg, sizeof(path_arg), "^usb/%x.%x", dpriv->dev_descr.idVendor,
dpriv->dev_descr.idProduct);
sunos_physpath_to_devlink(dpriv->phypath, path_arg, &dpriv->ugenpath);
if (access(dpriv->ugenpath, F_OK) == -1) {
usbi_err(HANDLE_CTX(dev_handle), "fail to detach kernel driver");
return (LIBUSB_ERROR_IO);
}
return sunos_usb_open_ep0((sunos_dev_handle_priv_t *)dev_handle->os_priv, dpriv);
}
static int
sunos_attach_kernel_driver(struct libusb_device_handle *dev_handle,
int interface_number)
{
struct libusb_context *ctx = HANDLE_CTX(dev_handle);
string_list_t *list;
char path_arg[PATH_MAX];
sunos_dev_priv_t *dpriv;
int r;
/* we open the dev in detach driver, so we need close it first. */
sunos_close(dev_handle);
dpriv = (sunos_dev_priv_t *)dev_handle->dev->os_priv;
snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
usbi_dbg("%s", path_arg);
list = sunos_new_string_list();
if (list == NULL)
return (LIBUSB_ERROR_NO_MEM);
/* detach ugen driver */
r = 0;
r |= sunos_append_to_string_list(list, UPDATEDRV);
r |= sunos_append_to_string_list(list, "-d"); /* add rule */
r |= sunos_append_to_string_list(list, "-i"); /* specific device */
r |= sunos_append_to_string_list(list, path_arg); /* physical path */
r |= sunos_append_to_string_list(list, "ugen");
if (r) {
sunos_free_string_list(list);
return (LIBUSB_ERROR_NO_MEM);
}
r = sunos_exec_command(ctx, UPDATEDRV_PATH, list);
sunos_free_string_list(list);
if (r < 0)
return (LIBUSB_ERROR_OTHER);
/* reconfigure the driver node */
r = 0;
r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
if (r)
usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
return 0;
}
static int
sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
{
int proplen;
int n, *addr, *port_prop;
int *i, n, *addr, *port_prop;
char *phypath;
uint8_t *rdata;
struct libusb_device_descriptor *descr;
sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
char match_str[PATH_MAX];
/* Device descriptors */
proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
@@ -137,7 +526,11 @@ sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
phypath = di_devfs_path(node);
if (phypath) {
dpriv->phypath = strdup(phypath);
snprintf(match_str, sizeof(match_str), "^usb/%x.%x", dpriv->dev_descr.idVendor, dpriv->dev_descr.idProduct);
usbi_dbg("match is %s", match_str);
sunos_physpath_to_devlink(dpriv->phypath, match_str, &dpriv->ugenpath);
di_devfs_path_free(phypath);
} else {
free(dpriv->raw_cfgdescr);
@@ -153,13 +546,13 @@ sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
}
/* speed */
if (di_prop_exists(DDI_DEV_T_ANY, node, "low-speed") == 1) {
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "low-speed", &i) >= 0) {
dev->speed = LIBUSB_SPEED_LOW;
} else if (di_prop_exists(DDI_DEV_T_ANY, node, "high-speed") == 1) {
} else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "high-speed", &i) >= 0) {
dev->speed = LIBUSB_SPEED_HIGH;
} else if (di_prop_exists(DDI_DEV_T_ANY, node, "full-speed") == 1) {
} else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "full-speed", &i) >= 0) {
dev->speed = LIBUSB_SPEED_FULL;
} else if (di_prop_exists(DDI_DEV_T_ANY, node, "super-speed") == 1) {
} else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "super-speed", &i) >= 0) {
dev->speed = LIBUSB_SPEED_SUPER;
}
@@ -170,111 +563,98 @@ sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
return (LIBUSB_SUCCESS);
}
static int
sunos_add_devices(di_devlink_t link, void *arg)
{
struct devlink_cbarg *largs = (struct devlink_cbarg *)arg;
struct node_args *nargs;
di_node_t myself, pnode;
di_node_t myself, dn;
uint64_t session_id = 0;
uint16_t bdf = 0;
uint64_t sid = 0;
uint64_t bdf = 0;
struct libusb_device *dev;
sunos_dev_priv_t *devpriv;
const char *path, *newpath;
int n, i;
int n, *j;
int i = 0;
int *addr_prop;
uint8_t bus_number = 0;
uint32_t * regbuf = NULL;
uint32_t reg;
nargs = (struct node_args *)largs->nargs;
myself = largs->myself;
if (nargs->last_ugenpath) {
/* the same node's links */
return (DI_WALK_CONTINUE);
}
/*
* Construct session ID.
* session ID = ...parent hub addr|hub addr|dev addr.
* session ID = dev_addr | hub addr |parent hub addr|...|root hub bdf
* 8 bits 8bits 8 bits 16bits
*/
pnode = myself;
i = 0;
while (pnode != DI_NODE_NIL) {
if (di_prop_exists(DDI_DEV_T_ANY, pnode, "root-hub") == 1) {
/* walk to root */
uint32_t *regbuf = NULL;
uint32_t reg;
if (myself == DI_NODE_NIL)
return (DI_WALK_CONTINUE);
n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "reg",
(int **)&regbuf);
reg = regbuf[0];
bdf = (PCI_REG_BUS_G(reg) << 8) |
(PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
session_id |= (bdf << i * 8);
dn = myself;
/* find the root hub */
while (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "root-hub", &j) != 0) {
usbi_dbg("find_root_hub:%s", di_devfs_path(dn));
n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
"assigned-address", &addr_prop);
session_id |= ((addr_prop[0] & 0xff) << i++ * 8);
dn = di_parent_node(dn);
}
/* same as 'unit-address' property */
bus_number =
(PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
/* dn is the root hub node */
n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "reg", (int **)&regbuf);
reg = regbuf[0];
bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
/* bdf must larger than i*8 bits */
session_id |= (bdf << i * 8);
bus_number = (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
usbi_dbg("device bus address=%s:%x",
di_bus_addr(pnode), bus_number);
break;
}
usbi_dbg("device bus address=%s:%x, name:%s",
di_bus_addr(myself), bus_number, di_node_name(dn));
usbi_dbg("session id org:%lx", session_id);
/* dn is the usb device */
for (dn = di_child_node(myself); dn != DI_NODE_NIL; dn = di_sibling_node(dn)) {
usbi_dbg("device path:%s", di_devfs_path(dn));
/* skip hub devices, because its driver can not been unload */
if (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "usb-port-count", &addr_prop) != -1)
continue;
/* usb_addr */
n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode,
n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
"assigned-address", &addr_prop);
if ((n != 1) || (addr_prop[0] == 0)) {
usbi_dbg("cannot get valid usb_addr");
return (DI_WALK_CONTINUE);
continue;
}
session_id |= ((addr_prop[0] & 0xff) << i * 8);
if (++i > 7)
break;
sid = (session_id << 8) | (addr_prop[0] & 0xff) ;
usbi_dbg("session id %lx", sid);
pnode = di_parent_node(pnode);
}
path = di_devlink_path(link);
dev = usbi_get_device_by_session_id(nargs->ctx, session_id);
if (dev == NULL) {
dev = usbi_alloc_device(nargs->ctx, session_id);
dev = usbi_get_device_by_session_id(nargs->ctx, sid);
if (dev == NULL) {
usbi_dbg("can't alloc device");
dev = usbi_alloc_device(nargs->ctx, sid);
if (dev == NULL) {
usbi_dbg("can't alloc device");
continue;
}
devpriv = (sunos_dev_priv_t *)dev->os_priv;
dev->bus_number = bus_number;
return (DI_WALK_TERMINATE);
if (sunos_fill_in_dev_info(dn, dev) != LIBUSB_SUCCESS) {
libusb_unref_device(dev);
usbi_dbg("get infomation fail");
continue;
}
if (usbi_sanitize_device(dev) < 0) {
libusb_unref_device(dev);
usbi_dbg("sanatize failed: ");
return (DI_WALK_TERMINATE);
}
} else {
devpriv = (sunos_dev_priv_t *)dev->os_priv;
usbi_dbg("Dev %s exists", devpriv->ugenpath);
}
devpriv = (sunos_dev_priv_t *)dev->os_priv;
if ((newpath = strrchr(path, '/')) == NULL) {
libusb_unref_device(dev);
return (DI_WALK_TERMINATE);
}
devpriv->ugenpath = strndup(path, strlen(path) -
strlen(newpath));
dev->bus_number = bus_number;
if (sunos_fill_in_dev_info(myself, dev) != LIBUSB_SUCCESS) {
libusb_unref_device(dev);
return (DI_WALK_TERMINATE);
}
if (usbi_sanitize_device(dev) < 0) {
libusb_unref_device(dev);
usbi_dbg("sanatize failed: ");
return (DI_WALK_TERMINATE);
}
} else {
usbi_dbg("Dev %s exists", path);
}
devpriv = (sunos_dev_priv_t *)dev->os_priv;
if (nargs->last_ugenpath == NULL) {
/* first device */
nargs->last_ugenpath = devpriv->ugenpath;
if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) {
usbi_dbg("cannot append device");
@@ -285,11 +665,11 @@ sunos_add_devices(di_devlink_t link, void *arg)
* hereafter. Front end or app should take care of their ref.
*/
libusb_unref_device(dev);
}
usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x",
devpriv->ugenpath, path, (uint64_t)session_id,
(*nargs->discdevs)->len, bdf);
usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x",
devpriv->ugenpath, di_devfs_path(dn), (uint64_t)sid,
(*nargs->discdevs)->len, bdf);
}
return (DI_WALK_CONTINUE);
}
@@ -303,14 +683,14 @@ sunos_walk_minor_node_link(di_node_t node, void *args)
struct node_args *nargs = (struct node_args *)args;
di_devlink_handle_t devlink_hdl = nargs->dlink_hdl;
/* walk each minor to find ugen devices */
/* walk each minor to find usb devices */
while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
minor_path = di_devfs_minor_path(minor);
arg.nargs = args;
arg.myself = node;
arg.minor = minor;
(void) di_devlink_walk(devlink_hdl,
"^usb/[0-9a-f]+[.][0-9a-f]+", minor_path,
"^usb/hub[0-9]+", minor_path,
DI_PRIMARY_LINK, (void *)&arg, sunos_add_devices);
di_devfs_path_free(minor_path);
}
@@ -496,7 +876,7 @@ sunos_check_device_and_status_open(struct libusb_device_handle *hdl,
usbi_dbg("can't find interface for endpoint 0x%02x",
ep_addr);
return (LIBUSB_ERROR_ACCESS);
return (EACCES);
}
/* create filename */
@@ -603,6 +983,11 @@ sunos_open(struct libusb_device_handle *handle)
hpriv->eps[i].statfd = -1;
}
if (sunos_kernel_driver_active(handle, 0)) {
/* pretend we can open the device */
return (LIBUSB_SUCCESS);
}
if ((ret = sunos_usb_open_ep0(hpriv, dpriv)) != LIBUSB_SUCCESS) {
usbi_dbg("fail: %d", ret);
return (ret);
@@ -811,26 +1196,32 @@ sunos_async_callback(union sigval arg)
int ret;
sunos_dev_handle_priv_t *hpriv;
uint8_t ep;
libusb_device_handle *dev_handle;
hpriv = (sunos_dev_handle_priv_t *)xfer->dev_handle->os_priv;
ep = sunos_usb_ep_index(xfer->endpoint);
dev_handle = xfer->dev_handle;
ret = aio_error(aiocb);
if (ret != 0) {
xfer->status = sunos_usb_get_status(hpriv->eps[ep].statfd);
} else {
xfer->actual_length =
LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer)->transferred =
aio_return(aiocb);
/* libusb can forcibly interrupt transfer in do_close() */
if (dev_handle != NULL) {
hpriv = (sunos_dev_handle_priv_t *)dev_handle->os_priv;
ep = sunos_usb_ep_index(xfer->endpoint);
ret = aio_error(aiocb);
if (ret != 0) {
xfer->status = sunos_usb_get_status(hpriv->eps[ep].statfd);
} else {
xfer->actual_length =
LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer)->transferred =
aio_return(aiocb);
}
usb_dump_data(xfer->buffer, xfer->actual_length);
usbi_dbg("ret=%d, len=%d, actual_len=%d", ret, xfer->length,
xfer->actual_length);
/* async notification */
usbi_signal_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer));
}
usb_dump_data(xfer->buffer, xfer->actual_length);
usbi_dbg("ret=%d, len=%d, actual_len=%d", ret, xfer->length,
xfer->actual_length);
/* async notification */
usbi_signal_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer));
}
static int
@@ -975,9 +1366,15 @@ solaris_submit_ctrl_on_default(struct libusb_transfer *transfer)
}
usbi_dbg("Done: ctrl data bytes %d", ret);
/* sync transfer handling */
/**
* Sync transfer handling.
* We should release transfer lock here and later get it back
* as usbi_handle_transfer_completion() takes its own transfer lock.
*/
usbi_mutex_unlock(&LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->lock);
ret = usbi_handle_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer),
transfer->status);
usbi_mutex_lock(&LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->lock);
return (ret);
}
@@ -1010,9 +1407,7 @@ void
sunos_destroy_device(struct libusb_device *dev)
{
sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
usbi_dbg("");
usbi_dbg("destroy everyting");
free(dpriv->raw_cfgdescr);
free(dpriv->ugenpath);
free(dpriv->phypath);
@@ -1120,8 +1515,6 @@ sunos_handle_transfer_completion(struct usbi_transfer *itransfer)
int
sunos_clock_gettime(int clkid, struct timespec *tp)
{
usbi_dbg("clock %d", clkid);
if (clkid == USBI_CLOCK_REALTIME)
return clock_gettime(CLOCK_REALTIME, tp);
@@ -1254,7 +1647,14 @@ sunos_usb_get_status(int fd)
return (status);
}
const struct usbi_os_backend sunos_backend = {
#ifdef USBI_TIMERFD_AVAILABLE
static clockid_t op_get_timerfd_clockid(void)
{
return CLOCK_MONOTONIC;
}
#endif
const struct usbi_os_backend usbi_backend = {
.name = "Solaris",
.caps = 0,
.init = sunos_init,
@@ -1276,9 +1676,9 @@ const struct usbi_os_backend sunos_backend = {
.reset_device = sunos_reset_device, /* TODO */
.alloc_streams = NULL,
.free_streams = NULL,
.kernel_driver_active = NULL,
.detach_kernel_driver = NULL,
.attach_kernel_driver = NULL,
.kernel_driver_active = sunos_kernel_driver_active,
.detach_kernel_driver = sunos_detach_kernel_driver,
.attach_kernel_driver = sunos_attach_kernel_driver,
.destroy_device = sunos_destroy_device,
.submit_transfer = sunos_submit_transfer,
.cancel_transfer = sunos_cancel_transfer,
@@ -1286,6 +1686,9 @@ const struct usbi_os_backend sunos_backend = {
.clear_transfer_priv = sunos_clear_transfer_priv,
.handle_transfer_completion = sunos_handle_transfer_completion,
.clock_gettime = sunos_clock_gettime,
#ifdef USBI_TIMERFD_AVAILABLE
.get_timerfd_clockid = op_get_timerfd_clockid,
#endif
.device_priv_size = sizeof(sunos_dev_priv_t),
.device_handle_priv_size = sizeof(sunos_dev_handle_priv_t),
.transfer_priv_size = sizeof(sunos_xfer_priv_t),
+6
View File
@@ -65,6 +65,12 @@ struct devlink_cbarg {
di_minor_t minor;
};
typedef struct walk_link {
char *path;
int len;
char **linkpp;
} walk_link_t;
/* AIO callback args */
struct aio_callback_args{
struct libusb_transfer *transfer;
+6 -5
View File
@@ -29,7 +29,7 @@
# include <unistd.h>
# include <sys/syscall.h>
#elif defined(__APPLE__)
# include <mach/mach.h>
# include <pthread.h>
#elif defined(__CYGWIN__)
# include <windows.h>
#endif
@@ -43,7 +43,7 @@ int usbi_cond_timedwait(pthread_cond_t *cond,
struct timespec timeout;
int r;
r = usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timeout);
r = usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, &timeout);
if (r < 0)
return r;
@@ -59,7 +59,7 @@ int usbi_cond_timedwait(pthread_cond_t *cond,
int usbi_get_tid(void)
{
int ret = -1;
int ret;
#if defined(__ANDROID__)
ret = gettid();
#elif defined(__linux__)
@@ -69,10 +69,11 @@ int usbi_get_tid(void)
real thread support. For 5.1 and earlier, -1 is returned. */
ret = syscall(SYS_getthrid);
#elif defined(__APPLE__)
ret = mach_thread_self();
mach_port_deallocate(mach_task_self(), ret);
ret = (int)pthread_mach_thread_np(pthread_self());
#elif defined(__CYGWIN__)
ret = GetCurrentThreadId();
#else
ret = -1;
#endif
/* TODO: NetBSD thread ID support */
return ret;
+67 -23
View File
@@ -26,32 +26,76 @@
#include <sys/time.h>
#endif
#define usbi_mutex_static_t pthread_mutex_t
#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#define usbi_mutex_static_lock pthread_mutex_lock
#define usbi_mutex_static_unlock pthread_mutex_unlock
#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
typedef pthread_mutex_t usbi_mutex_static_t;
static inline void usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
{
(void)pthread_mutex_lock(mutex);
}
static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
{
(void)pthread_mutex_unlock(mutex);
}
#define usbi_mutex_t pthread_mutex_t
#define usbi_mutex_init(mutex) pthread_mutex_init((mutex), NULL)
#define usbi_mutex_lock pthread_mutex_lock
#define usbi_mutex_unlock pthread_mutex_unlock
#define usbi_mutex_trylock pthread_mutex_trylock
#define usbi_mutex_destroy pthread_mutex_destroy
typedef pthread_mutex_t usbi_mutex_t;
static inline int usbi_mutex_init(usbi_mutex_t *mutex)
{
return pthread_mutex_init(mutex, NULL);
}
static inline void usbi_mutex_lock(usbi_mutex_t *mutex)
{
(void)pthread_mutex_lock(mutex);
}
static inline void usbi_mutex_unlock(usbi_mutex_t *mutex)
{
(void)pthread_mutex_unlock(mutex);
}
static inline int usbi_mutex_trylock(usbi_mutex_t *mutex)
{
return pthread_mutex_trylock(mutex);
}
static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
{
(void)pthread_mutex_destroy(mutex);
}
#define usbi_cond_t pthread_cond_t
#define usbi_cond_init(cond) pthread_cond_init((cond), NULL)
#define usbi_cond_wait pthread_cond_wait
#define usbi_cond_broadcast pthread_cond_broadcast
#define usbi_cond_destroy pthread_cond_destroy
typedef pthread_cond_t usbi_cond_t;
static inline void usbi_cond_init(pthread_cond_t *cond)
{
(void)pthread_cond_init(cond, NULL);
}
static inline int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
{
return pthread_cond_wait(cond, mutex);
}
int usbi_cond_timedwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, const struct timeval *tv);
static inline void usbi_cond_broadcast(usbi_cond_t *cond)
{
(void)pthread_cond_broadcast(cond);
}
static inline void usbi_cond_destroy(usbi_cond_t *cond)
{
(void)pthread_cond_destroy(cond);
}
#define usbi_tls_key_t pthread_key_t
#define usbi_tls_key_create(key) pthread_key_create((key), NULL)
#define usbi_tls_key_get pthread_getspecific
#define usbi_tls_key_set pthread_setspecific
#define usbi_tls_key_delete pthread_key_delete
int usbi_cond_timedwait(pthread_cond_t *cond,
pthread_mutex_t *mutex, const struct timeval *tv);
typedef pthread_key_t usbi_tls_key_t;
static inline void usbi_tls_key_create(usbi_tls_key_t *key)
{
(void)pthread_key_create(key, NULL);
}
static inline void *usbi_tls_key_get(usbi_tls_key_t key)
{
return pthread_getspecific(key);
}
static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr)
{
(void)pthread_setspecific(key, ptr);
}
static inline void usbi_tls_key_delete(usbi_tls_key_t key)
{
(void)pthread_key_delete(key);
}
int usbi_get_tid(void);
+40 -173
View File
@@ -20,189 +20,67 @@
#include <config.h>
#include <objbase.h>
#include <errno.h>
#include "libusbi.h"
struct usbi_cond_perthread {
struct list_head list;
DWORD tid;
HANDLE event;
};
int usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
void usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
{
if (!mutex)
return EINVAL;
while (InterlockedExchange(mutex, 1) == 1)
while (InterlockedExchange(mutex, 1L) == 1L)
SleepEx(0, TRUE);
return 0;
}
int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
void usbi_cond_init(usbi_cond_t *cond)
{
if (!mutex)
return EINVAL;
InterlockedExchange(mutex, 0);
return 0;
}
int usbi_mutex_init(usbi_mutex_t *mutex)
{
if (!mutex)
return EINVAL;
*mutex = CreateMutex(NULL, FALSE, NULL);
if (!*mutex)
return ENOMEM;
return 0;
}
int usbi_mutex_lock(usbi_mutex_t *mutex)
{
DWORD result;
if (!mutex)
return EINVAL;
result = WaitForSingleObject(*mutex, INFINITE);
if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
return 0; // acquired (ToDo: check that abandoned is ok)
else
return EINVAL; // don't know how this would happen
// so don't know proper errno
}
int usbi_mutex_unlock(usbi_mutex_t *mutex)
{
if (!mutex)
return EINVAL;
if (ReleaseMutex(*mutex))
return 0;
else
return EPERM;
}
int usbi_mutex_trylock(usbi_mutex_t *mutex)
{
DWORD result;
if (!mutex)
return EINVAL;
result = WaitForSingleObject(*mutex, 0);
if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
return 0; // acquired (ToDo: check that abandoned is ok)
else if (result == WAIT_TIMEOUT)
return EBUSY;
else
return EINVAL; // don't know how this would happen
// so don't know proper error
}
int usbi_mutex_destroy(usbi_mutex_t *mutex)
{
// It is not clear if CloseHandle failure is due to failure to unlock.
// If so, this should be errno=EBUSY.
if (!mutex || !CloseHandle(*mutex))
return EINVAL;
*mutex = NULL;
return 0;
}
int usbi_cond_init(usbi_cond_t *cond)
{
if (!cond)
return EINVAL;
list_init(&cond->waiters);
list_init(&cond->not_waiting);
return 0;
}
int usbi_cond_destroy(usbi_cond_t *cond)
{
// This assumes no one is using this anymore. The check MAY NOT BE safe.
struct usbi_cond_perthread *pos, *next_pos;
if(!cond)
return EINVAL;
if (!list_empty(&cond->waiters))
return EBUSY; // (!see above!)
list_for_each_entry_safe(pos, next_pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
CloseHandle(pos->event);
list_del(&pos->list);
free(pos);
}
return 0;
}
int usbi_cond_broadcast(usbi_cond_t *cond)
{
// Assumes mutex is locked; this is not in keeping with POSIX spec, but
// libusb does this anyway, so we simplify by not adding more sync
// primitives to the CV definition!
int fail = 0;
struct usbi_cond_perthread *pos;
if (!cond)
return EINVAL;
list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) {
if (!SetEvent(pos->event))
fail = 1;
}
// The wait function will remove its respective item from the list.
return fail ? EINVAL : 0;
}
__inline static int usbi_cond_intwait(usbi_cond_t *cond,
static int usbi_cond_intwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, DWORD timeout_ms)
{
struct usbi_cond_perthread *pos;
int r, found = 0;
DWORD r2, tid = GetCurrentThreadId();
DWORD r;
if (!cond || !mutex)
return EINVAL;
list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
if(tid == pos->tid) {
found = 1;
break;
}
}
if (!found) {
pos = calloc(1, sizeof(struct usbi_cond_perthread));
if (!pos)
// Same assumption as usbi_cond_broadcast() holds
if (list_empty(&cond->not_waiting)) {
pos = malloc(sizeof(*pos));
if (pos == NULL)
return ENOMEM; // This errno is not POSIX-allowed.
pos->tid = tid;
pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset.
if (!pos->event) {
if (pos->event == NULL) {
free(pos);
return ENOMEM;
}
list_add(&pos->list, &cond->not_waiting);
} else {
pos = list_first_entry(&cond->not_waiting, struct usbi_cond_perthread, list);
list_del(&pos->list); // remove from not_waiting list.
// Ensure the event is clear before waiting
WaitForSingleObject(pos->event, 0);
}
list_del(&pos->list); // remove from not_waiting list.
list_add(&pos->list, &cond->waiters);
r = usbi_mutex_unlock(mutex);
if (r)
return r;
r2 = WaitForSingleObject(pos->event, timeout_ms);
r = usbi_mutex_lock(mutex);
if (r)
return r;
LeaveCriticalSection(mutex);
r = WaitForSingleObject(pos->event, timeout_ms);
EnterCriticalSection(mutex);
list_del(&pos->list);
list_add(&pos->list, &cond->not_waiting);
if (r2 == WAIT_OBJECT_0)
if (r == WAIT_OBJECT_0)
return 0;
else if (r2 == WAIT_TIMEOUT)
else if (r == WAIT_TIMEOUT)
return ETIMEDOUT;
else
return EINVAL;
}
// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot!
int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
{
@@ -221,39 +99,28 @@ int usbi_cond_timedwait(usbi_cond_t *cond,
return usbi_cond_intwait(cond, mutex, millis);
}
int usbi_tls_key_create(usbi_tls_key_t *key)
void usbi_cond_broadcast(usbi_cond_t *cond)
{
if (!key)
return EINVAL;
*key = TlsAlloc();
if (*key == TLS_OUT_OF_INDEXES)
return ENOMEM;
else
return 0;
// Assumes mutex is locked; this is not in keeping with POSIX spec, but
// libusb does this anyway, so we simplify by not adding more sync
// primitives to the CV definition!
struct usbi_cond_perthread *pos;
list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread)
SetEvent(pos->event);
// The wait function will remove its respective item from the list.
}
void *usbi_tls_key_get(usbi_tls_key_t key)
void usbi_cond_destroy(usbi_cond_t *cond)
{
return TlsGetValue(key);
}
// This assumes no one is using this anymore. The check MAY NOT BE safe.
struct usbi_cond_perthread *pos, *next;
int usbi_tls_key_set(usbi_tls_key_t key, void *value)
{
if (TlsSetValue(key, value))
return 0;
else
return EINVAL;
}
int usbi_tls_key_delete(usbi_tls_key_t key)
{
if (TlsFree(key))
return 0;
else
return EINVAL;
}
int usbi_get_tid(void)
{
return (int)GetCurrentThreadId();
if (!list_empty(&cond->waiters))
return; // (!see above!)
list_for_each_entry_safe(pos, next, &cond->not_waiting, list, struct usbi_cond_perthread) {
CloseHandle(pos->event);
list_del(&pos->list);
free(pos);
}
}
+64 -29
View File
@@ -21,17 +21,40 @@
#ifndef LIBUSB_THREADS_WINDOWS_H
#define LIBUSB_THREADS_WINDOWS_H
#define usbi_mutex_static_t volatile LONG
#define USBI_MUTEX_INITIALIZER 0
#define USBI_MUTEX_INITIALIZER 0L
#ifdef _WIN32_WCE
typedef LONG usbi_mutex_static_t;
#else
typedef volatile LONG usbi_mutex_static_t;
#endif
void usbi_mutex_static_lock(usbi_mutex_static_t *mutex);
static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
{
InterlockedExchange(mutex, 0L);
}
#define usbi_mutex_t HANDLE
typedef struct usbi_cond {
// Every time a thread touches the CV, it winds up in one of these lists.
// It stays there until the CV is destroyed, even if the thread terminates.
struct list_head waiters;
struct list_head not_waiting;
} usbi_cond_t;
typedef CRITICAL_SECTION usbi_mutex_t;
static inline int usbi_mutex_init(usbi_mutex_t *mutex)
{
InitializeCriticalSection(mutex);
return 0;
}
static inline void usbi_mutex_lock(usbi_mutex_t *mutex)
{
EnterCriticalSection(mutex);
}
static inline void usbi_mutex_unlock(usbi_mutex_t *mutex)
{
LeaveCriticalSection(mutex);
}
static inline int usbi_mutex_trylock(usbi_mutex_t *mutex)
{
return !TryEnterCriticalSection(mutex);
}
static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
{
DeleteCriticalSection(mutex);
}
// We *were* getting timespec from pthread.h:
#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED))
@@ -45,32 +68,44 @@ struct timespec {
// We *were* getting ETIMEDOUT from pthread.h:
#ifndef ETIMEDOUT
# define ETIMEDOUT 10060 /* This is the value in winsock.h. */
#define ETIMEDOUT 10060 /* This is the value in winsock.h. */
#endif
#define usbi_tls_key_t DWORD
typedef struct usbi_cond {
// Every time a thread touches the CV, it winds up in one of these lists.
// It stays there until the CV is destroyed, even if the thread terminates.
struct list_head waiters;
struct list_head not_waiting;
} usbi_cond_t;
int usbi_mutex_static_lock(usbi_mutex_static_t *mutex);
int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex);
int usbi_mutex_init(usbi_mutex_t *mutex);
int usbi_mutex_lock(usbi_mutex_t *mutex);
int usbi_mutex_unlock(usbi_mutex_t *mutex);
int usbi_mutex_trylock(usbi_mutex_t *mutex);
int usbi_mutex_destroy(usbi_mutex_t *mutex);
int usbi_cond_init(usbi_cond_t *cond);
void usbi_cond_init(usbi_cond_t *cond);
int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex);
int usbi_cond_timedwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, const struct timeval *tv);
int usbi_cond_broadcast(usbi_cond_t *cond);
int usbi_cond_destroy(usbi_cond_t *cond);
void usbi_cond_broadcast(usbi_cond_t *cond);
void usbi_cond_destroy(usbi_cond_t *cond);
int usbi_tls_key_create(usbi_tls_key_t *key);
void *usbi_tls_key_get(usbi_tls_key_t key);
int usbi_tls_key_set(usbi_tls_key_t key, void *value);
int usbi_tls_key_delete(usbi_tls_key_t key);
typedef DWORD usbi_tls_key_t;
static inline void usbi_tls_key_create(usbi_tls_key_t *key)
{
*key = TlsAlloc();
}
static inline void *usbi_tls_key_get(usbi_tls_key_t key)
{
return TlsGetValue(key);
}
static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr)
{
(void)TlsSetValue(key, ptr);
}
static inline void usbi_tls_key_delete(usbi_tls_key_t key)
{
(void)TlsFree(key);
}
int usbi_get_tid(void);
static inline int usbi_get_tid(void)
{
return (int)GetCurrentThreadId();
}
#endif /* LIBUSB_THREADS_WINDOWS_H */
+51 -62
View File
@@ -31,8 +31,7 @@
#include "wince_usb.h"
// Global variables
const uint64_t epoch_time = UINT64_C(116444736000000000); // 1970.01.01 00:00:000 in MS Filetime
int windows_version = WINDOWS_CE;
int errno = 0;
static uint64_t hires_frequency, hires_ticks_to_ps;
static HANDLE driver_handle = INVALID_HANDLE_VALUE;
static int concurrent_usage = -1;
@@ -42,38 +41,39 @@ static int concurrent_usage = -1;
* uses retval as errorcode, or, if 0, use GetLastError()
*/
#if defined(ENABLE_LOGGING)
static const char *windows_error_str(DWORD retval)
static const char *windows_error_str(DWORD error_code)
{
static TCHAR wErr_string[ERR_BUFFER_SIZE];
static char err_string[ERR_BUFFER_SIZE];
DWORD error_code, format_error;
DWORD size;
size_t i;
int len;
error_code = retval ? retval : GetLastError();
if (error_code == 0)
error_code = GetLastError();
safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("[%u] "), (unsigned int)error_code);
len = sprintf(err_string, "[%u] ", (unsigned int)error_code);
size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &wErr_string[safe_tcslen(wErr_string)],
ERR_BUFFER_SIZE - (DWORD)safe_tcslen(wErr_string), NULL);
size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
wErr_string, ERR_BUFFER_SIZE, NULL);
if (size == 0) {
format_error = GetLastError();
DWORD format_error = GetLastError();
if (format_error)
safe_stprintf(wErr_string, ERR_BUFFER_SIZE,
_T("Windows error code %u (FormatMessage error code %u)"),
snprintf(err_string, ERR_BUFFER_SIZE,
"Windows error code %u (FormatMessage error code %u)",
(unsigned int)error_code, (unsigned int)format_error);
else
safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("Unknown error code %u"), (unsigned int)error_code);
snprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", (unsigned int)error_code);
} else {
// Remove CR/LF terminators
for (i = safe_tcslen(wErr_string) - 1; ((wErr_string[i] == 0x0A) || (wErr_string[i] == 0x0D)); i--)
wErr_string[i] = 0;
}
// Remove CR/LF terminators, if present
size_t pos = size - 2;
if (wErr_string[pos] == 0x0D)
wErr_string[pos] = 0;
if (WideCharToMultiByte(CP_ACP, 0, wErr_string, -1, err_string, ERR_BUFFER_SIZE, NULL, NULL) < 0)
strcpy(err_string, "Unable to convert error string");
if (!WideCharToMultiByte(CP_ACP, 0, wErr_string, -1, &err_string[len], ERR_BUFFER_SIZE - len, NULL, NULL))
strcpy(err_string, "Unable to convert error string");
}
return err_string;
}
@@ -109,7 +109,7 @@ static int translate_driver_error(DWORD error)
}
}
static int init_dllimports(void)
static BOOL init_dllimports(void)
{
DLL_GET_HANDLE(ceusbkwrapper);
DLL_LOAD_FUNC(ceusbkwrapper, UkwOpenDriver, TRUE);
@@ -135,7 +135,7 @@ static int init_dllimports(void)
DLL_LOAD_FUNC(ceusbkwrapper, UkwIssueBulkTransfer, TRUE);
DLL_LOAD_FUNC(ceusbkwrapper, UkwIsPipeHalted, TRUE);
return LIBUSB_SUCCESS;
return TRUE;
}
static void exit_dllimports(void)
@@ -186,11 +186,8 @@ static int wince_init(struct libusb_context *ctx)
// NB: concurrent usage supposes that init calls are equally balanced with
// exit calls. If init is called more than exit, we will not exit properly
if ( ++concurrent_usage == 0 ) { // First init?
// Initialize pollable file descriptors
init_polling();
// Load DLL imports
if (init_dllimports() != LIBUSB_SUCCESS) {
if (!init_dllimports()) {
usbi_err(ctx, "could not resolve DLL functions");
r = LIBUSB_ERROR_NOT_SUPPORTED;
goto init_exit;
@@ -223,7 +220,6 @@ static int wince_init(struct libusb_context *ctx)
init_exit: // Holds semaphore here.
if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
exit_dllimports();
exit_polling();
if (driver_handle != INVALID_HANDLE_VALUE) {
UkwCloseDriver(driver_handle);
@@ -239,10 +235,11 @@ init_exit: // Holds semaphore here.
return r;
}
static void wince_exit(void)
static void wince_exit(struct libusb_context *ctx)
{
HANDLE semaphore;
TCHAR sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
UNUSED(ctx);
_stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
semaphore = CreateSemaphore(NULL, 1, 1, sem_name);
@@ -259,7 +256,6 @@ static void wince_exit(void)
// Only works if exits and inits are balanced exactly
if (--concurrent_usage < 0) { // Last exit
exit_dllimports();
exit_polling();
if (driver_handle != INVALID_HANDLE_VALUE) {
UkwCloseDriver(driver_handle);
@@ -328,19 +324,19 @@ static int wince_get_device_list(
}
new_devices = discovered_devs_append(new_devices, dev);
if (!discdevs) {
if (!new_devices) {
r = LIBUSB_ERROR_NO_MEM;
goto err_out;
}
safe_unref_device(dev);
libusb_unref_device(dev);
}
*discdevs = new_devices;
return r;
err_out:
*discdevs = new_devices;
safe_unref_device(dev);
libusb_unref_device(dev);
// Release the remainder of the unprocessed device list.
// The devices added to new_devices already will still be passed up to libusb,
// which can dispose of them at its leisure.
@@ -541,12 +537,9 @@ static void wince_destroy_device(struct libusb_device *dev)
static void wince_clear_transfer_priv(struct usbi_transfer *itransfer)
{
struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
struct winfd wfd = fd_to_winfd(transfer_priv->pollable_fd.fd);
// No need to cancel transfer as it is either complete or abandoned
wfd.itransfer = NULL;
CloseHandle(wfd.handle);
usbi_free_fd(&transfer_priv->pollable_fd);
usbi_close(transfer_priv->pollable_fd.fd);
transfer_priv->pollable_fd = INVALID_WINFD;
}
static int wince_cancel_transfer(struct usbi_transfer *itransfer)
@@ -570,11 +563,10 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer
BOOL direction_in, ret;
struct winfd wfd;
DWORD flags;
HANDLE eventHandle;
PUKW_CONTROL_HEADER setup = NULL;
const BOOL control_transfer = transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL;
int r;
transfer_priv->pollable_fd = INVALID_WINFD;
if (control_transfer) {
setup = (PUKW_CONTROL_HEADER) transfer->buffer;
direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
@@ -584,19 +576,18 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer
flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
flags |= UKW_TF_SHORT_TRANSFER_OK;
eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
if (eventHandle == NULL) {
usbi_err(ctx, "Failed to create event for async transfer");
wfd = usbi_create_fd();
if (wfd.fd < 0)
return LIBUSB_ERROR_NO_MEM;
}
wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, itransfer, &wince_cancel_transfer);
if (wfd.fd < 0) {
CloseHandle(eventHandle);
return LIBUSB_ERROR_NO_MEM;
r = usbi_add_pollfd(ctx, wfd.fd, direction_in ? POLLIN : POLLOUT);
if (r) {
usbi_close(wfd.fd);
return r;
}
transfer_priv->pollable_fd = wfd;
if (control_transfer) {
// Split out control setup header and data buffer
DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
@@ -612,19 +603,16 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer
int libusbErr = translate_driver_error(GetLastError());
usbi_err(ctx, "UkwIssue%sTransfer failed: error %u",
control_transfer ? "Control" : "Bulk", (unsigned int)GetLastError());
wince_clear_transfer_priv(itransfer);
usbi_remove_pollfd(ctx, wfd.fd);
usbi_close(wfd.fd);
transfer_priv->pollable_fd = INVALID_WINFD;
return libusbErr;
}
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT);
return LIBUSB_SUCCESS;
}
static int wince_submit_iso_transfer(struct usbi_transfer *itransfer)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int wince_submit_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
@@ -635,7 +623,6 @@ static int wince_submit_transfer(struct usbi_transfer *itransfer)
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
return wince_submit_control_or_bulk_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
return wince_submit_iso_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
return LIBUSB_ERROR_NOT_SUPPORTED;
default:
@@ -763,7 +750,7 @@ static int wince_handle_events(
struct wince_transfer_priv* transfer_priv = NULL;
POLL_NFDS_TYPE i = 0;
BOOL found = FALSE;
struct usbi_transfer *transfer;
struct usbi_transfer *itransfer;
DWORD io_size, io_result;
int r = LIBUSB_SUCCESS;
@@ -780,8 +767,8 @@ static int wince_handle_events(
// Because a Windows OVERLAPPED is used for poll emulation,
// a pollable fd is created and stored with each transfer
usbi_mutex_lock(&ctx->flying_transfers_lock);
list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
transfer_priv = usbi_transfer_get_os_priv(transfer);
list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
transfer_priv = usbi_transfer_get_os_priv(itransfer);
if (transfer_priv->pollable_fd.fd == fds[i].fd) {
found = TRUE;
break;
@@ -796,7 +783,7 @@ static int wince_handle_events(
// let handle_callback free the event using the transfer wfd
// If you don't use the transfer wfd, you run a risk of trying to free a
// newly allocated wfd that took the place of the one from the transfer.
wince_handle_callback(transfer, io_result, io_size);
wince_handle_callback(itransfer, io_result, io_size);
} else if (found) {
usbi_err(ctx, "matching transfer for fd %d has not completed", fds[i]);
r = LIBUSB_ERROR_OTHER;
@@ -832,14 +819,14 @@ static int wince_clock_gettime(int clk_id, struct timespec *tp)
// Fall through and return real-time if monotonic read failed or was not detected @ init
case USBI_CLOCK_REALTIME:
// We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
// with a predef epoch_time to have an epoch that starts at 1970.01.01 00:00
// with a predef epoch time to have an epoch that starts at 1970.01.01 00:00
// Note however that our resolution is bounded by the Windows system time
// functions and is at best of the order of 1 ms (or, usually, worse)
GetSystemTime(&st);
SystemTimeToFileTime(&st, &filetime);
rtime.LowPart = filetime.dwLowDateTime;
rtime.HighPart = filetime.dwHighDateTime;
rtime.QuadPart -= epoch_time;
rtime.QuadPart -= EPOCH_TIME;
tp->tv_sec = (long)(rtime.QuadPart / 10000000);
tp->tv_nsec = (long)((rtime.QuadPart % 10000000)*100);
return LIBUSB_SUCCESS;
@@ -848,11 +835,12 @@ static int wince_clock_gettime(int clk_id, struct timespec *tp)
}
}
const struct usbi_os_backend wince_backend = {
const struct usbi_os_backend usbi_backend = {
"Windows CE",
0,
wince_init,
wince_exit,
NULL, /* set_option() */
wince_get_device_list,
NULL, /* hotplug_poll */
@@ -893,6 +881,7 @@ const struct usbi_os_backend wince_backend = {
NULL, /* handle_transfer_completion() */
wince_clock_gettime,
0,
sizeof(struct wince_device_priv),
0,
sizeof(struct wince_transfer_priv),
+24 -35
View File
@@ -37,38 +37,23 @@
#define false FALSE
#endif
#define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime
#if defined(__CYGWIN__ )
#define _stricmp strcasecmp
#define _snprintf snprintf
#define _strdup strdup
// _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread
#define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, (LPDWORD)f)
#endif
#define safe_free(p) do {if (p != NULL) {free((void*)p); p = NULL;}} while(0)
#define safe_closehandle(h) do {if (h != INVALID_HANDLE_VALUE) {CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0)
#define safe_min(a, b) MIN((size_t)(a), (size_t)(b))
#define safe_strcp(dst, dst_max, src, count) do {memcpy(dst, src, safe_min(count, dst_max)); \
((char*)dst)[safe_min(count, dst_max)-1] = 0;} while(0)
#define safe_strcpy(dst, dst_max, src) safe_strcp(dst, dst_max, src, safe_strlen(src)+1)
#define safe_strncat(dst, dst_max, src, count) strncat(dst, src, safe_min(count, dst_max - safe_strlen(dst) - 1))
#define safe_strcat(dst, dst_max, src) safe_strncat(dst, dst_max, src, safe_strlen(src)+1)
#define safe_strcmp(str1, str2) strcmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2))
#define safe_stricmp(str1, str2) _stricmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2))
#define safe_strncmp(str1, str2, count) strncmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2), count)
#define safe_strlen(str) ((str==NULL)?0:strlen(str))
#define safe_sprintf(dst, count, ...) do {_snprintf(dst, count, __VA_ARGS__); (dst)[(count)-1] = 0; } while(0)
#define safe_stprintf _sntprintf
#define safe_tcslen(str) ((str==NULL)?0:_tcslen(str))
#define safe_unref_device(dev) do {if (dev != NULL) {libusb_unref_device(dev); dev = NULL;}} while(0)
#define wchar_to_utf8_ms(wstr, str, strlen) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, strlen, NULL, NULL)
#define safe_free(p) do {if (p != NULL) {free((void *)p); p = NULL;}} while (0)
#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
#define ERR_BUFFER_SIZE 256
/*
* API macros - leveraged from libusb-win32 1.x
*/
@@ -83,31 +68,35 @@
/*
* Macros for handling DLL themselves
*/
#define DLL_HANDLE_NAME(name) __dll_##name##_handle
#define DLL_DECLARE_HANDLE(name) \
static HMODULE __dll_##name##_handle = NULL
static HMODULE DLL_HANDLE_NAME(name) = NULL
#define DLL_GET_HANDLE(name) \
do { \
__dll_##name##_handle = DLL_LOAD_LIBRARY(name); \
if (!__dll_##name##_handle) \
return LIBUSB_ERROR_OTHER; \
DLL_HANDLE_NAME(name) = DLL_LOAD_LIBRARY(name); \
if (!DLL_HANDLE_NAME(name)) \
return FALSE; \
} while (0)
#define DLL_FREE_HANDLE(name) \
do { \
if (__dll_##name##_handle) { \
FreeLibrary(__dll_##name##_handle); \
__dll_##name##_handle = NULL; \
if (DLL_HANDLE_NAME(name)) { \
FreeLibrary(DLL_HANDLE_NAME(name)); \
DLL_HANDLE_NAME(name) = NULL; \
} \
} while(0)
} while (0)
/*
* Macros for handling functions within a DLL
*/
#define DLL_FUNC_NAME(name) __dll_##name##_func_t
#define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \
typedef ret (api * __dll_##name##_func_t)args; \
static __dll_##name##_func_t prefixname = NULL
typedef ret (api * DLL_FUNC_NAME(name))args; \
static DLL_FUNC_NAME(name) prefixname = NULL
#define DLL_DECLARE_FUNC(api, ret, name, args) \
DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args)
@@ -116,22 +105,22 @@
#define DLL_LOAD_FUNC_PREFIXNAME(dll, prefixname, name, ret_on_failure) \
do { \
HMODULE h = __dll_##dll##_handle; \
prefixname = (__dll_##name##_func_t)GetProcAddress(h, \
HMODULE h = DLL_HANDLE_NAME(dll); \
prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
DLL_STRINGIFY(name)); \
if (prefixname) \
break; \
prefixname = (__dll_##name##_func_t)GetProcAddress(h, \
prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \
if (prefixname) \
break; \
prefixname = (__dll_##name##_func_t)GetProcAddress(h, \
prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
DLL_STRINGIFY(name) DLL_STRINGIFY(W)); \
if (prefixname) \
break; \
if (ret_on_failure) \
return LIBUSB_ERROR_NOT_FOUND; \
} while(0)
return FALSE; \
} while (0)
#define DLL_LOAD_FUNC(dll, name, ret_on_failure) \
DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure)
File diff suppressed because it is too large. Load diff
+74 -37
View File
@@ -26,48 +26,85 @@
#pragma once
// Missing from MinGW
#if !defined(FACILITY_SETUPAPI)
#define FACILITY_SETUPAPI 15
#endif
#include "windows_nt_shared_types.h"
typedef struct USB_CONFIGURATION_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT wTotalLength;
UCHAR bNumInterfaces;
UCHAR bConfigurationValue;
UCHAR iConfiguration;
UCHAR bmAttributes;
UCHAR MaxPower;
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
/* Windows versions */
enum windows_version {
WINDOWS_UNDEFINED,
WINDOWS_2000,
WINDOWS_XP,
WINDOWS_2003, // Also XP x64
WINDOWS_VISTA,
WINDOWS_7,
WINDOWS_8,
WINDOWS_8_1,
WINDOWS_10,
WINDOWS_11_OR_LATER
};
typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
extern enum windows_version windows_version;
int windows_common_init(struct libusb_context *ctx);
void windows_common_exit(void);
/* This call is only available from Vista */
extern BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED);
struct windows_backend {
int (*init)(struct libusb_context *ctx);
void (*exit)(struct libusb_context *ctx);
int (*get_device_list)(struct libusb_context *ctx,
struct discovered_devs **discdevs);
int (*open)(struct libusb_device_handle *dev_handle);
void (*close)(struct libusb_device_handle *dev_handle);
int (*get_device_descriptor)(struct libusb_device *device, unsigned char *buffer);
int (*get_active_config_descriptor)(struct libusb_device *device,
unsigned char *buffer, size_t len);
int (*get_config_descriptor)(struct libusb_device *device,
uint8_t config_index, unsigned char *buffer, size_t len);
int (*get_config_descriptor_by_value)(struct libusb_device *device,
uint8_t bConfigurationValue, unsigned char **buffer);
int (*get_configuration)(struct libusb_device_handle *dev_handle, int *config);
int (*set_configuration)(struct libusb_device_handle *dev_handle, int config);
int (*claim_interface)(struct libusb_device_handle *dev_handle, int interface_number);
int (*release_interface)(struct libusb_device_handle *dev_handle, int interface_number);
int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle,
int interface_number, int altsetting);
int (*clear_halt)(struct libusb_device_handle *dev_handle,
unsigned char endpoint);
int (*reset_device)(struct libusb_device_handle *dev_handle);
void (*destroy_device)(struct libusb_device *dev);
int (*submit_transfer)(struct usbi_transfer *itransfer);
int (*cancel_transfer)(struct usbi_transfer *itransfer);
void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
int (*copy_transfer_data)(struct usbi_transfer *itransfer, uint32_t io_size);
int (*get_transfer_fd)(struct usbi_transfer *itransfer);
void (*get_overlapped_result)(struct usbi_transfer *itransfer,
DWORD *io_result, DWORD *io_size);
};
struct windows_context_priv {
const struct windows_backend *backend;
};
union windows_device_priv {
struct usbdk_device_priv usbdk_priv;
struct winusb_device_priv winusb_priv;
};
union windows_device_handle_priv {
struct usbdk_device_handle_priv usbdk_priv;
struct winusb_device_handle_priv winusb_priv;
};
union windows_transfer_priv {
struct usbdk_transfer_priv usbdk_priv;
struct winusb_transfer_priv winusb_priv;
};
extern const struct windows_backend usbdk_backend;
extern const struct windows_backend winusb_backend;
unsigned long htab_hash(const char *str);
int windows_clock_gettime(int clk_id, struct timespec *tp);
typedef void(*CLEAR_TRANSFER_PRIV)(struct usbi_transfer *itransfer);
typedef int(*COPY_TRANSFER_DATA)(struct usbi_transfer *itransfer, uint32_t io_size);
typedef struct winfd *(*GET_FD)(struct usbi_transfer *transfer);
typedef void(*GET_OVERLAPPED_RESULT)(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size);
typedef struct win_backend
{
CLEAR_TRANSFER_PRIV clear_transfer_priv;
COPY_TRANSFER_DATA copy_transfer_data;
GET_FD get_fd;
GET_OVERLAPPED_RESULT get_overlapped_result;
} win_backend;
void win_nt_init(win_backend *backend);
void windows_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size);
int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready);
void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size);
#if defined(ENABLE_LOGGING)
const char *windows_error_str(DWORD retval);
const char *windows_error_str(DWORD error_code);
#endif
+147
View File
@@ -0,0 +1,147 @@
#pragma once
#include "windows_common.h"
#include <pshpack1.h>
typedef struct USB_DEVICE_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT bcdUSB;
UCHAR bDeviceClass;
UCHAR bDeviceSubClass;
UCHAR bDeviceProtocol;
UCHAR bMaxPacketSize0;
USHORT idVendor;
USHORT idProduct;
USHORT bcdDevice;
UCHAR iManufacturer;
UCHAR iProduct;
UCHAR iSerialNumber;
UCHAR bNumConfigurations;
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
typedef struct USB_CONFIGURATION_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT wTotalLength;
UCHAR bNumInterfaces;
UCHAR bConfigurationValue;
UCHAR iConfiguration;
UCHAR bmAttributes;
UCHAR MaxPower;
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
#include <poppack.h>
#define MAX_DEVICE_ID_LEN 200
typedef struct USB_DK_DEVICE_ID {
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
WCHAR InstanceID[MAX_DEVICE_ID_LEN];
} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
typedef struct USB_DK_DEVICE_INFO {
USB_DK_DEVICE_ID ID;
ULONG64 FilterID;
ULONG64 Port;
ULONG64 Speed;
USB_DEVICE_DESCRIPTOR DeviceDescriptor;
} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
typedef struct USB_DK_ISO_TRANSFER_RESULT {
ULONG64 ActualLength;
ULONG64 TransferResult;
} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
typedef struct USB_DK_GEN_TRANSFER_RESULT {
ULONG64 BytesTransferred;
ULONG64 UsbdStatus; // USBD_STATUS code
} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT;
typedef struct USB_DK_TRANSFER_RESULT {
USB_DK_GEN_TRANSFER_RESULT GenResult;
PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
typedef struct USB_DK_TRANSFER_REQUEST {
ULONG64 EndpointAddress;
PVOID64 Buffer;
ULONG64 BufferLength;
ULONG64 TransferType;
ULONG64 IsochronousPacketsArraySize;
PVOID64 IsochronousPacketsArray;
USB_DK_TRANSFER_RESULT Result;
} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
struct usbdk_device_priv {
USB_DK_DEVICE_INFO info;
PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
HANDLE redirector_handle;
HANDLE system_handle;
uint8_t active_configuration;
};
struct winusb_device_priv {
bool initialized;
bool root_hub;
uint8_t active_config;
uint8_t depth; // distance to HCD
const struct windows_usb_api_backend *apib;
char *dev_id;
char *path; // device interface path
int sub_api; // for WinUSB-like APIs
struct {
char *path; // each interface needs a device interface path,
const struct windows_usb_api_backend *apib; // an API backend (multiple drivers support),
int sub_api;
int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
uint8_t *endpoint;
int current_altsetting;
bool restricted_functionality; // indicates if the interface functionality is restricted
// by Windows (eg. HID keyboards or mice cannot do R/W)
} usb_interface[USB_MAXINTERFACES];
struct hid_device_priv *hid;
USB_DEVICE_DESCRIPTOR dev_descriptor;
PUSB_CONFIGURATION_DESCRIPTOR *config_descriptor; // list of pointers to the cached config descriptors
};
struct usbdk_device_handle_priv {
// Not currently used
char dummy;
};
struct winusb_device_handle_priv {
int active_interface;
struct {
HANDLE dev_handle; // WinUSB needs an extra handle for the file
HANDLE api_handle; // used by the API to communicate with the device
} interface_handle[USB_MAXINTERFACES];
int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
};
struct usbdk_transfer_priv {
USB_DK_TRANSFER_REQUEST request;
struct winfd pollable_fd;
HANDLE system_handle;
PULONG64 IsochronousPacketsArray;
PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
};
struct winusb_transfer_priv {
struct winfd pollable_fd;
HANDLE handle;
uint8_t interface_number;
uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
uint8_t *hid_dest; // transfer buffer destination, required for HID
size_t hid_expected_size;
// For isochronous transfers with LibUSBk driver:
void *iso_context;
// For isochronous transfers with Microsoft WinUSB driver:
void *isoch_buffer_handle; // The isoch_buffer_handle to free at the end of the transfer
BOOL iso_break_stream; // Whether the isoch. stream was to be continued in the last call of libusb_submit_transfer.
// As we this structure is zeroed out upon initialization, we need to use inverse logic here.
libusb_transfer_cb_fn iso_user_callback; // Original transfer callback of the user. Might be used for isochronous transfers.
};
+174 -260
View File
@@ -24,19 +24,11 @@
#include <config.h>
#include <windows.h>
#include <cfgmgr32.h>
#include <stdio.h>
#include "libusbi.h"
#include "windows_common.h"
#include "windows_nt_common.h"
#define ULONG64 uint64_t
#define PVOID64 uint64_t
typedef CONST WCHAR *PCWCHAR;
#define wcsncpy_s wcsncpy
#include "windows_usbdk.h"
#if !defined(STATUS_SUCCESS)
@@ -53,7 +45,7 @@ typedef LONG NTSTATUS;
#endif
#if !defined(USBD_SUCCESS)
typedef int32_t USBD_STATUS;
typedef LONG USBD_STATUS;
#define USBD_SUCCESS(Status) ((USBD_STATUS) (Status) >= 0)
#define USBD_PENDING(Status) ((ULONG) (Status) >> 30 == 1)
#define USBD_ERROR(Status) ((USBD_STATUS) (Status) < 0)
@@ -64,24 +56,6 @@ typedef int32_t USBD_STATUS;
#define USBD_STATUS_CANCELED ((USBD_STATUS) 0xc0010000)
#endif
static void backend_init(void);
static int concurrent_usage = -1;
struct usbdk_device_priv {
USB_DK_DEVICE_INFO info;
PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
HANDLE redirector_handle;
uint8_t active_configuration;
};
struct usbdk_transfer_priv {
USB_DK_TRANSFER_REQUEST request;
struct winfd pollable_fd;
PULONG64 IsochronousPacketsArray;
PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
};
static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
{
return (struct usbdk_device_priv *)dev->os_priv;
@@ -115,7 +89,7 @@ static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
if (api_ptr == NULL)
usbi_err(ctx, "UsbDkHelper API %s not found, error %d", api_name, GetLastError());
usbi_err(ctx, "UsbDkHelper API %s not found: %s", api_name, windows_error_str(0));
return api_ptr;
}
@@ -132,7 +106,7 @@ static int load_usbdk_helper_dll(struct libusb_context *ctx)
{
usbdk_helper.module = LoadLibraryA("UsbDkHelper");
if (usbdk_helper.module == NULL) {
usbi_err(ctx, "Failed to load UsbDkHelper.dll, error %d", GetLastError());
usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0));
return LIBUSB_ERROR_NOT_FOUND;
}
@@ -198,44 +172,41 @@ error_unload:
static int usbdk_init(struct libusb_context *ctx)
{
int r;
SC_HANDLE managerHandle;
SC_HANDLE serviceHandle;
if (++concurrent_usage == 0) { // First init?
backend_init();
r = load_usbdk_helper_dll(ctx);
if (r)
goto init_exit;
init_polling();
r = windows_common_init(ctx);
if (r)
goto init_exit;
}
// At this stage, either we went through full init successfully, or didn't need to
r = LIBUSB_SUCCESS;
init_exit:
if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
exit_polling();
windows_common_exit();
unload_usbdk_helper_dll();
managerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (managerHandle == NULL) {
usbi_warn(ctx, "failed to open service control manager: %s", windows_error_str(0));
return LIBUSB_ERROR_OTHER;
}
if (r != LIBUSB_SUCCESS)
--concurrent_usage; // Not expected to call libusb_exit if we failed.
serviceHandle = OpenServiceA(managerHandle, "UsbDk", GENERIC_READ);
CloseServiceHandle(managerHandle);
return r;
if (serviceHandle == NULL) {
if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
usbi_warn(ctx, "failed to open UsbDk service: %s", windows_error_str(0));
return LIBUSB_ERROR_NOT_FOUND;
}
CloseServiceHandle(serviceHandle);
return load_usbdk_helper_dll(ctx);
}
static void usbdk_exit(struct libusb_context *ctx)
{
UNUSED(ctx);
unload_usbdk_helper_dll();
}
static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
PUSB_DK_DEVICE_ID id, unsigned long *session_id)
{
char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID)];
char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID) + 1];
if (sprintf(dev_identity, "%S%S", id->DeviceID, id->InstanceID) == -1) {
if (snprintf(dev_identity, sizeof(dev_identity), "%S%S", id->DeviceID, id->InstanceID) == -1) {
usbi_warn(ctx, "cannot form device identity", id->DeviceID);
return LIBUSB_ERROR_NOT_SUPPORTED;
}
@@ -299,11 +270,11 @@ static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
dev->port_number = (uint8_t)info->Port;
dev->parent_dev = NULL;
//Addresses in libusb are 1-based
// Addresses in libusb are 1-based
dev->device_address = (uint8_t)(info->Port + 1);
dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
dev->device_descriptor = info->DeviceDescriptor;
memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
switch (info->Speed) {
case LowSpeed:
@@ -333,7 +304,7 @@ static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_d
ULONG dev_number;
PUSB_DK_DEVICE_INFO devices;
if(!usbdk_helper.GetDevicesList(&devices, &dev_number))
if (!usbdk_helper.GetDevicesList(&devices, &dev_number))
return LIBUSB_ERROR_OTHER;
for (i = 0; i < dev_number; i++) {
@@ -374,26 +345,16 @@ func_exit:
return r;
}
static void usbdk_exit(void)
{
if (--concurrent_usage < 0) {
windows_common_exit();
exit_polling();
unload_usbdk_helper_dll();
}
}
static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian)
static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer)
{
struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
*host_endian = 0;
return LIBUSB_SUCCESS;
}
static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len)
{
struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
PUSB_CONFIGURATION_DESCRIPTOR config_header;
@@ -406,15 +367,31 @@ static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config
size = min(config_header->wTotalLength, len);
memcpy(buffer, config_header, size);
*host_endian = 0;
return (int)size;
}
static inline int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian)
static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
unsigned char **buffer)
{
struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
PUSB_CONFIGURATION_DESCRIPTOR config_header;
uint8_t index;
for (index = 0; index < dev->num_configurations; index++) {
config_header = priv->config_descriptors[index];
if (config_header->bConfigurationValue == bConfigurationValue) {
*buffer = (unsigned char *)priv->config_descriptors[index];
return (int)config_header->wTotalLength;
}
}
return LIBUSB_ERROR_NOT_FOUND;
}
static int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len)
{
return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
buffer, len, host_endian);
buffer, len);
}
static int usbdk_open(struct libusb_device_handle *dev_handle)
@@ -427,6 +404,8 @@ static int usbdk_open(struct libusb_device_handle *dev_handle)
return LIBUSB_ERROR_OTHER;
}
priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
return LIBUSB_SUCCESS;
}
@@ -434,10 +413,8 @@ static void usbdk_close(struct libusb_device_handle *dev_handle)
{
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
if (!usbdk_helper.StopRedirect(priv->redirector_handle)) {
struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
usbi_err(ctx, "Redirector shutdown failed");
}
if (!usbdk_helper.StopRedirect(priv->redirector_handle))
usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed");
}
static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
@@ -463,7 +440,7 @@ static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int if
static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
{
struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
struct libusb_context *ctx = HANDLE_CTX(dev_handle);
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
@@ -483,7 +460,7 @@ static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int
static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
{
struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
struct libusb_context *ctx = HANDLE_CTX(dev_handle);
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
@@ -496,7 +473,7 @@ static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned ch
static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
{
struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
struct libusb_context *ctx = HANDLE_CTX(dev_handle);
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
@@ -507,27 +484,6 @@ static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
return LIBUSB_SUCCESS;
}
static int usbdk_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface)
{
UNUSED(dev_handle);
UNUSED(iface);
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int usbdk_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
{
UNUSED(dev_handle);
UNUSED(iface);
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int usbdk_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
{
UNUSED(dev_handle);
UNUSED(iface);
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static void usbdk_destroy_device(struct libusb_device *dev)
{
struct usbdk_device_priv* p = _usbdk_device_priv(dev);
@@ -536,12 +492,14 @@ static void usbdk_destroy_device(struct libusb_device *dev)
usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
}
static void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
{
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
usbi_free_fd(&transfer_priv->pollable_fd);
usbi_close(transfer_priv->pollable_fd.fd);
transfer_priv->pollable_fd = INVALID_WINFD;
transfer_priv->system_handle = NULL;
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
safe_free(transfer_priv->IsochronousPacketsArray);
@@ -554,47 +512,30 @@ static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
struct winfd wfd;
ULONG Length;
struct libusb_context *ctx = TRANSFER_CTX(transfer);
OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
TransferResult transResult;
HANDLE sysHandle;
sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
wfd = usbi_create_fd(sysHandle, RW_READ, NULL, NULL);
// Always use the handle returned from usbi_create_fd (wfd.handle)
if (wfd.fd < 0)
return LIBUSB_ERROR_NO_MEM;
transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
transfer_priv->request.BufferLength = transfer->length;
transfer_priv->request.TransferType = ControlTransferType;
transfer_priv->pollable_fd = INVALID_WINFD;
Length = (ULONG)transfer->length;
if (IS_XFERIN(transfer))
transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN)
transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else
transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
switch (transResult) {
case TransferSuccess:
wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
wfd.overlapped->InternalHigh = (DWORD)Length;
windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
break;
case TransferSuccessAsync:
break;
case TransferFailure:
usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
usbi_free_fd(&wfd);
return LIBUSB_ERROR_IO;
}
// Use priv_transfer to store data needed for async polling
transfer_priv->pollable_fd = wfd;
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
return LIBUSB_SUCCESS;
}
@@ -603,12 +544,11 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
struct winfd wfd;
struct libusb_context *ctx = TRANSFER_CTX(transfer);
OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
TransferResult transferRes;
HANDLE sysHandle;
transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
transfer_priv->request.BufferLength = transfer->length;
transfer_priv->request.EndpointAddress = transfer->endpoint;
@@ -617,42 +557,29 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
transfer_priv->request.TransferType = BulkTransferType;
break;
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
transfer_priv->request.TransferType = IntertuptTransferType;
transfer_priv->request.TransferType = InterruptTransferType;
break;
default:
usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer. %s", transfer->type, windows_error_str(0));
usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM;
}
transfer_priv->pollable_fd = INVALID_WINFD;
sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
// Always use the handle returned from usbi_create_fd (wfd.handle)
if (wfd.fd < 0)
return LIBUSB_ERROR_NO_MEM;
if (IS_XFERIN(transfer))
transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else
transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
switch (transferRes) {
case TransferSuccess:
wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
break;
case TransferSuccessAsync:
break;
case TransferFailure:
usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
usbi_free_fd(&wfd);
return LIBUSB_ERROR_IO;
}
transfer_priv->pollable_fd = wfd;
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
return LIBUSB_SUCCESS;
}
@@ -661,68 +588,81 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
struct winfd wfd;
struct libusb_context *ctx = TRANSFER_CTX(transfer);
OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
TransferResult transferRes;
int i;
HANDLE sysHandle;
transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
transfer_priv->request.BufferLength = transfer->length;
transfer_priv->request.EndpointAddress = transfer->endpoint;
transfer_priv->request.TransferType = IsochronousTransferType;
transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
transfer_priv->request.IsochronousPacketsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousPacketsArray;
transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray;
if (!transfer_priv->IsochronousPacketsArray) {
usbi_err(ctx, "Allocation of IsochronousPacketsArray is failed, %s", windows_error_str(0));
return LIBUSB_ERROR_IO;
usbi_err(ctx, "Allocation of IsochronousPacketsArray failed");
return LIBUSB_ERROR_NO_MEM;
}
transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousResultsArray;
transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray;
if (!transfer_priv->IsochronousResultsArray) {
usbi_err(ctx, "Allocation of isochronousResultsArray is failed, %s", windows_error_str(0));
free(transfer_priv->IsochronousPacketsArray);
return LIBUSB_ERROR_IO;
usbi_err(ctx, "Allocation of isochronousResultsArray failed");
return LIBUSB_ERROR_NO_MEM;
}
for (i = 0; i < transfer->num_iso_packets; i++)
transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
transfer_priv->pollable_fd = INVALID_WINFD;
sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
// Always use the handle returned from usbi_create_fd (wfd.handle)
if (wfd.fd < 0) {
free(transfer_priv->IsochronousPacketsArray);
free(transfer_priv->IsochronousResultsArray);
return LIBUSB_ERROR_NO_MEM;
}
if (IS_XFERIN(transfer))
transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else
transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
switch (transferRes) {
case TransferSuccess:
wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
break;
case TransferSuccessAsync:
break;
case TransferFailure:
usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
usbi_free_fd(&wfd);
free(transfer_priv->IsochronousPacketsArray);
free(transfer_priv->IsochronousResultsArray);
return LIBUSB_ERROR_IO;
}
return LIBUSB_SUCCESS;
}
static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer,
short events, int (*transfer_fn)(struct usbi_transfer *))
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct libusb_context *ctx = TRANSFER_CTX(transfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct winfd wfd;
int r;
wfd = usbi_create_fd();
if (wfd.fd < 0)
return LIBUSB_ERROR_NO_MEM;
r = usbi_add_pollfd(ctx, wfd.fd, events);
if (r) {
usbi_close(wfd.fd);
return r;
}
// Use transfer_priv to store data needed for async polling
transfer_priv->pollable_fd = wfd;
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
transfer_priv->system_handle = priv->system_handle;
r = transfer_fn(itransfer);
if (r != LIBUSB_SUCCESS) {
usbi_remove_pollfd(ctx, wfd.fd);
usbdk_clear_transfer_priv(itransfer);
return r;
}
return LIBUSB_SUCCESS;
}
@@ -730,33 +670,52 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
int (*transfer_fn)(struct usbi_transfer *);
short events;
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
return usbdk_do_control_transfer(itransfer);
events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT;
transfer_fn = usbdk_do_control_transfer;
break;
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
else
return usbdk_do_bulk_transfer(itransfer);
events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
transfer_fn = usbdk_do_bulk_transfer;
break;
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
return usbdk_do_iso_transfer(itransfer);
events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
transfer_fn = usbdk_do_iso_transfer;
break;
default:
usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM;
}
return usbdk_do_submit_transfer(itransfer, events, transfer_fn);
}
static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
struct libusb_context *ctx = TRANSFER_CTX(transfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct winfd *pollable_fd = &transfer_priv->pollable_fd;
if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE;
if (pCancelIoEx != NULL) {
// Use CancelIoEx if available to cancel just a single transfer
if (!pCancelIoEx(priv->system_handle, pollable_fd->overlapped)) {
usbi_err(ctx, "CancelIoEx failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE;
}
} else {
if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE;
}
}
return LIBUSB_SUCCESS;
@@ -781,16 +740,16 @@ static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
}
}
static int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
static int usbdk_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
{
itransfer->transferred += io_size;
return LIBUSB_TRANSFER_COMPLETED;
}
static struct winfd *windows_get_fd(struct usbi_transfer *transfer)
static int usbdk_get_transfer_fd(struct usbi_transfer *itransfer)
{
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
return &transfer_priv->pollable_fd;
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
return transfer_priv->pollable_fd.fd;
}
static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
@@ -799,30 +758,28 @@ static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
return NO_ERROR;
switch (UsbdStatus) {
case USBD_STATUS_STALL_PID:
case USBD_STATUS_ENDPOINT_HALTED:
case USBD_STATUS_BAD_START_FRAME:
return ERROR_GEN_FAILURE;
case USBD_STATUS_TIMEOUT:
return ERROR_SEM_TIMEOUT;
case USBD_STATUS_CANCELED:
return ERROR_OPERATION_ABORTED;
default:
return ERROR_FUNCTION_FAILED;
return ERROR_GEN_FAILURE;
}
}
static void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size)
static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size)
{
if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
|| GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { // Regular async overlapped
struct libusb_transfer *ltransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct winfd *pollable_fd = &transfer_priv->pollable_fd;
if (ltransfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
int i;
if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
|| GetOverlappedResult(transfer_priv->system_handle, pollable_fd->overlapped, io_size, FALSE)) { // Regular async overlapped
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
ULONG64 i;
for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
struct libusb_iso_packet_descriptor *lib_desc = &ltransfer->iso_packet_desc[i];
struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
case STATUS_SUCCESS:
@@ -839,78 +796,35 @@ static void windows_get_overlapped_result(struct usbi_transfer *transfer, struct
}
}
*io_size = (DWORD) transfer_priv->request.Result.GenResult.BytesTransferred;
*io_result = usbdk_translate_usbd_status((USBD_STATUS) transfer_priv->request.Result.GenResult.UsbdStatus);
}
else {
*io_size = (DWORD)transfer_priv->request.Result.GenResult.BytesTransferred;
*io_result = usbdk_translate_usbd_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus);
} else {
*io_result = GetLastError();
}
}
static int usbdk_clock_gettime(int clk_id, struct timespec *tp)
{
return windows_clock_gettime(clk_id, tp);
}
const struct usbi_os_backend usbdk_backend = {
"Windows",
USBI_CAP_HAS_HID_ACCESS,
const struct windows_backend usbdk_backend = {
usbdk_init,
usbdk_exit,
usbdk_get_device_list,
NULL,
usbdk_open,
usbdk_close,
usbdk_get_device_descriptor,
usbdk_get_active_config_descriptor,
usbdk_get_config_descriptor,
NULL,
usbdk_get_config_descriptor_by_value,
usbdk_get_configuration,
usbdk_set_configuration,
usbdk_claim_interface,
usbdk_release_interface,
usbdk_set_interface_altsetting,
usbdk_clear_halt,
usbdk_reset_device,
NULL,
NULL,
NULL, // dev_mem_alloc()
NULL, // dev_mem_free()
usbdk_kernel_driver_active,
usbdk_detach_kernel_driver,
usbdk_attach_kernel_driver,
usbdk_destroy_device,
usbdk_submit_transfer,
usbdk_cancel_transfer,
windows_clear_transfer_priv,
windows_handle_events,
NULL,
usbdk_clock_gettime,
#if defined(USBI_TIMERFD_AVAILABLE)
NULL,
#endif
sizeof(struct usbdk_device_priv),
0,
sizeof(struct usbdk_transfer_priv),
usbdk_clear_transfer_priv,
usbdk_copy_transfer_data,
usbdk_get_transfer_fd,
usbdk_get_overlapped_result,
};
static void backend_init(void)
{
win_backend backend;
backend.clear_transfer_priv = windows_clear_transfer_priv;
backend.copy_transfer_data = windows_copy_transfer_data;
backend.get_fd = windows_get_fd;
backend.get_overlapped_result = windows_get_overlapped_result;
win_nt_init(&backend);
}
+3 -46
View File
@@ -23,56 +23,13 @@
#pragma once
typedef struct tag_USB_DK_DEVICE_ID {
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
WCHAR InstanceID[MAX_DEVICE_ID_LEN];
} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
#include "windows_nt_common.h"
static inline void UsbDkFillIDStruct(USB_DK_DEVICE_ID *ID, PCWCHAR DeviceID, PCWCHAR InstanceID)
{
wcsncpy_s(ID->DeviceID, DeviceID, MAX_DEVICE_ID_LEN);
wcsncpy_s(ID->InstanceID, InstanceID, MAX_DEVICE_ID_LEN);
}
typedef struct tag_USB_DK_DEVICE_INFO {
USB_DK_DEVICE_ID ID;
ULONG64 FilterID;
ULONG64 Port;
ULONG64 Speed;
USB_DEVICE_DESCRIPTOR DeviceDescriptor;
} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
typedef struct tag_USB_DK_CONFIG_DESCRIPTOR_REQUEST {
typedef struct USB_DK_CONFIG_DESCRIPTOR_REQUEST {
USB_DK_DEVICE_ID ID;
ULONG64 Index;
} USB_DK_CONFIG_DESCRIPTOR_REQUEST, *PUSB_DK_CONFIG_DESCRIPTOR_REQUEST;
typedef struct tag_USB_DK_ISO_TRANSFER_RESULT {
ULONG64 ActualLength;
ULONG64 TransferResult;
} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
typedef struct tag_USB_DK_GEN_TRANSFER_RESULT {
ULONG64 BytesTransferred;
ULONG64 UsbdStatus; // USBD_STATUS code
} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT;
typedef struct tag_USB_DK_TRANSFER_RESULT {
USB_DK_GEN_TRANSFER_RESULT GenResult;
PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
typedef struct tag_USB_DK_TRANSFER_REQUEST {
ULONG64 EndpointAddress;
PVOID64 Buffer;
ULONG64 BufferLength;
ULONG64 TransferType;
ULONG64 IsochronousPacketsArraySize;
PVOID64 IsochronousPacketsArray;
USB_DK_TRANSFER_RESULT Result;
} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
typedef enum {
TransferFailure = 0,
TransferSuccess,
@@ -90,7 +47,7 @@ typedef enum {
typedef enum {
ControlTransferType,
BulkTransferType,
IntertuptTransferType,
InterruptTransferType,
IsochronousTransferType
} USB_DK_TRANSFER_TYPE;
+1383 -1310
View File
File diff suppressed because it is too large. Load diff
+244 -414
View File
@@ -36,15 +36,14 @@
#endif
// Missing from MSVC6 setupapi.h
#if !defined(SPDRP_ADDRESS)
#ifndef SPDRP_ADDRESS
#define SPDRP_ADDRESS 28
#endif
#if !defined(SPDRP_INSTALL_STATE)
#ifndef SPDRP_INSTALL_STATE
#define SPDRP_INSTALL_STATE 34
#endif
#define MAX_CTRL_BUFFER_LENGTH 4096
#define MAX_USB_DEVICES 256
#define MAX_USB_STRING_LENGTH 128
#define MAX_HID_REPORT_SIZE 1024
#define MAX_HID_DESCRIPTOR_SIZE 256
@@ -61,17 +60,17 @@
// http://msdn.microsoft.com/en-us/library/ff545978.aspx
// http://msdn.microsoft.com/en-us/library/ff545972.aspx
// http://msdn.microsoft.com/en-us/library/ff545982.aspx
#if !defined(GUID_DEVINTERFACE_USB_HOST_CONTROLLER)
const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} };
#ifndef GUID_DEVINTERFACE_USB_HOST_CONTROLLER
const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = {0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27}};
#endif
#if !defined(GUID_DEVINTERFACE_USB_DEVICE)
const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} };
#ifndef GUID_DEVINTERFACE_USB_DEVICE
const GUID GUID_DEVINTERFACE_USB_DEVICE = {0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}};
#endif
#if !defined(GUID_DEVINTERFACE_USB_HUB)
const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} };
#ifndef GUID_DEVINTERFACE_USB_HUB
const GUID GUID_DEVINTERFACE_USB_HUB = {0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8}};
#endif
#if !defined(GUID_DEVINTERFACE_LIBUSB0_FILTER)
const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9} };
#ifndef GUID_DEVINTERFACE_LIBUSB0_FILTER
const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = {0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9}};
#endif
@@ -84,8 +83,6 @@ const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8
#define USB_API_WINUSBX 3
#define USB_API_HID 4
#define USB_API_MAX 5
// The following is used to indicate if the HID or composite extra props have already been set.
#define USB_API_SET (1 << USB_API_MAX)
// Sub-APIs for WinUSB-like driver APIs (WinUSB, libusbK, libusb-win32 through the libusbK DLL)
// Must have the same values as the KUSB_DRVID enum from libusbk.h
@@ -95,15 +92,13 @@ const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8
#define SUB_API_WINUSB 2
#define SUB_API_MAX 3
#define WINUSBX_DRV_NAMES {"libusbK", "libusb0", "WinUSB"}
struct windows_usb_api_backend {
const uint8_t id;
const char *designation;
const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
const char * const designation;
const char * const * const driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
const uint8_t nb_driver_names;
int (*init)(int sub_api, struct libusb_context *ctx);
int (*exit)(int sub_api);
int (*init)(struct libusb_context *ctx);
void (*exit)(void);
int (*open)(int sub_api, struct libusb_device_handle *dev_handle);
void (*close)(int sub_api, struct libusb_device_handle *dev_handle);
int (*configure_endpoints)(int sub_api, struct libusb_device_handle *dev_handle, int iface);
@@ -123,9 +118,16 @@ struct windows_usb_api_backend {
extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
#define PRINT_UNSUPPORTED_API(fname) \
usbi_dbg("unsupported API call for '" \
#fname "' (unrecognized device driver)"); \
return LIBUSB_ERROR_NOT_SUPPORTED;
usbi_dbg("unsupported API call for '%s' " \
"(unrecognized device driver)", #fname)
#define CHECK_SUPPORTED_API(apip, fname) \
do { \
if ((apip)->fname == NULL) { \
PRINT_UNSUPPORTED_API(fname); \
return LIBUSB_ERROR_NOT_SUPPORTED; \
} \
} while (0)
/*
* private structures definition
@@ -154,15 +156,16 @@ struct libusb_hid_descriptor {
#define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN)
#define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type))
#ifndef CTL_CODE
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#endif
// The following are used for HID reports IOCTLs
#define HID_CTL_CODE(id) \
CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS)
#define HID_BUFFER_CTL_CODE(id) \
CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HID_IN_CTL_CODE(id) \
CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS)
CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define HID_OUT_CTL_CODE(id) \
CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
#define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104)
@@ -193,106 +196,57 @@ struct hid_device_priv {
uint16_t input_report_size;
uint16_t output_report_size;
uint16_t feature_report_size;
uint16_t usage;
uint16_t usagePage;
WCHAR string[3][MAX_USB_STRING_LENGTH];
uint8_t string_index[3]; // man, prod, ser
};
struct windows_device_priv {
uint8_t depth; // distance to HCD
uint8_t port; // port number on the hub
uint8_t active_config;
struct windows_usb_api_backend const *apib;
char *path; // device interface path
int sub_api; // for WinUSB-like APIs
struct {
char *path; // each interface needs a device interface path,
struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support),
int sub_api;
int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
uint8_t *endpoint;
bool restricted_functionality; // indicates if the interface functionality is restricted
// by Windows (eg. HID keyboards or mice cannot do R/W)
} usb_interface[USB_MAXINTERFACES];
struct hid_device_priv *hid;
USB_DEVICE_DESCRIPTOR dev_descriptor;
unsigned char **config_descriptor; // list of pointers to the cached config descriptors
};
static inline struct windows_device_priv *_device_priv(struct libusb_device *dev)
static inline struct winusb_device_priv *_device_priv(struct libusb_device *dev)
{
return (struct windows_device_priv *)dev->os_priv;
return (struct winusb_device_priv *)dev->os_priv;
}
static inline struct windows_device_priv *windows_device_priv_init(struct libusb_device *dev)
static inline struct winusb_device_priv *winusb_device_priv_init(struct libusb_device *dev)
{
struct windows_device_priv *p = _device_priv(dev);
struct winusb_device_priv *p = _device_priv(dev);
int i;
p->depth = 0;
p->port = 0;
p->path = NULL;
p->apib = &usb_api_backend[USB_API_UNSUPPORTED];
p->sub_api = SUB_API_NOTSET;
p->hid = NULL;
p->active_config = 0;
p->config_descriptor = NULL;
memset(&p->dev_descriptor, 0, sizeof(USB_DEVICE_DESCRIPTOR));
for (i = 0; i < USB_MAXINTERFACES; i++) {
p->usb_interface[i].path = NULL;
p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED];
p->usb_interface[i].sub_api = SUB_API_NOTSET;
p->usb_interface[i].nb_endpoints = 0;
p->usb_interface[i].endpoint = NULL;
p->usb_interface[i].restricted_functionality = false;
}
return p;
}
static inline void windows_device_priv_release(struct libusb_device *dev)
static inline void winusb_device_priv_release(struct libusb_device *dev)
{
struct windows_device_priv *p = _device_priv(dev);
struct winusb_device_priv *p = _device_priv(dev);
int i;
safe_free(p->path);
free(p->dev_id);
free(p->path);
if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) {
for (i = 0; i < dev->num_configurations; i++)
safe_free(p->config_descriptor[i]);
free(p->config_descriptor[i]);
}
safe_free(p->config_descriptor);
safe_free(p->hid);
free(p->config_descriptor);
free(p->hid);
for (i = 0; i < USB_MAXINTERFACES; i++) {
safe_free(p->usb_interface[i].path);
safe_free(p->usb_interface[i].endpoint);
free(p->usb_interface[i].path);
free(p->usb_interface[i].endpoint);
}
}
struct interface_handle_t {
HANDLE dev_handle; // WinUSB needs an extra handle for the file
HANDLE api_handle; // used by the API to communicate with the device
};
struct windows_device_handle_priv {
int active_interface;
struct interface_handle_t interface_handle[USB_MAXINTERFACES];
int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
};
static inline struct windows_device_handle_priv *_device_handle_priv(
static inline struct winusb_device_handle_priv *_device_handle_priv(
struct libusb_device_handle *handle)
{
return (struct windows_device_handle_priv *)handle->os_priv;
return (struct winusb_device_handle_priv *)handle->os_priv;
}
// used for async polling functions
struct windows_transfer_priv {
struct winfd pollable_fd;
uint8_t interface_number;
uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
uint8_t *hid_dest; // transfer buffer destination, required for HID
size_t hid_expected_size;
};
// used to match a device driver (including filter drivers) against a supported API
struct driver_lookup {
char list[MAX_KEY_LENGTH + 1]; // REG_MULTI_SZ list of services (driver) names
@@ -300,34 +254,6 @@ struct driver_lookup {
const char* designation; // internal designation (for debug output)
};
/* OLE32 dependency */
DLL_DECLARE_HANDLE(OLE32);
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID));
/* Kernel32 dependencies */
DLL_DECLARE_HANDLE(Kernel32);
/* This call is only available from XP SP2 */
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, IsWow64Process, (HANDLE, PBOOL));
/* SetupAPI dependencies */
DLL_DECLARE_HANDLE(SetupAPI);
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA,
const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA,
PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,
PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD));
/* AdvAPI32 dependencies */
DLL_DECLARE_HANDLE(AdvAPI32);
DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
/*
* Windows DDK API definitions. Most of it copied from MinGW's includes
*/
@@ -336,58 +262,64 @@ typedef DEVNODE *PDEVNODE, *PDEVINST;
typedef DWORD RETURN_TYPE;
typedef RETURN_TYPE CONFIGRET;
#define CR_SUCCESS 0x00000000
#define CR_NO_SUCH_DEVNODE 0x0000000D
#define CR_SUCCESS 0x00000000
#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE
#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG
#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING
#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE
#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT
/* Cfgmgr32 dependencies */
DLL_DECLARE_HANDLE(Cfgmgr32);
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG));
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG));
#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS
#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE
#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE
#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS
#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR
#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR
#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION
#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION
#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE
#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE
#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME
/* AdvAPI32 dependencies */
DLL_DECLARE_HANDLE(AdvAPI32);
DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
#define USB_GET_NODE_INFORMATION 258
#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260
#define USB_GET_NODE_CONNECTION_NAME 261
#define USB_GET_HUB_CAPABILITIES 271
#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX)
#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274
/* OLE32 dependency */
DLL_DECLARE_HANDLE(OLE32);
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HRESULT, p, IIDFromString, (LPCOLESTR, LPIID));
/* SetupAPI dependencies */
DLL_DECLARE_HANDLE(SetupAPI);
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (LPCGUID, PCSTR, HWND, DWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA,
LPCGUID, DWORD, PSP_DEVICE_INTERFACE_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInstanceIdA, (HDEVINFO, PSP_DEVINFO_DATA,
PCSTR, DWORD, PDWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA,
PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,
PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD));
#ifndef USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260
#endif
#if !defined(USB_GET_HUB_CAPABILITIES_EX)
#define USB_GET_HUB_CAPABILITIES_EX 276
#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX
#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274
#endif
#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2)
#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX_V2
#define USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 279
#endif
#ifndef METHOD_BUFFERED
#define METHOD_BUFFERED 0
#endif
#ifndef FILE_ANY_ACCESS
#define FILE_ANY_ACCESS 0x00000000
#endif
#ifndef FILE_DEVICE_UNKNOWN
#define FILE_DEVICE_UNKNOWN 0x00000022
#endif
#ifndef FILE_DEVICE_USB
#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
#endif
#ifndef CTL_CODE
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#endif
#define USB_CTL_CODE(id) \
CTL_CODE(FILE_DEVICE_USB, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \
USB_CTL_CODE(USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION)
#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \
USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX)
#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \
USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2)
typedef enum USB_CONNECTION_STATUS {
NoDeviceConnected,
@@ -406,42 +338,25 @@ typedef enum USB_HUB_NODE {
UsbMIParent
} USB_HUB_NODE;
/* Cfgmgr32.dll interface */
DLL_DECLARE_HANDLE(Cfgmgr32);
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG));
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG));
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG));
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG));
#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \
CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_GET_HUB_CAPABILITIES \
CTL_CODE(FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \
CTL_CODE(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_GET_ROOT_HUB_NAME \
CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_GET_NODE_INFORMATION \
CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \
CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \
CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES \
CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_ATTRIBUTES, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_GET_NODE_CONNECTION_NAME \
CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Most of the structures below need to be packed
#pragma pack(push, 1)
#include <pshpack1.h>
typedef struct _USB_DESCRIPTOR_REQUEST {
ULONG ConnectionIndex;
struct {
UCHAR bmRequest;
UCHAR bRequest;
USHORT wValue;
USHORT wIndex;
USHORT wLength;
} SetupPacket;
// UCHAR Data[0];
} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST;
typedef struct _USB_CONFIGURATION_DESCRIPTOR_SHORT {
USB_DESCRIPTOR_REQUEST req;
USB_CONFIGURATION_DESCRIPTOR desc;
} USB_CONFIGURATION_DESCRIPTOR_SHORT;
typedef struct USB_INTERFACE_DESCRIPTOR {
UCHAR bLength;
@@ -455,103 +370,7 @@ typedef struct USB_INTERFACE_DESCRIPTOR {
UCHAR iInterface;
} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;
typedef struct USB_CONFIGURATION_DESCRIPTOR_SHORT {
struct {
ULONG ConnectionIndex;
struct {
UCHAR bmRequest;
UCHAR bRequest;
USHORT wValue;
USHORT wIndex;
USHORT wLength;
} SetupPacket;
} req;
USB_CONFIGURATION_DESCRIPTOR data;
} USB_CONFIGURATION_DESCRIPTOR_SHORT;
typedef struct USB_ENDPOINT_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bEndpointAddress;
UCHAR bmAttributes;
USHORT wMaxPacketSize;
UCHAR bInterval;
} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;
typedef struct USB_DESCRIPTOR_REQUEST {
ULONG ConnectionIndex;
struct {
UCHAR bmRequest;
UCHAR bRequest;
USHORT wValue;
USHORT wIndex;
USHORT wLength;
} SetupPacket;
// UCHAR Data[0];
} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST;
typedef struct USB_HUB_DESCRIPTOR {
UCHAR bDescriptorLength;
UCHAR bDescriptorType;
UCHAR bNumberOfPorts;
USHORT wHubCharacteristics;
UCHAR bPowerOnToPowerGood;
UCHAR bHubControlCurrent;
UCHAR bRemoveAndPowerMask[64];
} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;
typedef struct USB_ROOT_HUB_NAME {
ULONG ActualLength;
WCHAR RootHubName[1];
} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME;
typedef struct USB_ROOT_HUB_NAME_FIXED {
ULONG ActualLength;
WCHAR RootHubName[MAX_PATH_LENGTH];
} USB_ROOT_HUB_NAME_FIXED;
typedef struct USB_NODE_CONNECTION_NAME {
ULONG ConnectionIndex;
ULONG ActualLength;
WCHAR NodeName[1];
} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME;
typedef struct USB_NODE_CONNECTION_NAME_FIXED {
ULONG ConnectionIndex;
ULONG ActualLength;
WCHAR NodeName[MAX_PATH_LENGTH];
} USB_NODE_CONNECTION_NAME_FIXED;
typedef struct USB_HUB_NAME_FIXED {
union {
USB_ROOT_HUB_NAME_FIXED root;
USB_NODE_CONNECTION_NAME_FIXED node;
} u;
} USB_HUB_NAME_FIXED;
typedef struct USB_HUB_INFORMATION {
USB_HUB_DESCRIPTOR HubDescriptor;
BOOLEAN HubIsBusPowered;
} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION;
typedef struct USB_MI_PARENT_INFORMATION {
ULONG NumberOfInterfaces;
} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION;
typedef struct USB_NODE_INFORMATION {
USB_HUB_NODE NodeType;
union {
USB_HUB_INFORMATION HubInformation;
USB_MI_PARENT_INFORMATION MiParentInformation;
} u;
} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION;
typedef struct USB_PIPE_INFO {
USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
ULONG ScheduleOffset;
} USB_PIPE_INFO, *PUSB_PIPE_INFO;
typedef struct USB_NODE_CONNECTION_INFORMATION_EX {
typedef struct _USB_NODE_CONNECTION_INFORMATION_EX {
ULONG ConnectionIndex;
USB_DEVICE_DESCRIPTOR DeviceDescriptor;
UCHAR CurrentConfigurationValue;
@@ -589,25 +408,7 @@ typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 {
USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS Flags;
} USB_NODE_CONNECTION_INFORMATION_EX_V2, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2;
typedef struct USB_HUB_CAP_FLAGS {
ULONG HubIsHighSpeedCapable:1;
ULONG HubIsHighSpeed:1;
ULONG HubIsMultiTtCapable:1;
ULONG HubIsMultiTt:1;
ULONG HubIsRoot:1;
ULONG HubIsArmedWakeOnConnect:1;
ULONG ReservedMBZ:26;
} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS;
typedef struct USB_HUB_CAPABILITIES {
ULONG HubIs2xCapable:1;
} USB_HUB_CAPABILITIES, *PUSB_HUB_CAPABILITIES;
typedef struct USB_HUB_CAPABILITIES_EX {
USB_HUB_CAP_FLAGS CapabilityFlags;
} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX;
#pragma pack(pop)
#include <poppack.h>
/* winusb.dll interface */
@@ -619,36 +420,25 @@ typedef struct USB_HUB_CAPABILITIES_EX {
#define AUTO_FLUSH 0x06
#define RAW_IO 0x07
#define MAXIMUM_TRANSFER_SIZE 0x08
#define AUTO_SUSPEND 0x81
#define SUSPEND_DELAY 0x83
#define DEVICE_SPEED 0x01
#define LowSpeed 0x01
#define FullSpeed 0x02
#define HighSpeed 0x03
typedef enum USBD_PIPE_TYPE {
typedef enum _USBD_PIPE_TYPE {
UsbdPipeTypeControl,
UsbdPipeTypeIsochronous,
UsbdPipeTypeBulk,
UsbdPipeTypeInterrupt
} USBD_PIPE_TYPE;
typedef struct {
USBD_PIPE_TYPE PipeType;
UCHAR PipeId;
USHORT MaximumPacketSize;
UCHAR Interval;
} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION;
#include <pshpack1.h>
#pragma pack(1)
typedef struct {
UCHAR request_type;
UCHAR request;
USHORT value;
USHORT index;
USHORT length;
typedef struct _WINUSB_SETUP_PACKET {
UCHAR RequestType;
UCHAR Request;
USHORT Value;
USHORT Index;
USHORT Length;
} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET;
#pragma pack()
#include <poppack.h>
typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
@@ -676,59 +466,10 @@ typedef BOOL (WINAPI *WinUsb_GetAssociatedInterface_t)(
UCHAR AssociatedInterfaceIndex,
PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle
);
typedef BOOL (WINAPI *WinUsb_GetCurrentAlternateSetting_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
PUCHAR AlternateSetting
);
typedef BOOL (WINAPI *WinUsb_GetDescriptor_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR DescriptorType,
UCHAR Index,
USHORT LanguageID,
PUCHAR Buffer,
ULONG BufferLength,
PULONG LengthTransferred
);
typedef BOOL (WINAPI *WinUsb_GetOverlappedResult_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
LPOVERLAPPED lpOverlapped,
LPDWORD lpNumberOfBytesTransferred,
BOOL bWait
);
typedef BOOL (WINAPI *WinUsb_GetPipePolicy_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
ULONG PolicyType,
PULONG ValueLength,
PVOID Value
);
typedef BOOL (WINAPI *WinUsb_GetPowerPolicy_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
ULONG PolicyType,
PULONG ValueLength,
PVOID Value
);
typedef BOOL (WINAPI *WinUsb_Initialize_t)(
HANDLE DeviceHandle,
PWINUSB_INTERFACE_HANDLE InterfaceHandle
);
typedef BOOL (WINAPI *WinUsb_QueryDeviceInformation_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
ULONG InformationType,
PULONG BufferLength,
PVOID Buffer
);
typedef BOOL (WINAPI *WinUsb_QueryInterfaceSettings_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR AlternateSettingNumber,
PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor
);
typedef BOOL (WINAPI *WinUsb_QueryPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR AlternateInterfaceNumber,
UCHAR PipeIndex,
PWINUSB_PIPE_INFORMATION PipeInformation
);
typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
@@ -737,6 +478,9 @@ typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
PULONG LengthTransferred,
LPOVERLAPPED Overlapped
);
typedef BOOL (WINAPI *WinUsb_ResetDevice_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle
);
typedef BOOL (WINAPI *WinUsb_ResetPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID
@@ -752,12 +496,6 @@ typedef BOOL (WINAPI *WinUsb_SetPipePolicy_t)(
ULONG ValueLength,
PVOID Value
);
typedef BOOL (WINAPI *WinUsb_SetPowerPolicy_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
ULONG PolicyType,
ULONG ValueLength,
PVOID Value
);
typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
@@ -766,8 +504,59 @@ typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
PULONG LengthTransferred,
LPOVERLAPPED Overlapped
);
typedef BOOL (WINAPI *WinUsb_ResetDevice_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle
typedef PVOID WINUSB_ISOCH_BUFFER_HANDLE, *PWINUSB_ISOCH_BUFFER_HANDLE;
typedef BOOL (WINAPI *WinUsb_RegisterIsochBuffer_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PVOID Buffer,
ULONG BufferLength,
PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
);
typedef BOOL (WINAPI *WinUsb_UnregisterIsochBuffer_t)(
WINUSB_ISOCH_BUFFER_HANDLE BufferHandle
);
typedef BOOL (WINAPI *WinUsb_WriteIsochPipeAsap_t)(
WINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
ULONG Offset,
ULONG Length,
BOOL ContinueStream,
LPOVERLAPPED Overlapped
);
typedef LONG USBD_STATUS;
typedef struct {
ULONG Offset;
ULONG Length;
USBD_STATUS Status;
} USBD_ISO_PACKET_DESCRIPTOR, *PUSBD_ISO_PACKET_DESCRIPTOR;
typedef BOOL (WINAPI *WinUsb_ReadIsochPipeAsap_t)(
PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
ULONG Offset,
ULONG Length,
BOOL ContinueStream,
ULONG NumberOfPackets,
PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors,
LPOVERLAPPED Overlapped
);
typedef struct {
USBD_PIPE_TYPE PipeType;
UCHAR PipeId;
USHORT MaximumPacketSize;
UCHAR Interval;
ULONG MaximumBytesPerInterval;
} WINUSB_PIPE_INFORMATION_EX, *PWINUSB_PIPE_INFORMATION_EX;
typedef BOOL (WINAPI *WinUsb_QueryPipeEx_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR AlternateInterfaceHandle,
UCHAR PipeIndex,
PWINUSB_PIPE_INFORMATION_EX PipeInformationEx
);
/* /!\ These must match the ones from the official libusbk.h */
@@ -814,8 +603,7 @@ typedef struct _KLIB_VERSION {
INT Minor;
INT Micro;
INT Nano;
} KLIB_VERSION;
typedef KLIB_VERSION* PKLIB_VERSION;
} KLIB_VERSION, *PKLIB_VERSION;
typedef BOOL (WINAPI *LibK_GetProcAddress_t)(
PVOID *ProcAddress,
@@ -827,29 +615,72 @@ typedef VOID (WINAPI *LibK_GetVersion_t)(
PKLIB_VERSION Version
);
//KISO_PACKET is equivalent of libusb_iso_packet_descriptor except uses absolute "offset" field instead of sequential Lengths
typedef struct _KISO_PACKET {
UINT offset;
USHORT actual_length; //changed from libusbk_shared.h "Length" for clarity
USHORT status;
} KISO_PACKET, *PKISO_PACKET;
typedef enum _KISO_FLAG {
KISO_FLAG_NONE = 0,
KISO_FLAG_SET_START_FRAME = 0x00000001,
} KISO_FLAG;
//KISO_CONTEXT is the conceptual equivalent of libusb_transfer except is isochronous-specific and must match libusbk's version
typedef struct _KISO_CONTEXT {
KISO_FLAG Flags;
UINT StartFrame;
SHORT ErrorCount;
SHORT NumberOfPackets;
UINT UrbHdrStatus;
KISO_PACKET IsoPackets[0];
} KISO_CONTEXT, *PKISO_CONTEXT;
typedef BOOL(WINAPI *WinUsb_IsoReadPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PUCHAR Buffer,
ULONG BufferLength,
LPOVERLAPPED Overlapped,
PKISO_CONTEXT IsoContext
);
typedef BOOL(WINAPI *WinUsb_IsoWritePipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PUCHAR Buffer,
ULONG BufferLength,
LPOVERLAPPED Overlapped,
PKISO_CONTEXT IsoContext
);
struct winusb_interface {
bool initialized;
bool CancelIoEx_supported;
WinUsb_AbortPipe_t AbortPipe;
WinUsb_ControlTransfer_t ControlTransfer;
WinUsb_FlushPipe_t FlushPipe;
WinUsb_Free_t Free;
WinUsb_GetAssociatedInterface_t GetAssociatedInterface;
WinUsb_GetCurrentAlternateSetting_t GetCurrentAlternateSetting;
WinUsb_GetDescriptor_t GetDescriptor;
WinUsb_GetOverlappedResult_t GetOverlappedResult;
WinUsb_GetPipePolicy_t GetPipePolicy;
WinUsb_GetPowerPolicy_t GetPowerPolicy;
WinUsb_Initialize_t Initialize;
WinUsb_QueryDeviceInformation_t QueryDeviceInformation;
WinUsb_QueryInterfaceSettings_t QueryInterfaceSettings;
WinUsb_QueryPipe_t QueryPipe;
WinUsb_ReadPipe_t ReadPipe;
WinUsb_ResetDevice_t ResetDevice;
WinUsb_ResetPipe_t ResetPipe;
WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting;
WinUsb_SetPipePolicy_t SetPipePolicy;
WinUsb_SetPowerPolicy_t SetPowerPolicy;
WinUsb_WritePipe_t WritePipe;
WinUsb_ResetDevice_t ResetDevice;
// Isochoronous functions for LibUSBk sub api:
WinUsb_IsoReadPipe_t IsoReadPipe;
WinUsb_IsoWritePipe_t IsoWritePipe;
// Isochronous functions for Microsoft WinUSB sub api (native WinUSB):
WinUsb_RegisterIsochBuffer_t RegisterIsochBuffer;
WinUsb_UnregisterIsochBuffer_t UnregisterIsochBuffer;
WinUsb_WriteIsochPipeAsap_t WriteIsochPipeAsap;
WinUsb_ReadIsochPipeAsap_t ReadIsochPipeAsap;
WinUsb_QueryPipeEx_t QueryPipeEx;
};
/* hid.dll interface */
@@ -857,17 +688,19 @@ struct winusb_interface {
#define HIDP_STATUS_SUCCESS 0x110000
typedef void * PHIDP_PREPARSED_DATA;
#pragma pack(1)
typedef struct {
#include <pshpack1.h>
typedef struct _HIDD_ATTIRBUTES {
ULONG Size;
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
#pragma pack()
#include <poppack.h>
typedef USHORT USAGE;
typedef struct {
typedef struct _HIDP_CAPS {
USAGE Usage;
USAGE UsagePage;
USHORT InputReportByteLength;
@@ -930,19 +763,16 @@ typedef struct _HIDP_VALUE_CAPS {
} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;
DLL_DECLARE_HANDLE(hid);
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES));
DLL_DECLARE_FUNC(WINAPI, VOID, HidD_GetHidGuid, (LPGUID));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetIndexedString, (HANDLE, ULONG, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, LONG, HidP_GetCaps, (PHIDP_PREPARSED_DATA, PHIDP_CAPS));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetFeature, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetFeature, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetInputReport, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetOutputReport, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FlushQueue, (HANDLE));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA));
+33 -2
View File
@@ -38,7 +38,7 @@ static size_t usbi_locale = 0;
* How to add a new \ref libusb_strerror() translation:
* <ol>
* <li> Download the latest \c strerror.c from:<br>
* https://raw.github.com/libusb/libusb/master/libusb/sterror.c </li>
* https://raw.github.com/libusb/libusb/master/libusb/strerror.c </li>
* <li> Open the file in an UTF-8 capable editor </li>
* <li> Add the 2 letter <a href="http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes">ISO 639-1</a>
* code for your locale at the end of \c usbi_locale_supported[]<br>
@@ -60,7 +60,7 @@ static size_t usbi_locale = 0;
* </ol>
*/
static const char* usbi_locale_supported[] = { "en", "nl", "fr", "ru" };
static const char* usbi_locale_supported[] = { "en", "nl", "fr", "ru", "de", "hu" };
static const char* usbi_localized_errors[ARRAYSIZE(usbi_locale_supported)][LIBUSB_ERROR_COUNT] = {
{ /* English (en) */
"Success",
@@ -122,6 +122,37 @@ static const char* usbi_localized_errors[ARRAYSIZE(usbi_locale_supported)][LIBUS
"Память исчерпана",
"Операция не поддерживается данной платформой",
"Неизвестная ошибка"
}, { /* German (de) */
"Erfolgreich",
"Eingabe-/Ausgabefehler",
"Ungültiger Parameter",
"Keine Berechtigung (Zugriffsrechte fehlen)",
"Kein passendes Gerät gefunden (es könnte entfernt worden sein)",
"Entität nicht gefunden",
"Die Ressource ist belegt",
"Die Wartezeit für die Operation ist abgelaufen",
"Mehr Daten empfangen als erwartet",
"Datenübergabe unterbrochen (broken pipe)",
"Unterbrechung während des Betriebssystemaufrufs",
"Nicht genügend Hauptspeicher verfügbar",
"Die Operation wird nicht unterstützt oder ist auf dieser Platform nicht implementiert",
"Allgemeiner Fehler",
}, { /* Hungarian (hu) */
"Sikeres",
"Be-/kimeneti hiba",
"Érvénytelen paraméter",
"Hozzáférés megtagadva",
"Az eszköz nem található (eltávolították?)",
"Nem található",
"Az erőforrás foglalt",
"Időtúllépés",
"Túlcsordulás",
"Törött adatcsatorna",
"Rendszerhívás megszakítva",
"Nincs elég memória",
"A művelet nem támogatott ezen a rendszeren",
"Általános hiba",
}
};
+2 -2
View File
@@ -7,12 +7,12 @@
#define LIBUSB_MINOR 0
#endif
#ifndef LIBUSB_MICRO
#define LIBUSB_MICRO 21
#define LIBUSB_MICRO 23
#endif
#ifndef LIBUSB_NANO
#define LIBUSB_NANO 0
#endif
/* LIBUSB_RC is the release candidate suffix. Should normally be empty. */
#ifndef LIBUSB_RC
#define LIBUSB_RC ""
#define LIBUSB_RC "-rc1"
#endif
+1 -1
View File
@@ -1 +1 @@
#define LIBUSB_NANO 11156
#define LIBUSB_NANO 11367