⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io.c

📁 linux 下的libusb 1.0.0版本
💻 C
📖 第 1 页 / 共 5 页
字号:
	pthread_mutex_init(&ctx->flying_transfers_lock, NULL);	pthread_mutex_init(&ctx->pollfds_lock, NULL);	pthread_mutex_init(&ctx->pollfd_modify_lock, NULL);	pthread_mutex_init(&ctx->events_lock, NULL);	pthread_mutex_init(&ctx->event_waiters_lock, NULL);	pthread_cond_init(&ctx->event_waiters_cond, NULL);	list_init(&ctx->flying_transfers);	list_init(&ctx->pollfds);	/* FIXME should use an eventfd on kernels that support it */	r = pipe(ctx->ctrl_pipe);	if (r < 0)		return LIBUSB_ERROR_OTHER;	r = usbi_add_pollfd(ctx, ctx->ctrl_pipe[0], POLLIN);	if (r < 0)		return r;	return 0;}void usbi_io_exit(struct libusb_context *ctx){	usbi_remove_pollfd(ctx, ctx->ctrl_pipe[0]);	close(ctx->ctrl_pipe[0]);	close(ctx->ctrl_pipe[1]);}static int calculate_timeout(struct usbi_transfer *transfer){	int r;	struct timespec current_time;	unsigned int timeout =		__USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout;	if (!timeout)		return 0;	r = clock_gettime(CLOCK_MONOTONIC, &current_time);	if (r < 0) {		usbi_err(ITRANSFER_CTX(transfer),			"failed to read monotonic clock, errno=%d", errno);		return r;	}	current_time.tv_sec += timeout / 1000;	current_time.tv_nsec += (timeout % 1000) * 1000000;	if (current_time.tv_nsec > 1000000000) {		current_time.tv_nsec -= 1000000000;		current_time.tv_sec++;	}	TIMESPEC_TO_TIMEVAL(&transfer->timeout, &current_time);	return 0;}static void add_to_flying_list(struct usbi_transfer *transfer){	struct usbi_transfer *cur;	struct timeval *timeout = &transfer->timeout;	struct libusb_context *ctx = ITRANSFER_CTX(transfer);		pthread_mutex_lock(&ctx->flying_transfers_lock);	/* if we have no other flying transfers, start the list with this one */	if (list_empty(&ctx->flying_transfers)) {		list_add(&transfer->list, &ctx->flying_transfers);		goto out;	}	/* if we have infinite timeout, append to end of list */	if (!timerisset(timeout)) {		list_add_tail(&transfer->list, &ctx->flying_transfers);		goto out;	}	/* otherwise, find appropriate place in list */	list_for_each_entry(cur, &ctx->flying_transfers, list) {		/* find first timeout that occurs after the transfer in question */		struct timeval *cur_tv = &cur->timeout;		if (!timerisset(cur_tv) || (cur_tv->tv_sec > timeout->tv_sec) ||				(cur_tv->tv_sec == timeout->tv_sec &&					cur_tv->tv_usec > timeout->tv_usec)) {			list_add_tail(&transfer->list, &cur->list);			goto out;		}	}	/* otherwise we need to be inserted at the end */	list_add_tail(&transfer->list, &ctx->flying_transfers);out:	pthread_mutex_unlock(&ctx->flying_transfers_lock);}/** \ingroup asyncio * Allocate a libusb transfer with a specified number of isochronous packet * descriptors. The returned transfer is pre-initialized for you. When the new * transfer is no longer needed, it should be freed with * libusb_free_transfer(). * * Transfers intended for non-isochronous endpoints (e.g. control, bulk, * interrupt) should specify an iso_packets count of zero. * * For transfers intended for isochronous endpoints, specify an appropriate * number of packet descriptors to be allocated as part of the transfer. * The returned transfer is not specially initialized for isochronous I/O; * you are still required to set the * \ref libusb_transfer::num_iso_packets "num_iso_packets" and * \ref libusb_transfer::type "type" fields accordingly. * * It is safe to allocate a transfer with some isochronous packets and then * 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 * \returns a newly allocated transfer, or NULL on error */API_EXPORTED struct libusb_transfer *libusb_alloc_transfer(int iso_packets){	size_t os_alloc_size = usbi_backend->transfer_priv_size		+ (usbi_backend->add_iso_packet_size * iso_packets);	int alloc_size = sizeof(struct usbi_transfer)		+ sizeof(struct libusb_transfer)		+ (sizeof(struct libusb_iso_packet_descriptor) * iso_packets)		+ os_alloc_size;	struct usbi_transfer *itransfer = malloc(alloc_size);	if (!itransfer)		return NULL;	memset(itransfer, 0, alloc_size);	itransfer->num_iso_packets = iso_packets;	return __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);}/** \ingroup asyncio * Free a transfer structure. This should be called for all transfers * allocated with libusb_alloc_transfer(). * * If the \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_BUFFER * "LIBUSB_TRANSFER_FREE_BUFFER" flag is set and the transfer buffer is * non-NULL, this function will also free the transfer buffer using the * standard system memory allocator (e.g. free()). * * It is legal to call this function with a NULL transfer. In this case, * the function will simply return safely. * * \param transfer the transfer to free */API_EXPORTED void libusb_free_transfer(struct libusb_transfer *transfer){	struct usbi_transfer *itransfer;	if (!transfer)		return;	if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER && transfer->buffer)		free(transfer->buffer);	itransfer = __LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);	free(itransfer);}/** \ingroup asyncio * Submit a transfer. This function will fire off the USB transfer and then * return immediately. * * It is undefined behaviour to submit a transfer that has already been * submitted but has not yet completed. * * \param transfer the transfer to submit * \returns 0 on success * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure */API_EXPORTED int libusb_submit_transfer(struct libusb_transfer *transfer){	struct usbi_transfer *itransfer =		__LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);	int r;	itransfer->transferred = 0;	itransfer->flags = 0;	r = calculate_timeout(itransfer);	if (r < 0)		return LIBUSB_ERROR_OTHER;	add_to_flying_list(itransfer);	r = usbi_backend->submit_transfer(itransfer);	if (r) {		pthread_mutex_lock(&TRANSFER_CTX(transfer)->flying_transfers_lock);		list_del(&itransfer->list);		pthread_mutex_unlock(&TRANSFER_CTX(transfer)->flying_transfers_lock);	}	return r;}/** \ingroup asyncio * Asynchronously cancel a previously submitted transfer. * It is undefined behaviour to call this function on a transfer that is * already being cancelled or has already completed. * This function returns immediately, but this does not indicate cancellation * is complete. Your callback function will be invoked at some later time * with a transfer status of * \ref libusb_transfer_status::LIBUSB_TRANSFER_CANCELLED * "LIBUSB_TRANSFER_CANCELLED." * * \param transfer the transfer to cancel * \returns 0 on success * \returns a LIBUSB_ERROR code on failure */API_EXPORTED int libusb_cancel_transfer(struct libusb_transfer *transfer){	struct usbi_transfer *itransfer =		__LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);	int r;	usbi_dbg("");	r = usbi_backend->cancel_transfer(itransfer);	if (r < 0)		usbi_err(TRANSFER_CTX(transfer),			"cancel transfer failed error %d", r);	return r;}/* Handle completion of a transfer (completion might be an error condition). * This will invoke the user-supplied callback function, which may end up * freeing the transfer. Therefore you cannot use the transfer structure * after calling this function, and you should free all backend-specific * data before calling it. */void usbi_handle_transfer_completion(struct usbi_transfer *itransfer,	enum libusb_transfer_status status){	struct libusb_transfer *transfer =		__USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);	struct libusb_context *ctx = TRANSFER_CTX(transfer);	uint8_t flags;	pthread_mutex_lock(&ctx->flying_transfers_lock);	list_del(&itransfer->list);	pthread_mutex_unlock(&ctx->flying_transfers_lock);	if (status == LIBUSB_TRANSFER_COMPLETED			&& transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {		int rqlen = transfer->length;		if (transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL)			rqlen -= LIBUSB_CONTROL_SETUP_SIZE;		if (rqlen != itransfer->transferred) {			usbi_dbg("interpreting short transfer as error");			status = LIBUSB_TRANSFER_ERROR;		}	}	flags = transfer->flags;	transfer->status = status;	transfer->actual_length = itransfer->transferred;	if (transfer->callback)		transfer->callback(transfer);	/* transfer might have been freed by the above call, do not use from	 * this point. */	if (flags & LIBUSB_TRANSFER_FREE_TRANSFER)		libusb_free_transfer(transfer);	pthread_mutex_lock(&ctx->event_waiters_lock);	pthread_cond_broadcast(&ctx->event_waiters_cond);	pthread_mutex_unlock(&ctx->event_waiters_lock);}/* Similar to usbi_handle_transfer_completion() but exclusively for transfers * that were asynchronously cancelled. The same concerns w.r.t. freeing of * transfers exist here. */void usbi_handle_transfer_cancellation(struct usbi_transfer *transfer){	/* if the URB was cancelled due to timeout, report timeout to the user */	if (transfer->flags & USBI_TRANSFER_TIMED_OUT) {		usbi_dbg("detected timeout cancellation");		usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_TIMED_OUT);		return;	}	/* otherwise its a normal async cancel */	usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_CANCELLED);}/** \ingroup poll * Attempt to acquire the event handling lock. This lock is used to ensure that * only one thread is monitoring libusb event sources at any one time. * * You only need to use this lock if you are developing an application * which calls poll() or select() on libusb's file descriptors directly. * If you stick to libusb's event handling loop functions (e.g. * libusb_handle_events()) then you do not need to be concerned with this * locking. * * While holding this lock, you are trusted to actually be handling events. * If you are no longer handling events, you must call libusb_unlock_events() * as soon as possible. * * \param ctx the context to operate on, or NULL for the default context * \returns 0 if the lock was obtained successfully * \returns 1 if the lock was not obtained (i.e. another thread holds the lock) * \see \ref mtasync */API_EXPORTED int libusb_try_lock_events(libusb_context *ctx){	int r;	USBI_GET_CONTEXT(ctx);	/* is someone else waiting to modify poll fds? if so, don't let this thread	 * start event handling */	pthread_mutex_lock(&ctx->pollfd_modify_lock);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -