Beispiel #1
0
/* Before using the hash table we must allocate memory for it.
   We allocate one element more as the found prime number says.
   This is done for more effective indexing as explained in the
   comment for the hash function.  */
static bool htab_create(struct libusb_context *ctx, unsigned long nel)
{
	if (htab_table != NULL) {
		usbi_err(ctx, "hash table already allocated");
		return true;
	}

	// Create a mutex
	usbi_mutex_init(&htab_write_mutex);

	// Change nel to the first prime number not smaller as nel.
	nel |= 1;
	while (!isprime(nel))
		nel += 2;

	htab_size = nel;
	usbi_dbg("using %lu entries hash table", nel);
	htab_filled = 0;

	// allocate memory and zero out.
	htab_table = calloc(htab_size + 1, sizeof(htab_entry));
	if (htab_table == NULL) {
		usbi_err(ctx, "could not allocate space for hash table");
		return false;
	}

	return true;
}
int linux_udev_start_event_monitor(void)
{
	int r;

	if (NULL == udev_ctx) {
		udev_ctx = udev_new();
		if (!udev_ctx) {
			return LIBUSB_ERROR_OTHER;
		}
	}

        udev_monitor = udev_monitor_new_from_netlink(udev_ctx, "udev");
        if (!udev_monitor) {
                usbi_err(NULL, "could not initialize udev monitor");
                return LIBUSB_ERROR_OTHER;
        }

        r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", 0);
        if (r) {
                usbi_err(NULL, "could not initialize udev monitor filter for \"usb\" subsystem");
                return LIBUSB_ERROR_OTHER;
        }

        if (udev_monitor_enable_receiving(udev_monitor)) {
                usbi_err(NULL, "failed to enable the udev monitor");
                return LIBUSB_ERROR_OTHER;
        }

        udev_monitor_fd = udev_monitor_get_fd(udev_monitor);

        pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL);

        return LIBUSB_SUCCESS;
}
Beispiel #3
0
/** \ingroup desc
 * Get an USB 2.0 Extension descriptor
 *
 * \param ctx the context to operate on, or NULL for the default context
 * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
 * \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION
 * LIBUSB_BT_USB_2_0_EXTENSION
 * \param usb_2_0_extension output location for the USB 2.0 Extension
 * descriptor. Only valid if 0 was returned. Must be freed with
 * libusb_free_usb_2_0_extension_descriptor() after use.
 * \returns 0 on success
 * \returns a LIBUSB_ERROR code on error
 */
int API_EXPORTED libusb_get_usb_2_0_extension_descriptor(
	struct libusb_context *ctx,
	struct libusb_bos_dev_capability_descriptor *dev_cap,
	struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension)
{
	struct libusb_usb_2_0_extension_descriptor *_usb_2_0_extension;
	const int host_endian = 0;

	if (dev_cap->bDevCapabilityType != LIBUSB_BT_USB_2_0_EXTENSION) {
		usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)",
			 dev_cap->bDevCapabilityType,
			 LIBUSB_BT_USB_2_0_EXTENSION);
		return LIBUSB_ERROR_INVALID_PARAM;
	}
	if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) {
		usbi_err(ctx, "short dev-cap descriptor read %d/%d",
			 dev_cap->bLength, LIBUSB_BT_USB_2_0_EXTENSION_SIZE);
		return LIBUSB_ERROR_IO;
	}

	_usb_2_0_extension = malloc(sizeof(*_usb_2_0_extension));
	if (!_usb_2_0_extension)
		return LIBUSB_ERROR_NO_MEM;

	usbi_parse_descriptor((unsigned char *)dev_cap, "bbbd",
			      _usb_2_0_extension, host_endian);

	*usb_2_0_extension = _usb_2_0_extension;
	return LIBUSB_SUCCESS;
}
Beispiel #4
0
/** \ingroup desc
 * Get a Container ID descriptor
 *
 * \param ctx the context to operate on, or NULL for the default context
 * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
 * \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID
 * LIBUSB_BT_CONTAINER_ID
 * \param container_id output location for the Container ID descriptor.
 * Only valid if 0 was returned. Must be freed with
 * libusb_free_container_id_descriptor() after use.
 * \returns 0 on success
 * \returns a LIBUSB_ERROR code on error
 */
int API_EXPORTED libusb_get_container_id_descriptor(struct libusb_context *ctx,
	struct libusb_bos_dev_capability_descriptor *dev_cap,
	struct libusb_container_id_descriptor **container_id)
{
	struct libusb_container_id_descriptor *_container_id;
	const int host_endian = 0;

	if (dev_cap->bDevCapabilityType != LIBUSB_BT_CONTAINER_ID) {
		usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)",
			 dev_cap->bDevCapabilityType,
			 LIBUSB_BT_CONTAINER_ID);
		return LIBUSB_ERROR_INVALID_PARAM;
	}
	if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) {
		usbi_err(ctx, "short dev-cap descriptor read %d/%d",
			 dev_cap->bLength, LIBUSB_BT_CONTAINER_ID_SIZE);
		return LIBUSB_ERROR_IO;
	}

	_container_id = malloc(sizeof(*_container_id));
	if (!_container_id)
		return LIBUSB_ERROR_NO_MEM;

	usbi_parse_descriptor((unsigned char *)dev_cap, "bbbbu",
			      _container_id, host_endian);

	*container_id = _container_id;
	return LIBUSB_SUCCESS;
}
Beispiel #5
0
/** \ingroup desc
 * Get a SuperSpeed USB Device Capability descriptor
 *
 * \param ctx the context to operate on, or NULL for the default context
 * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
 * \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
 * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
 * \param ss_usb_device_cap output location for the SuperSpeed USB Device
 * Capability descriptor. Only valid if 0 was returned. Must be freed with
 * libusb_free_ss_usb_device_capability_descriptor() after use.
 * \returns 0 on success
 * \returns a LIBUSB_ERROR code on error
 */
int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor(
	struct libusb_context *ctx,
	struct libusb_bos_dev_capability_descriptor *dev_cap,
	struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap)
{
	struct libusb_ss_usb_device_capability_descriptor *_ss_usb_device_cap;
	const int host_endian = 0;

	if (dev_cap->bDevCapabilityType != LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) {
		usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)",
			 dev_cap->bDevCapabilityType,
			 LIBUSB_BT_SS_USB_DEVICE_CAPABILITY);
		return LIBUSB_ERROR_INVALID_PARAM;
	}
	if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) {
		usbi_err(ctx, "short dev-cap descriptor read %d/%d",
			 dev_cap->bLength, LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE);
		return LIBUSB_ERROR_IO;
	}

	_ss_usb_device_cap = malloc(sizeof(*_ss_usb_device_cap));
	if (!_ss_usb_device_cap)
		return LIBUSB_ERROR_NO_MEM;

	usbi_parse_descriptor((unsigned char *)dev_cap, "bbbbwbbw",
			      _ss_usb_device_cap, host_endian);

	*ss_usb_device_cap = _ss_usb_device_cap;
	return LIBUSB_SUCCESS;
}
Beispiel #6
0
static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
	struct usbdk_device_priv *p, PUSB_DK_DEVICE_INFO info)
{
	uint8_t i;
	USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
	Request.ID = info->ID;

	p->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
	if (p->config_descriptors == NULL) {
		usbi_err(ctx, "failed to allocate configuration descriptors holder");
		return LIBUSB_ERROR_NO_MEM;
	}

	for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
		ULONG Length;

		Request.Index = i;
		if (!usbdk_helper.GetConfigurationDescriptor(&Request, &p->config_descriptors[i], &Length)) {
			usbi_err(ctx, "failed to retrieve configuration descriptors");
			usbdk_release_config_descriptors(p, i);
			return LIBUSB_ERROR_OTHER;
		}
	}

	return LIBUSB_SUCCESS;
}
Beispiel #7
0
static int wince_submit_control_or_bulk_transfer(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 wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
	struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
	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;

	transfer_priv->pollable_fd = INVALID_WINFD;
	if (control_transfer) {
		setup = (PUKW_CONTROL_HEADER) transfer->buffer;
		direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
	} else {
		direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
	}
	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");
		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;
	}

	transfer_priv->pollable_fd = wfd;
	if (control_transfer) {
		// Split out control setup header and data buffer
		DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
		PVOID buf = (PVOID) &transfer->buffer[sizeof(UKW_CONTROL_HEADER)];

		ret = UkwIssueControlTransfer(priv->dev, flags, setup, buf, bufLen, &transfer->actual_length, wfd.overlapped);
	} else {
		ret = UkwIssueBulkTransfer(priv->dev, flags, transfer->endpoint, transfer->buffer, 
			transfer->length, &transfer->actual_length, wfd.overlapped);
	}
	if (!ret) {
		int libusbErr = translate_driver_error(GetLastError());
		usbi_err(ctx, "UkwIssue%sTransfer failed: error %d",
			control_transfer ? "Control" : "Bulk", GetLastError());
		wince_clear_transfer_priv(itransfer);
		return libusbErr;
	}
	usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT);
	itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;

	return LIBUSB_SUCCESS;
}
Beispiel #8
0
static int windows_clock_gettime(int clk_id, struct timespec *tp)
{
	struct timer_request request;
#if !defined(_MSC_VER) || (_MSC_VER < 1900)
	FILETIME filetime;
	ULARGE_INTEGER rtime;
#endif
	DWORD r;

	switch (clk_id) {
	case USBI_CLOCK_MONOTONIC:
		if (timer_thread) {
			request.tp = tp;
			request.event = CreateEvent(NULL, FALSE, FALSE, NULL);
			if (request.event == NULL)
				return LIBUSB_ERROR_NO_MEM;

			if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_REQUEST, 0, (LPARAM)&request)) {
				usbi_err(NULL, "PostThreadMessage failed for timer thread: %s", windows_error_str(0));
				CloseHandle(request.event);
				return LIBUSB_ERROR_OTHER;
			}

			do {
				r = WaitForSingleObject(request.event, TIMER_REQUEST_RETRY_MS);
				if (r == WAIT_TIMEOUT)
					usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
				else if (r == WAIT_FAILED)
					usbi_err(NULL, "WaitForSingleObject failed: %s", windows_error_str(0));
			} while (r == WAIT_TIMEOUT);
			CloseHandle(request.event);

			if (r == WAIT_OBJECT_0)
				return LIBUSB_SUCCESS;
			else
				return LIBUSB_ERROR_OTHER;
		}
		// Fall through and return real-time if monotonic was not detected @ timer init
	case USBI_CLOCK_REALTIME:
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
		timespec_get(tp, TIME_UTC);
#else
		// 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
		// 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)
		GetSystemTimeAsFileTime(&filetime);
		rtime.LowPart = filetime.dwLowDateTime;
		rtime.HighPart = filetime.dwHighDateTime;
		rtime.QuadPart -= EPOCH_TIME;
		tp->tv_sec = (long)(rtime.QuadPart / 10000000);
		tp->tv_nsec = (long)((rtime.QuadPart % 10000000) * 100);
#endif
		return LIBUSB_SUCCESS;
	default:
		return LIBUSB_ERROR_INVALID_PARAM;
	}
}
Beispiel #9
0
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;
	TransferResult transferRes;
	HANDLE sysHandle;

	transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
	transfer_priv->request.BufferLength = transfer->length;
	transfer_priv->request.EndpointAddress = transfer->endpoint;

	switch (transfer->type) {
	case LIBUSB_TRANSFER_TYPE_BULK:
		transfer_priv->request.TransferType = BulkTransferType;
		break;
	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
		transfer_priv->request.TransferType = IntertuptTransferType;
		break;
	default:
		usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer. %s", transfer->type, windows_error_str(0));
		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);
	else
		transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);

	switch (transferRes) {
	case TransferSuccess:
		wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
		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;
}
Beispiel #10
0
static int wince_handle_events(
	struct libusb_context *ctx,
	struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
{
	struct wince_transfer_priv* transfer_priv = NULL;
	POLL_NFDS_TYPE i = 0;
	BOOL found = FALSE;
	struct usbi_transfer *transfer;
	DWORD io_size, io_result;
	int r = LIBUSB_SUCCESS;

	usbi_mutex_lock(&ctx->open_devs_lock);
	for (i = 0; i < nfds && num_ready > 0; i++) {

		usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);

		if (!fds[i].revents)
			continue;

		num_ready--;

		// 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);
			if (transfer_priv->pollable_fd.fd == fds[i].fd) {
				found = TRUE;
				break;
			}
		}
		usbi_mutex_unlock(&ctx->flying_transfers_lock);

		if (found && HasOverlappedIoCompleted(transfer_priv->pollable_fd.overlapped)) {
			io_result = (DWORD)transfer_priv->pollable_fd.overlapped->Internal;
			io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh;
			usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd);
			// 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);
		} else if (found) {
			usbi_err(ctx, "matching transfer for fd %d has not completed", fds[i]);
			r = LIBUSB_ERROR_OTHER;
			break;
		} else {
			usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i]);
			r = LIBUSB_ERROR_NOT_FOUND;
			break;
		}
	}
	usbi_mutex_unlock(&ctx->open_devs_lock);

	return r;
}
Beispiel #11
0
static void do_close(struct libusb_context *ctx,
	struct libusb_device_handle *dev_handle)
{
	struct usbi_transfer *itransfer;
	struct usbi_transfer *tmp;

	libusb_lock_events(ctx);

	
	usbi_mutex_lock(&ctx->flying_transfers_lock);

	
	list_for_each_entry_safe(itransfer, tmp, &ctx->flying_transfers, list, struct usbi_transfer) {
		struct libusb_transfer *transfer =
		        USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);

		if (transfer->dev_handle != dev_handle)
			continue;

		if (!(itransfer->flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) {
			usbi_err(ctx, "Device handle closed while transfer was still being processed, but the device is still connected as far as we know");

			if (itransfer->flags & USBI_TRANSFER_CANCELLING)
				usbi_warn(ctx, "A cancellation for an in-flight transfer hasn't completed but closing the device handle");
			else
				usbi_err(ctx, "A cancellation hasn't even been scheduled on the transfer for which the device is closing");
		}

		usbi_mutex_lock(&itransfer->lock);
		list_del(&itransfer->list);
		transfer->dev_handle = NULL;
		usbi_mutex_unlock(&itransfer->lock);

		usbi_dbg("Removed transfer %p from the in-flight list because device handle %p closed",
			 transfer, dev_handle);
	}
	usbi_mutex_unlock(&ctx->flying_transfers_lock);

	libusb_unlock_events(ctx);

	usbi_mutex_lock(&ctx->open_devs_lock);
	list_del(&dev_handle->list);
	usbi_mutex_unlock(&ctx->open_devs_lock);

	usbi_backend->close(dev_handle);
	libusb_unref_device(dev_handle->dev);
	usbi_mutex_destroy(&dev_handle->lock);
	free(dev_handle);
}
Beispiel #12
0
static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
{
	int r = LIBUSB_SUCCESS;
	ULONG i;
	struct discovered_devs *discdevs = NULL;
	ULONG dev_number;
	PUSB_DK_DEVICE_INFO devices;

	if(!usbdk_helper.GetDevicesList(&devices, &dev_number))
		return LIBUSB_ERROR_OTHER;

	for (i = 0; i < dev_number; i++) {
		unsigned long session_id;
		struct libusb_device *dev = NULL;

		if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
			continue;

		dev = usbi_get_device_by_session_id(ctx, session_id);
		if (dev == NULL) {
			dev = usbi_alloc_device(ctx, session_id);
			if (dev == NULL) {
				usbi_err(ctx, "failed to allocate a new device structure");
				continue;
			}

			usbdk_device_init(dev, &devices[i]);
			if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
				libusb_unref_device(dev);
				continue;
			}
		}

		discdevs = discovered_devs_append(*_discdevs, dev);
		libusb_unref_device(dev);
		if (!discdevs) {
			usbi_err(ctx, "cannot append new device to list");
			r = LIBUSB_ERROR_NO_MEM;
			goto func_exit;
		}

		*_discdevs = discdevs;
	}

func_exit:
	usbdk_helper.ReleaseDevicesList(devices);
	return r;
}
Beispiel #13
0
void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx,
	libusb_hotplug_callback_handle handle)
{
	struct libusb_hotplug_callback *hotplug_cb;
	libusb_hotplug_message message;
	ssize_t ret;

	/* check for hotplug support */
	if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
		return;
	}

	USBI_GET_CONTEXT(ctx);

	usbi_mutex_lock(&ctx->hotplug_cbs_lock);
	list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list,
			    struct libusb_hotplug_callback) {
		if (handle == hotplug_cb->handle) {
			/* Mark this callback for deregistration */
			hotplug_cb->needs_free = 1;
		}
	}
	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);

	/* wakeup handle_events to do the actual free */
	memset(&message, 0, sizeof(message));
	ret = usbi_write(ctx->hotplug_pipe[1], &message, sizeof(message));
	if (sizeof(message) != ret) {
		usbi_err(ctx, "error writing hotplug message");
	}
}
Beispiel #14
0
int API_EXPORTED libusb_get_max_iso_packet_size(libusb_device *dev,
	unsigned char endpoint)
{
	struct libusb_config_descriptor *config;
	const struct libusb_endpoint_descriptor *ep;
	enum libusb_transfer_type ep_type;
	uint16_t val;
	int r;

	r = libusb_get_active_config_descriptor(dev, &config);
	if (r < 0) {
		usbi_err(DEVICE_CTX(dev),
			"could not retrieve active config descriptor");
		return LIBUSB_ERROR_OTHER;
	}

	ep = find_endpoint(config, endpoint);
	if (!ep)
		return LIBUSB_ERROR_NOT_FOUND;

	val = ep->wMaxPacketSize;
	ep_type = ep->bmAttributes & 0x3;
	libusb_free_config_descriptor(config);

	r = val & 0x07ff;
	if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
			|| ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT)
		r *= (1 + ((val >> 11) & 3));
	return r;
}
Beispiel #15
0
int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev,
	int *config)
{
	int r = LIBUSB_ERROR_NOT_SUPPORTED;

	usbi_dbg("");
	if (usbi_backend->get_configuration)
		r = usbi_backend->get_configuration(dev, config);

	if (r == LIBUSB_ERROR_NOT_SUPPORTED) {
		uint8_t tmp = 0;
		usbi_dbg("falling back to control message");
		r = libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN,
			LIBUSB_REQUEST_GET_CONFIGURATION, 0, 0, &tmp, 1, 1000);
		if (r == 0) {
			usbi_err(HANDLE_CTX(dev), "zero bytes returned in ctrl transfer?");
			r = LIBUSB_ERROR_IO;
		} else if (r == 1) {
			r = 0;
			*config = tmp;
		} else {
			usbi_dbg("control failed, error %d", r);
		}
	}

	if (r == 0)
		usbi_dbg("active config %d", *config);

	return r;
}
Beispiel #16
0
/*
 * synchronous write for fake "pipe" signaling
 */
ssize_t usbi_write(int fd, const void *buf, size_t count)
{
	int _index;
	UNUSED(buf);

	CHECK_INIT_POLLING;

	if (count != sizeof(unsigned char)) {
		usbi_err(NULL, "this function should only used for signaling");
		return -1;
	}

	_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;
	}

	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++;

	LeaveCriticalSection(&_poll_fd[_index].mutex);
	return sizeof(unsigned char);
}
Beispiel #17
0
/** \ingroup desc
 * Get the USB configuration descriptor for the currently active configuration.
 * This is a non-blocking function which does not involve any requests being
 * sent to the device.
 *
 * \param dev a device
 * \param config output location for the USB configuration descriptor. Only
 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
 * after use.
 * \returns 0 on success
 * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state
 * \returns another LIBUSB_ERROR code on error
 * \see libusb_get_config_descriptor
 */
int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
	struct libusb_config_descriptor **config)
{
	struct libusb_config_descriptor _config;
	unsigned char tmp[LIBUSB_DT_CONFIG_SIZE];
	unsigned char *buf = NULL;
	int host_endian = 0;
	int r;

	r = usbi_backend->get_active_config_descriptor(dev, tmp,
		LIBUSB_DT_CONFIG_SIZE, &host_endian);
	if (r < 0)
		return r;
	if (r < LIBUSB_DT_CONFIG_SIZE) {
		usbi_err(dev->ctx, "short config descriptor read %d/%d",
			 r, LIBUSB_DT_CONFIG_SIZE);
		return LIBUSB_ERROR_IO;
	}

	usbi_parse_descriptor(tmp, "bbw", &_config, host_endian);
	buf = malloc(_config.wTotalLength);
	if (!buf)
		return LIBUSB_ERROR_NO_MEM;

	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);

	free(buf);
	return r;
}
Beispiel #18
0
static void udev_hotplug_event(struct udev_device* udev_dev)
{
	const char* udev_action;
	const char* sys_name = NULL;
	uint8_t busnum = 0, devaddr = 0;
	int detached;
	int r;

	do {
		udev_action = udev_device_get_action(udev_dev);
		if (!udev_action) {
			break;
		}

		detached = !strncmp(udev_action, "remove", 6);

		r = udev_device_info(NULL, detached, udev_dev, &busnum, &devaddr, &sys_name);
		if (LIBUSB_SUCCESS != r) {
			break;
		}

		usbi_dbg("udev hotplug event. action: %s.", udev_action);

		if (strncmp(udev_action, "add", 3) == 0) {
			linux_hotplug_enumerate(busnum, devaddr, sys_name);
		} else if (detached) {
			linux_hotplug_disconnected(busnum, devaddr, sys_name);
		} else {
			usbi_err(NULL, "ignoring udev action %s", udev_action);
		}
	} while (0);

	udev_device_unref(udev_dev);
}
Beispiel #19
0
API_EXPORTED usb_dev_handle *usb_open(struct usb_device *dev)
{
	int r;
	usbi_dbg("");

	usb_dev_handle *udev = malloc(sizeof(*udev));
	if (!udev)
		return NULL;

	r = libusb_open((libusb_device *) dev->dev, &udev->handle);
	if (r < 0) {
		if (r == LIBUSB_ERROR_ACCESS) {
			usbi_info("Device open failed due to a permission denied error.");
			usbi_info("libusb requires write access to USB device nodes.");
		}
		usbi_err("could not open device, error %d", r);
		free(udev);
		errno = libusb_to_errno(r);
		return NULL;
	}

	udev->last_claimed_interface = -1;
	udev->device = dev;
	return udev;
}
ssize_t usbi_write(int fd, const void *buf, size_t count)
{
	int _index;

	CHECK_INIT_POLLING;

	if (count != sizeof(unsigned char)) {
		usbi_err(NULL, "this function should only used for signaling");
		return -1;
	}

	_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;
	}

	poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
	SetEvent(poll_fd[_index].overlapped->hEvent);
	poll_fd[_index].overlapped->Internal = STATUS_WAIT_0;
	
	
	poll_fd[_index].overlapped->InternalHigh++;

	LeaveCriticalSection(&_poll_fd[_index].mutex);
	return sizeof(unsigned char);
}
static int
haiku_handle_transfer_completion(struct usbi_transfer * itransfer)
{
	USBTransfer* transfer=*((USBTransfer**)usbi_transfer_get_os_priv(itransfer));

	usbi_mutex_lock(&itransfer->lock);
	if(transfer->IsCancelled())
	{
		delete transfer;
		*((USBTransfer**)usbi_transfer_get_os_priv(itransfer))=NULL;
		usbi_mutex_unlock(&itransfer->lock);
		if (itransfer->transferred < 0)
			itransfer->transferred = 0;
		return usbi_handle_transfer_cancellation(itransfer);
	}
	libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
	if(itransfer->transferred < 0)
	{
		usbi_err(ITRANSFER_CTX(itransfer), "error in transfer");
		status = LIBUSB_TRANSFER_ERROR;
		itransfer->transferred=0;
	}
	delete transfer;
	*((USBTransfer**)usbi_transfer_get_os_priv(itransfer))=NULL;
	usbi_mutex_unlock(&itransfer->lock);
	return usbi_handle_transfer_completion(itransfer, status);
}
int usbi_pipe(int filedes[2])
{
	int i;
	OVERLAPPED* overlapped;

	CHECK_INIT_POLLING;

	overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
	if (overlapped == NULL) {
		return -1;
	}
	
	overlapped->Internal = STATUS_PENDING;
	overlapped->InternalHigh = 0;

	
	filedes[0] = _open(NUL_DEVICE, _O_WRONLY);
	if (filedes[0] < 0) {
		usbi_err(NULL, "could not create pipe: errno %d", errno);
		goto out1;
	}
	
	filedes[1] = filedes[0];
	poll_dbg("pipe filedes = %d", filedes[0]);

	
	overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if(!overlapped->hEvent) {
		goto out2;
	}

	for (i=0; i<MAX_FDS; i++) {
		if (poll_fd[i].fd < 0) {
			EnterCriticalSection(&_poll_fd[i].mutex);
			
			if (poll_fd[i].fd >= 0) {
				LeaveCriticalSection(&_poll_fd[i].mutex);
				continue;
			}

			poll_fd[i].fd = filedes[0];
			poll_fd[i].handle = DUMMY_HANDLE;
			poll_fd[i].overlapped = overlapped;
			
			poll_fd[i].rw = RW_READ;
			_poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
			LeaveCriticalSection(&_poll_fd[i].mutex);
			return 0;
		}
	}

	CloseHandle(overlapped->hEvent);
out2:
	_close(filedes[0]);
out1:
	free(overlapped);
	return -1;
}
Beispiel #23
0
/*
 * 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 = (OVERLAPPED*) calloc(1, sizeof(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;

	// Read end of the "pipe"
	filedes[0] = _open(NUL_DEVICE, _O_WRONLY);
	if (filedes[0] < 0) {
		usbi_err(NULL, "could not create pipe: errno %d", errno);
		goto out1;
	}
	// We can use the same handle for both ends
	filedes[1] = filedes[0];
	poll_dbg("pipe filedes = %d", filedes[0]);

	// Note: manual reset must be true (second param) as the reset occurs in read
	overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if(!overlapped->hEvent) {
		goto out2;
	}

	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;
			}

			poll_fd[i].fd = 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;
		}
	}

	CloseHandle(overlapped->hEvent);
out2:
	_close(filedes[0]);
out1:
	free(overlapped);
	return -1;
}
Beispiel #24
0
int linux_udev_start_event_monitor(void)
{
	int r;

	assert(udev_ctx == NULL);
	udev_ctx = udev_new();
	if (!udev_ctx) {
		usbi_err(NULL, "could not create udev context");
		return LIBUSB_ERROR_OTHER;
	}

	udev_monitor = udev_monitor_new_from_netlink(udev_ctx, "udev");
	if (!udev_monitor) {
		usbi_err(NULL, "could not initialize udev monitor");
		goto err_free_ctx;
	}

	r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", 0);
	if (r) {
		usbi_err(NULL, "could not initialize udev monitor filter for \"usb\" subsystem");
		goto err_free_monitor;
	}

	if (udev_monitor_enable_receiving(udev_monitor)) {
		usbi_err(NULL, "failed to enable the udev monitor");
		goto err_free_monitor;
	}

	udev_monitor_fd = udev_monitor_get_fd(udev_monitor);

	/* 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);
		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;
	}

	r = pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL);
	if (r) {
		usbi_err(NULL, "creating hotplug event thread (%d)", r);
		goto err_free_monitor;
	}

	return LIBUSB_SUCCESS;

err_free_monitor:
	udev_monitor_unref(udev_monitor);
	udev_monitor = NULL;
	udev_monitor_fd = -1;
err_free_ctx:
	udev_unref(udev_ctx);
	udev_ctx = NULL;
	return LIBUSB_ERROR_OTHER;
}
Beispiel #25
0
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");
	}
}
Beispiel #26
0
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());

	return api_ptr;
}
Beispiel #27
0
int linux_netlink_start_event_monitor(void)
{
    int socktype = SOCK_RAW;
    int ret;

    snl.nl_groups = KERNEL;

#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 (-1 == linux_netlink_socket && EINVAL == errno) {
        linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
    }

    if (-1 == linux_netlink_socket) {
        return LIBUSB_ERROR_OTHER;
    }

    ret = set_fd_cloexec_nb (linux_netlink_socket);
    if (0 != ret) {
        close (linux_netlink_socket);
        linux_netlink_socket = -1;
        return LIBUSB_ERROR_OTHER;
    }

    ret = bind(linux_netlink_socket, (struct sockaddr *) &snl, sizeof(snl));
    if (0 != ret) {
        close(linux_netlink_socket);
        return LIBUSB_ERROR_OTHER;
    }

    /* TODO -- add authentication */
    /* setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); */

    ret = usbi_pipe(netlink_control_pipe);
    if (ret) {
        usbi_err(NULL, "could not create netlink control pipe");
        close(linux_netlink_socket);
        return LIBUSB_ERROR_OTHER;
    }

    ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
    if (0 != ret) {
        close(netlink_control_pipe[0]);
        close(netlink_control_pipe[1]);
        close(linux_netlink_socket);
        return LIBUSB_ERROR_OTHER;
    }

    return LIBUSB_SUCCESS;
}
Beispiel #28
0
/** \ingroup desc
 * Get a Binary Object Store (BOS) descriptor
 * This is a BLOCKING function, which will send requests to the device.
 *
 * \param handle the handle of an open libusb device
 * \param bos output location for the BOS descriptor. Only valid if 0 was returned.
 * Must be freed with \ref libusb_free_bos_descriptor() after use.
 * \returns 0 on success
 * \returns LIBUSB_ERROR_NOT_FOUND if the device doesn't have a BOS descriptor
 * \returns another LIBUSB_ERROR code on error
 */
int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *handle,
	struct libusb_bos_descriptor **bos)
{
	struct libusb_bos_descriptor _bos;
	uint8_t bos_header[LIBUSB_DT_BOS_SIZE] = {0};
	unsigned char *bos_data = NULL;
	const int host_endian = 0;
	int r;

	/* Read the BOS. This generates 2 requests on the bus,
	 * one for the header, and one for the full BOS */
	r = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, bos_header,
				  LIBUSB_DT_BOS_SIZE);
	if (r < 0) {
		if (r != LIBUSB_ERROR_PIPE)
			usbi_err(handle->dev->ctx, "failed to read BOS (%d)", r);
		return r;
	}
	if (r < LIBUSB_DT_BOS_SIZE) {
		usbi_err(handle->dev->ctx, "short BOS read %d/%d",
			 r, LIBUSB_DT_BOS_SIZE);
		return LIBUSB_ERROR_IO;
	}

	usbi_parse_descriptor(bos_header, "bbwb", &_bos, host_endian);
	usbi_dbg("found BOS descriptor: size %d bytes, %d capabilities",
		 _bos.wTotalLength, _bos.bNumDeviceCaps);
	bos_data = calloc(_bos.wTotalLength, 1);
	if (bos_data == NULL)
		return LIBUSB_ERROR_NO_MEM;

	r = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, bos_data,
				  _bos.wTotalLength);
	if (r >= 0)
		r = parse_bos(handle->dev->ctx, bos, bos_data, r, host_endian);
	else
		usbi_err(handle->dev->ctx, "failed to read BOS (%d)", r);

	free(bos_data);
	return r;
}
Beispiel #29
0
static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
{
	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
	struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);

	if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
		usbi_err(ctx, "ResetDevice failed: %s", windows_error_str(0));
		return LIBUSB_ERROR_NO_DEVICE;
	}

	return LIBUSB_SUCCESS;
}
Beispiel #30
0
/** \ingroup desc
 * Get a USB configuration descriptor based on its index.
 * This is a non-blocking function which does not involve any requests being
 * sent to the device.
 *
 * \param dev a device
 * \param config_index the index of the configuration you wish to retrieve
 * \param config output location for the USB configuration descriptor. Only
 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
 * after use.
 * \returns 0 on success
 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
 * \returns another LIBUSB_ERROR code on error
 * \see libusb_get_active_config_descriptor()
 * \see libusb_get_config_descriptor_by_value()
 */
int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
	uint8_t config_index, struct libusb_config_descriptor **config)
{
	struct libusb_config_descriptor *_config;
	unsigned char tmp[8];
	unsigned char *buf = NULL;
	int host_endian = 0;
	int r;

	usbi_dbg("index %d", config_index);
	if (config_index >= dev->num_configurations)
		return LIBUSB_ERROR_NOT_FOUND;

	_config = malloc(sizeof(*_config));
	if (!_config)
		return LIBUSB_ERROR_NO_MEM;

	r = usbi_backend->get_config_descriptor(dev, config_index, tmp,
		sizeof(tmp), &host_endian);
	if (r < 0)
		goto err;

	usbi_parse_descriptor(tmp, "bbw", _config, host_endian);
	buf = malloc(_config->wTotalLength);
	if (!buf) {
		r = LIBUSB_ERROR_NO_MEM;
		goto err;
	}

	host_endian = 0;
	r = usbi_backend->get_config_descriptor(dev, config_index, buf,
		_config->wTotalLength, &host_endian);
	if (r < 0)
		goto err;

	r = parse_configuration(dev->ctx, _config, buf, host_endian);
	if (r < 0) {
		usbi_err(dev->ctx, "parse_configuration failed with error %d", r);
		goto err;
	} else if (r > 0) {
		usbi_warn(dev->ctx, "descriptor data still left");
	}

	free(buf);
	*config = _config;
	return 0;

err:
	free(_config);
	if (buf)
		free(buf);
	return r;
}