Beispiel #1
0
/** Create an event source for libusb I/O.
 *
 * TODO: The combination of the USB I/O source with a user timeout is
 * conceptually broken. The user timeout supplied here is completely
 * unrelated to I/O -- the actual I/O timeout is set when submitting
 * a USB transfer.
 * The sigrok drivers generally use the timeout to poll device state.
 * Usually, this polling can be sensibly done only when there is no
 * active USB transfer -- i.e. it's actually mutually exclusive with
 * waiting for transfer completion.
 * Thus, the user timeout should be removed from the USB event source
 * API at some point. Instead, drivers should install separate timer
 * event sources for their polling needs.
 *
 * @param session The session the event source belongs to.
 * @param usb_ctx The libusb context for which to handle events.
 * @param timeout_ms The timeout interval in ms, or -1 to wait indefinitely.
 * @return A new event source object, or NULL on failure.
 */
static GSource *usb_source_new(struct sr_session *session,
		struct libusb_context *usb_ctx, int timeout_ms)
{
	static GSourceFuncs usb_source_funcs = {
		.prepare  = &usb_source_prepare,
		.check    = &usb_source_check,
		.dispatch = &usb_source_dispatch,
		.finalize = &usb_source_finalize
	};
	GSource *source;
	struct usb_source *usource;
	const struct libusb_pollfd **upollfds, **upfd;

	upollfds = libusb_get_pollfds(usb_ctx);
	if (!upollfds) {
		sr_err("Failed to get libusb file descriptors.");
		return NULL;
	}
	source = g_source_new(&usb_source_funcs, sizeof(struct usb_source));
	usource = (struct usb_source *)source;

	g_source_set_name(source, "usb");

	if (timeout_ms >= 0) {
		usource->timeout_us = 1000 * (int64_t)timeout_ms;
		usource->due_us = 0;
	} else {
		usource->timeout_us = -1;
		usource->due_us = INT64_MAX;
	}
	usource->session = session;
	usource->usb_ctx = usb_ctx;
	usource->pollfds = g_ptr_array_new_full(8, &usb_source_free_pollfd);

	for (upfd = upollfds; *upfd != NULL; upfd++)
		usb_pollfd_added((*upfd)->fd, (*upfd)->events, usource);

#if (LIBUSB_API_VERSION >= 0x01000104)
	libusb_free_pollfds(upollfds);
#else
	free(upollfds);
#endif
	libusb_set_pollfd_notifiers(usb_ctx,
		&usb_pollfd_added, &usb_pollfd_removed, usource);

	return source;
}
Beispiel #2
0
void usb_destroy_context(libusb_context *context) {
	const struct libusb_pollfd **pollfds = NULL;
	const struct libusb_pollfd **pollfd;

	libusb_set_pollfd_notifiers(context, NULL, NULL, NULL);

	pollfds = libusb_get_pollfds(context);

	if (pollfds == NULL) {
		log_error("Could not get pollfds from main libusb context");
	} else {
		for (pollfd = pollfds; *pollfd != NULL; ++pollfd) {
			event_remove_source((*pollfd)->fd, EVENT_SOURCE_TYPE_USB);
		}

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

	libusb_exit(context);
}
Beispiel #3
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;
}