Exemple #1
0
int usb_get_device_name(libusb_device_handle *device_handle, char *name, int length) {
	int rc;
	libusb_device *device = libusb_get_device(device_handle);
	uint8_t bus_number = libusb_get_bus_number(device);
	uint8_t device_address = libusb_get_device_address(device);
	struct libusb_device_descriptor descriptor;
	char product[64];
	char serial_number[64];

	// get device descriptor
	rc = libusb_get_device_descriptor(device, &descriptor);

	if (rc < 0) {
		log_error("Could not get device descriptor for USB device (bus: %u, device: %u): %s (%d)",
		          bus_number, device_address, usb_get_error_name(rc), rc);

		return -1;
	}

	// get product string descriptor
	rc = libusb_get_string_descriptor_ascii(device_handle,
	                                        descriptor.iProduct,
	                                        (unsigned char *)product,
	                                        sizeof(product));

	if (rc < 0) {
		log_error("Could not get product string descriptor for USB device (bus: %u, device: %u): %s (%d)",
		          bus_number, device_address, usb_get_error_name(rc), rc);

		return -1;
	}

	// get serial number string descriptor
	rc = libusb_get_string_descriptor_ascii(device_handle,
	                                        descriptor.iSerialNumber,
	                                        (unsigned char *)serial_number,
	                                        sizeof(serial_number));

	if (rc < 0) {
		log_error("Could not get serial number string descriptor for USB device (bus: %u, device: %u): %s (%d)",
		          bus_number, device_address, usb_get_error_name(rc), rc);

		return -1;
	}

	// format name
	snprintf(name, length, "%s [%s]", product, serial_number);

	return 0;
}
Exemple #2
0
static void usb_handle_events(void *opaque) {
	int rc;
	libusb_context *context = opaque;
	struct timeval tv;

	tv.tv_sec = 0;
	tv.tv_usec = 0;

	rc = libusb_handle_events_timeout(context, &tv);

	if (rc < 0) {
		log_error("Could not handle USB events: %s (%d)",
		          usb_get_error_name(rc), rc);
	}
}
Exemple #3
0
static int usb_enumerate(void) {
	int result = -1;
	libusb_device **devices;
	libusb_device *device;
	int rc;
	int i = 0;
	struct libusb_device_descriptor descriptor;
	uint8_t bus_number;
	uint8_t device_address;
	bool known;
	int k;
	USBStack *usb_stack;

	// get all devices
	rc = libusb_get_device_list(_context, &devices);

	if (rc < 0) {
		log_error("Could not get USB device list: %s (%d)",
		          usb_get_error_name(rc), rc);

		return -1;
	}

	// check for stacks
	for (device = devices[0]; device != NULL; device = devices[++i]) {
		bus_number = libusb_get_bus_number(device);
		device_address = libusb_get_device_address(device);

		rc = libusb_get_device_descriptor(device, &descriptor);

		if (rc < 0) {
			log_warn("Could not get device descriptor for USB device (bus: %u, device: %u), ignoring USB device: %s (%d)",
			         bus_number, device_address, usb_get_error_name(rc), rc);

			continue;
		}

		if (descriptor.idVendor == USB_BRICK_VENDOR_ID &&
		    descriptor.idProduct == USB_BRICK_PRODUCT_ID) {
			if (descriptor.bcdDevice < USB_BRICK_DEVICE_RELEASE) {
				log_warn("USB device (bus: %u, device: %u) has unsupported protocol 1.0 firmware, please update firmware, ignoring USB device",
				         bus_number, device_address);

				continue;
			}
		} else if (descriptor.idVendor == USB_RED_BRICK_VENDOR_ID &&
		           descriptor.idProduct == USB_RED_BRICK_PRODUCT_ID) {
			if (descriptor.bcdDevice < USB_RED_BRICK_DEVICE_RELEASE) {
				log_warn("USB device (bus: %u, device: %u) has unexpected release version, ignoring USB device",
				         bus_number, device_address);

				continue;
			}
		} else {
			continue;
		}

		// check all known stacks
		known = false;

		for (k = 0; k < _usb_stacks.count; ++k) {
			usb_stack = array_get(&_usb_stacks, k);

			if (usb_stack->bus_number == bus_number &&
			    usb_stack->device_address == device_address) {
				// mark known USBStack as connected
				usb_stack->connected = true;
				known = true;

				break;
			}
		}

		if (known) {
			continue;
		}

		// create new USBStack object
		log_debug("Found new USB device (bus: %u, device: %u)",
		          bus_number, device_address);

		usb_stack = array_append(&_usb_stacks);

		if (usb_stack == NULL) {
			log_error("Could not append to USB stacks array: %s (%d)",
			          get_errno_name(errno), errno);

			goto cleanup;
		}

		if (usb_stack_create(usb_stack, bus_number, device_address) < 0) {
			array_remove(&_usb_stacks, _usb_stacks.count - 1, NULL);

			log_warn("Ignoring USB device (bus: %u, device: %u) due to an error",
			         bus_number, device_address);

			continue;
		}

		// mark new stack as connected
		usb_stack->connected = true;

		log_info("Added USB device (bus: %u, device: %u) at index %d: %s",
		         usb_stack->bus_number, usb_stack->device_address,
		         _usb_stacks.count - 1, usb_stack->base.name);
	}

	result = 0;

cleanup:
	libusb_free_device_list(devices, 1);

	return result;
}
Exemple #4
0
int usb_get_interface_endpoints(libusb_device_handle *device_handle, int interface_number,
                                uint8_t *endpoint_in, uint8_t *endpoint_out) {
	int rc;
	libusb_device *device = libusb_get_device(device_handle);
	uint8_t bus_number = libusb_get_bus_number(device);
	uint8_t device_address = libusb_get_device_address(device);
	int i;
	struct libusb_config_descriptor *config_descriptor;
	const struct libusb_interface_descriptor *interface_descriptor;
	int k;
	const struct libusb_endpoint_descriptor *endpoint_descriptor;

	rc = libusb_get_config_descriptor(device, 0, &config_descriptor);

	if (rc < 0) {
		log_error("Could not get config descriptor for USB device (bus: %u, device: %u): %s (%d)",
		          bus_number, device_address, usb_get_error_name(rc), rc);

		return -1;
	}

	if (config_descriptor->bNumInterfaces == 0) {
		log_error("Config descriptor for USB device (bus: %u, device: %u) contains no interfaces",
		          bus_number, device_address);

		return -1;
	}

	for (i = 0; i < config_descriptor->bNumInterfaces; ++i) {
		if (config_descriptor->interface[i].num_altsetting < 1) {
			log_debug("Interface at index %d of USB device (bus: %u, device: %u) has no alt setting, ignoring it",
			          i, bus_number, device_address);

			continue;
		}

		interface_descriptor = &config_descriptor->interface[i].altsetting[0];

		if (interface_descriptor->bInterfaceNumber != interface_number) {
			continue;
		}

		if (interface_descriptor->bNumEndpoints != 2) {
			log_debug("Interface %d of USB device (bus: %u, device: %u) has %d endpoints, expecting 2, ignoring it",
			          interface_descriptor->bInterfaceNumber, bus_number, device_address,
			          interface_descriptor->bNumEndpoints);

			continue;
		}

		for (k = 0; k < interface_descriptor->bNumEndpoints; ++k) {
			endpoint_descriptor = &interface_descriptor->endpoint[k];

			if (endpoint_descriptor->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
				*endpoint_in = endpoint_descriptor->bEndpointAddress;
			} else {
				*endpoint_out = endpoint_descriptor->bEndpointAddress;
			}
		}

		libusb_free_config_descriptor(config_descriptor);

		return 0;
	}

	libusb_free_config_descriptor(config_descriptor);

	return -1;
}
Exemple #5
0
int usb_create_context(libusb_context **context) {
	int phase = 0;
	int rc;
	const struct libusb_pollfd **pollfds = NULL;
	const struct libusb_pollfd **pollfd;
	const struct libusb_pollfd **last_added_pollfd = NULL;

	rc = libusb_init(context);

	if (rc < 0) {
		log_error("Could not initialize libusb context: %s (%d)",
		          usb_get_error_name(rc), rc);

		goto cleanup;
	}

	switch (log_get_effective_level()) {
	case LOG_LEVEL_ERROR:
		libusb_set_debug(*context, 1);
		break;

	case LOG_LEVEL_WARN:
		libusb_set_debug(*context, 2);
		break;

	case LOG_LEVEL_INFO:
		libusb_set_debug(*context, 3);
		break;

	case LOG_LEVEL_DEBUG:
		if (log_is_included(LOG_LEVEL_DEBUG, &_libusb_log_source,
		                    LOG_DEBUG_GROUP_LIBUSB)) {
			libusb_set_debug(*context, 4);
		} else {
			libusb_set_debug(*context, 3);
		}

		break;

	default:
		break;
	}

	phase = 1;

	// get pollfds from main libusb context
	pollfds = libusb_get_pollfds(*context);

	if (pollfds == NULL) {
		log_error("Could not get pollfds from libusb context");

		goto cleanup;
	}

	for (pollfd = pollfds; *pollfd != NULL; ++pollfd) {
		if (event_add_source((*pollfd)->fd, EVENT_SOURCE_TYPE_USB,
		                     (*pollfd)->events, usb_handle_events,
		                     *context) < 0) {
			goto cleanup;
		}

		last_added_pollfd = pollfd;
		phase = 2;
	}

	phase = 3;

	// register pollfd notifiers
	libusb_set_pollfd_notifiers(*context, usb_add_pollfd, usb_remove_pollfd,
	                            *context);

cleanup:
	switch (phase) { // no breaks, all cases fall through intentionally
	case 2:
		for (pollfd = pollfds; pollfd != last_added_pollfd; ++pollfd) {
			event_remove_source((*pollfd)->fd, EVENT_SOURCE_TYPE_USB);
		}

	case 1:
		libusb_exit(*context);

	default:
		break;
	}

#if defined(_WIN32) || (defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000104) // libusb 1.0.20
	libusb_free_pollfds(pollfds); // avoids possible heap-mismatch on Windows
#else
	free(pollfds);
#endif

	return phase == 3 ? 0 : -1;
}
Exemple #6
0
int usb_transfer_submit(USBTransfer *usb_transfer) {
	uint8_t endpoint;
	int length;
	int rc;

	if (usb_transfer->submitted) {
		log_error("%s transfer %p (%p) is already submitted for %s",
		          usb_transfer_get_type_name(usb_transfer->type, true), usb_transfer,
		          usb_transfer->handle, usb_transfer->usb_stack->base.name);

		return -1;
	}

	switch (usb_transfer->type) {
	case USB_TRANSFER_TYPE_READ:
		endpoint = usb_transfer->usb_stack->endpoint_in;
		length = sizeof(Packet);

		break;

	case USB_TRANSFER_TYPE_WRITE:
		endpoint = usb_transfer->usb_stack->endpoint_out;
		length = usb_transfer->packet.header.length;

		break;

	default:
		log_error("Transfer for %s has invalid type",
		          usb_transfer->usb_stack->base.name);

		return -1;
	}

	usb_transfer->submitted = true;

	libusb_fill_bulk_transfer(usb_transfer->handle,
	                          usb_transfer->usb_stack->device_handle,
	                          endpoint,
	                          (unsigned char *)&usb_transfer->packet,
	                          length,
	                          usb_transfer_wrapper,
	                          usb_transfer,
	                          0);

	rc = libusb_submit_transfer(usb_transfer->handle);

	if (rc < 0) {
		log_error("Could not submit %s transfer %p (%p) to %s: %s (%d)",
		          usb_transfer_get_type_name(usb_transfer->type, false), usb_transfer,
		          usb_transfer->handle, usb_transfer->usb_stack->base.name,
		          usb_get_error_name(rc), rc);

		usb_transfer->submitted = false;

		return -1;
	}

	log_packet_debug("Submitted %s transfer %p (%p) for %u bytes to %s",
	                 usb_transfer_get_type_name(usb_transfer->type, false),
	                 usb_transfer, usb_transfer->handle, length,
	                 usb_transfer->usb_stack->base.name);

	return 0;
}
Exemple #7
0
void usb_transfer_destroy(USBTransfer *usb_transfer) {
	struct timeval tv;
	time_t start;
	time_t now;
	int rc;

	log_debug("Destroying %s transfer %p (%p) for %s",
	          usb_transfer_get_type_name(usb_transfer->type, false), usb_transfer,
	          usb_transfer->handle, usb_transfer->usb_stack->base.name);

	if (usb_transfer->submitted) {
		usb_transfer->completed = false;
		usb_transfer->cancelled = true;

		rc = libusb_cancel_transfer(usb_transfer->handle);

		// if libusb_cancel_transfer fails with LIBUSB_ERROR_NO_DEVICE if the
		// device was disconnected before the transfer could be cancelled. but
		// the transfer might be cancelled anyway and we need to wait for the
		// transfer to complete. this can result in waiting for a transfer that
		// might not complete anymore. but if we don't wait for the transfer to
		// complete if it actually will complete then the libusb_device_handle
		// might be closed before the transfer completes. this results in a
		// crash by NULL pointer dereference because libusb assumes that the
		// libusb_device_handle is not closed as long as there are submitted
		// transfers.
		if (rc < 0 && rc != LIBUSB_ERROR_NO_DEVICE) {
			log_warn("Could not cancel pending %s transfer %p (%p) for %s: %s (%d)",
			         usb_transfer_get_type_name(usb_transfer->type, false), usb_transfer,
			         usb_transfer->handle, usb_transfer->usb_stack->base.name,
			         usb_get_error_name(rc), rc);
		} else {
			tv.tv_sec = 0;
			tv.tv_usec = 0;

			start = time(NULL);
			now = start;

			// FIXME: don't wait 1 second per transfer
			while (!usb_transfer->completed && now >= start && now < start + 1) {
				rc = libusb_handle_events_timeout(usb_transfer->usb_stack->context, &tv);

				if (rc < 0) {
					log_error("Could not handle USB events during %s transfer %p (%p) cancellation for %s: %s (%d)",
					          usb_transfer_get_type_name(usb_transfer->type, false),
					          usb_transfer, usb_transfer->handle,
					          usb_transfer->usb_stack->base.name,
					          usb_get_error_name(rc), rc);
				}

				now = time(NULL);
			}

			if (!usb_transfer->completed) {
				log_warn("Attempt to cancel pending %s transfer %p (%p) for %s timed out",
				         usb_transfer_get_type_name(usb_transfer->type, false), usb_transfer,
				         usb_transfer->handle, usb_transfer->usb_stack->base.name);
			}
		}
	}

	if (!usb_transfer->submitted) {
		libusb_free_transfer(usb_transfer->handle);
	} else {
		log_warn("Leaking pending %s transfer %p (%p) for %s",
		         usb_transfer_get_type_name(usb_transfer->type, false), usb_transfer,
		         usb_transfer->handle, usb_transfer->usb_stack->base.name);
	}
}