2 * I/O functions for libusb
3 * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
4 * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <sys/select.h>
35 #define TRANSFER_TO_PRIV(trf) (container_of((trf), struct usbi_transfer, pub))
37 /* this is a list of in-flight rb_handles, sorted by timeout expiration.
38 * URBs to timeout the soonest are placed at the beginning of the list, URBs
39 * that will time out later are placed after, and urbs with infinite timeout
40 * are always placed at the very end. */
41 static struct list_head flying_transfers;
43 /* user callbacks for pollfd changes */
44 static libusb_pollfd_added_cb fd_added_cb = NULL;
45 static libusb_pollfd_removed_cb fd_removed_cb = NULL;
49 list_init(&flying_transfers);
54 static int calculate_timeout(struct usbi_transfer *transfer)
57 struct timespec current_time;
58 unsigned int timeout = transfer->pub.timeout;
63 r = clock_gettime(CLOCK_MONOTONIC, ¤t_time);
65 usbi_err("failed to read monotonic clock, errno=%d", errno);
69 current_time.tv_sec += timeout / 1000;
70 current_time.tv_nsec += (timeout % 1000) * 1000000;
72 if (current_time.tv_nsec > 1000000000) {
73 current_time.tv_nsec -= 1000000000;
74 current_time.tv_sec++;
77 TIMESPEC_TO_TIMEVAL(&transfer->timeout, ¤t_time);
81 static void add_to_flying_list(struct usbi_transfer *transfer)
83 struct usbi_transfer *cur;
84 struct timeval *timeout = &transfer->timeout;
86 /* if we have no other flying transfers, start the list with this one */
87 if (list_empty(&flying_transfers)) {
88 list_add(&transfer->list, &flying_transfers);
92 /* if we have infinite timeout, append to end of list */
93 if (!timerisset(timeout)) {
94 list_add_tail(&transfer->list, &flying_transfers);
98 /* otherwise, find appropriate place in list */
99 list_for_each_entry(cur, &flying_transfers, list) {
100 /* find first timeout that occurs after the transfer in question */
101 struct timeval *cur_tv = &cur->timeout;
103 if (!timerisset(cur_tv) || (cur_tv->tv_sec > timeout->tv_sec) ||
104 (cur_tv->tv_sec == timeout->tv_sec &&
105 cur_tv->tv_usec > timeout->tv_usec)) {
106 list_add_tail(&transfer->list, &cur->list);
111 /* otherwise we need to be inserted at the end */
112 list_add_tail(&transfer->list, &flying_transfers);
115 static int submit_transfer(struct usbi_transfer *itransfer)
118 struct usb_urb *urb = &itransfer->urb;
119 struct libusb_transfer *transfer = &itransfer->pub;
120 int to_be_transferred = transfer->length - itransfer->transferred;
122 switch (transfer->endpoint_type) {
123 case LIBUSB_ENDPOINT_TYPE_CONTROL:
124 urb->type = USB_URB_TYPE_CONTROL;
126 case LIBUSB_ENDPOINT_TYPE_BULK:
127 urb->type = USB_URB_TYPE_BULK;
129 case LIBUSB_ENDPOINT_TYPE_INTERRUPT:
130 urb->type = USB_URB_TYPE_INTERRUPT;
133 usbi_err("unknown endpoint type %d", transfer->endpoint_type);
137 urb->endpoint = transfer->endpoint;
138 urb->buffer = transfer->buffer + itransfer->transferred;
139 urb->buffer_length = MIN(to_be_transferred, MAX_URB_BUFFER_LENGTH);
141 /* FIXME: for requests that we have to split into multiple URBs, we should
142 * submit all the URBs instantly: submit, submit, submit, reap, reap, reap
143 * rather than: submit, reap, submit, reap, submit, reap
144 * this will improve performance and fix bugs concerning behaviour when
145 * the user submits two similar multiple-urb requests */
146 usbi_dbg("transferring %d from %d bytes", urb->buffer_length,
149 r = ioctl(transfer->dev_handle->fd, IOCTL_USB_SUBMITURB, urb);
151 usbi_err("submiturb failed error %d errno=%d", r, errno);
155 add_to_flying_list(itransfer);
159 API_EXPORTED size_t libusb_get_transfer_alloc_size(void)
161 return sizeof(struct usbi_transfer);
164 void __init_transfer(struct usbi_transfer *transfer)
166 memset(transfer, 0, sizeof(*transfer));
169 API_EXPORTED void libusb_init_transfer(struct libusb_transfer *transfer)
171 __init_transfer(TRANSFER_TO_PRIV(transfer));
174 API_EXPORTED struct libusb_transfer *libusb_alloc_transfer(void)
176 struct usbi_transfer *transfer = malloc(sizeof(*transfer));
180 __init_transfer(transfer);
181 return &transfer->pub;
184 API_EXPORTED int libusb_submit_transfer(struct libusb_transfer *transfer)
186 struct usbi_transfer *itransfer = TRANSFER_TO_PRIV(transfer);
189 itransfer->transferred = 0;
190 r = calculate_timeout(itransfer);
194 if (transfer->endpoint_type == LIBUSB_ENDPOINT_TYPE_CONTROL) {
195 struct libusb_control_setup *setup =
196 (struct libusb_control_setup *) transfer->buffer;
198 usbi_dbg("RQT=%02x RQ=%02x VAL=%04x IDX=%04x length=%d",
199 setup->bRequestType, setup->bRequest, setup->wValue, setup->wIndex,
202 setup->wValue = cpu_to_le16(setup->wValue);
203 setup->wIndex = cpu_to_le16(setup->wIndex);
204 setup->wLength = cpu_to_le16(setup->wLength);
207 return submit_transfer(itransfer);
210 API_EXPORTED int libusb_cancel_transfer(struct libusb_dev_handle *devh,
211 struct libusb_transfer *transfer)
213 struct usbi_transfer *itransfer = TRANSFER_TO_PRIV(transfer);
217 r = ioctl(devh->fd, IOCTL_USB_DISCARDURB, &itransfer->urb);
219 usbi_err("cancel transfer failed error %d", r);
223 API_EXPORTED int libusb_cancel_transfer_sync(struct libusb_dev_handle *devh,
224 struct libusb_transfer *transfer)
226 struct usbi_transfer *itransfer = TRANSFER_TO_PRIV(transfer);
230 r = ioctl(devh->fd, IOCTL_USB_DISCARDURB, &itransfer->urb);
232 usbi_err("cancel transfer failed error %d", r);
236 itransfer->flags |= USBI_TRANSFER_SYNC_CANCELLED;
237 while (itransfer->flags & USBI_TRANSFER_SYNC_CANCELLED) {
246 static void handle_transfer_completion(struct usbi_transfer *itransfer,
247 enum libusb_transfer_status status)
249 struct libusb_transfer *transfer = &itransfer->pub;
251 if (status == LIBUSB_TRANSFER_SILENT_COMPLETION)
254 transfer->status = status;
255 transfer->actual_length = itransfer->transferred;
256 if (transfer->callback)
257 transfer->callback(transfer);
260 static void handle_transfer_cancellation(struct libusb_dev_handle *devh,
261 struct usbi_transfer *transfer)
263 /* if the URB is being cancelled synchronously, raise cancellation
264 * completion event by unsetting flag, and ensure that user callback does
267 if (transfer->flags & USBI_TRANSFER_SYNC_CANCELLED) {
268 transfer->flags &= ~USBI_TRANSFER_SYNC_CANCELLED;
269 usbi_dbg("detected sync. cancel");
270 handle_transfer_completion(transfer, LIBUSB_TRANSFER_SILENT_COMPLETION);
274 /* if the URB was cancelled due to timeout, report timeout to the user */
275 if (transfer->flags & USBI_TRANSFER_TIMED_OUT) {
276 usbi_dbg("detected timeout cancellation");
277 handle_transfer_completion(transfer, LIBUSB_TRANSFER_TIMED_OUT);
281 /* otherwise its a normal async cancel */
282 handle_transfer_completion(transfer, LIBUSB_TRANSFER_CANCELLED);
285 static int reap_for_devh(struct libusb_dev_handle *devh)
289 struct usbi_transfer *itransfer;
290 struct libusb_transfer *transfer;
294 r = ioctl(devh->fd, IOCTL_USB_REAPURBNDELAY, &urb);
295 if (r == -1 && errno == EAGAIN)
298 usbi_err("reap failed error %d errno=%d", r, errno);
302 itransfer = container_of(urb, struct usbi_transfer, urb);
303 transfer = &itransfer->pub;
305 usbi_dbg("urb type=%d status=%d transferred=%d", urb->type, urb->status,
307 list_del(&itransfer->list);
309 if (urb->status == -2) {
310 handle_transfer_cancellation(devh, itransfer);
314 /* FIXME: research what other status codes may exist */
315 if (urb->status != 0)
316 usbi_warn("unrecognised urb status %d", urb->status);
318 /* determine how much data was asked for */
319 length = transfer->length;
320 if (transfer->endpoint_type == LIBUSB_ENDPOINT_TYPE_CONTROL)
321 length -= LIBUSB_CONTROL_SETUP_SIZE;
322 trf_requested = MIN(length - itransfer->transferred,
323 MAX_URB_BUFFER_LENGTH);
325 itransfer->transferred += urb->actual_length;
327 /* if we were provided less data than requested, then our transfer is
329 if (urb->actual_length < trf_requested) {
330 usbi_dbg("less data than requested (%d/%d) --> all done",
331 urb->actual_length, trf_requested);
332 handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
336 /* if we've transferred all data, we're done */
337 if (itransfer->transferred == length) {
338 usbi_dbg("transfer complete --> all done");
339 handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
343 /* otherwise, we have more data to transfer */
344 usbi_dbg("more data to transfer...");
345 memset(urb, 0, sizeof(*urb));
346 return submit_transfer(itransfer);
349 static void handle_timeout(struct usbi_transfer *itransfer)
351 /* handling timeouts is tricky, as we may race with the kernel: we may
352 * detect a timeout racing with the condition that the urb has actually
353 * completed. we asynchronously cancel the URB and report timeout
354 * to the user when the URB cancellation completes (or not at all if the
355 * URB actually gets delivered as per this race) */
356 struct libusb_transfer *transfer = &itransfer->pub;
359 itransfer->flags |= USBI_TRANSFER_TIMED_OUT;
360 r = libusb_cancel_transfer(transfer->dev_handle, transfer);
362 usbi_warn("async cancel failed %d errno=%d", r, errno);
365 static int handle_timeouts(void)
367 struct timespec systime_ts;
368 struct timeval systime;
369 struct usbi_transfer *transfer;
372 if (list_empty(&flying_transfers))
375 /* get current time */
376 r = clock_gettime(CLOCK_MONOTONIC, &systime_ts);
380 TIMESPEC_TO_TIMEVAL(&systime, &systime_ts);
382 /* iterate through flying transfers list, finding all transfers that
383 * have expired timeouts */
384 list_for_each_entry(transfer, &flying_transfers, list) {
385 struct timeval *cur_tv = &transfer->timeout;
387 /* if we've reached transfers of infinite timeout, we're all done */
388 if (!timerisset(cur_tv))
391 /* ignore timeouts we've already handled */
392 if (transfer->flags & USBI_TRANSFER_TIMED_OUT)
395 /* if transfer has non-expired timeout, nothing more to do */
396 if ((cur_tv->tv_sec > systime.tv_sec) ||
397 (cur_tv->tv_sec == systime.tv_sec &&
398 cur_tv->tv_usec > systime.tv_usec))
401 /* otherwise, we've got an expired timeout to handle */
402 handle_timeout(transfer);
408 static int poll_io(struct timeval *tv)
410 struct libusb_dev_handle *devh;
414 struct timeval select_timeout;
415 struct timeval timeout;
417 r = libusb_get_next_timeout(&timeout);
419 /* timeout already expired? */
420 if (!timerisset(&timeout))
421 return handle_timeouts();
423 /* choose the smallest of next URB timeout or user specified timeout */
424 if (timercmp(&timeout, tv, <))
425 select_timeout = timeout;
427 select_timeout = *tv;
429 select_timeout = *tv;
433 list_for_each_entry(devh, &open_devs, list) {
435 FD_SET(fd, &writefds);
440 usbi_dbg("select() with timeout in %d.%06ds", select_timeout.tv_sec,
441 select_timeout.tv_usec);
442 r = select(maxfd + 1, NULL, &writefds, NULL, &select_timeout);
443 usbi_dbg("select() returned %d with %d.%06ds remaining", r, select_timeout.tv_sec,
444 select_timeout.tv_usec);
446 *tv = select_timeout;
447 return handle_timeouts();
448 } else if (r == -1 && errno == EINTR) {
451 usbi_err("select failed %d err=%d\n", r, errno);
455 list_for_each_entry(devh, &open_devs, list) {
456 if (!FD_ISSET(devh->fd, &writefds))
458 r = reap_for_devh(devh);
459 if (r == -1 && errno == EAGAIN)
465 /* FIXME check return value? */
466 return handle_timeouts();
469 API_EXPORTED int libusb_poll_timeout(struct timeval *tv)
474 API_EXPORTED int libusb_poll(void)
482 API_EXPORTED int libusb_get_next_timeout(struct timeval *tv)
484 struct usbi_transfer *transfer;
485 struct timespec cur_ts;
486 struct timeval cur_tv;
487 struct timeval *next_timeout;
491 if (list_empty(&flying_transfers)) {
492 usbi_dbg("no URBs, no timeout!");
496 /* find next transfer which hasn't already been processed as timed out */
497 list_for_each_entry(transfer, &flying_transfers, list) {
498 if (!(transfer->flags & USBI_TRANSFER_TIMED_OUT)) {
505 usbi_dbg("all URBs have already been processed for timeouts");
509 next_timeout = &transfer->timeout;
511 /* no timeout for next transfer */
512 if (!timerisset(next_timeout)) {
513 usbi_dbg("no URBs with timeouts, no timeout!");
517 r = clock_gettime(CLOCK_MONOTONIC, &cur_ts);
519 usbi_err("failed to read monotonic clock, errno=%d", errno);
522 TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts);
524 if (timercmp(&cur_tv, next_timeout, >=)) {
525 usbi_dbg("first timeout already expired");
528 timersub(next_timeout, &cur_tv, tv);
529 usbi_dbg("next timeout in %d.%06ds", tv->tv_sec, tv->tv_usec);
535 static void ctrl_transfer_cb(struct libusb_transfer *transfer)
537 int *completed = transfer->user_data;
539 usbi_dbg("actual_length=%d", transfer->actual_length);
540 /* caller interprets result and frees transfer */
543 API_EXPORTED int libusb_control_transfer(libusb_dev_handle *dev_handle,
544 uint8_t bRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
545 unsigned char *data, uint16_t wLength, unsigned int timeout)
547 struct libusb_transfer *transfer = libusb_alloc_transfer();
548 unsigned char *buffer;
549 int length = wLength + LIBUSB_CONTROL_SETUP_SIZE;
556 buffer = malloc(length);
558 libusb_free_transfer(transfer);
562 libusb_fill_control_setup(buffer, bRequestType, bRequest, wValue, wIndex,
564 if ((bRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
565 memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength);
567 libusb_fill_control_transfer(transfer, dev_handle, buffer, length,
568 ctrl_transfer_cb, &completed, timeout);
569 r = libusb_submit_transfer(transfer);
571 libusb_free_transfer(transfer);
578 libusb_cancel_transfer_sync(dev_handle, transfer);
579 libusb_free_transfer(transfer);
584 if ((bRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
585 memcpy(data, libusb_control_transfer_get_data(transfer),
586 transfer->actual_length);
588 switch (transfer->status) {
589 case LIBUSB_TRANSFER_COMPLETED:
590 r = transfer->actual_length;
592 case LIBUSB_TRANSFER_TIMED_OUT:
596 usbi_warn("unrecognised status code %d", transfer->status);
600 libusb_free_transfer(transfer);
604 struct sync_bulk_handle {
605 enum libusb_transfer_status status;
609 static void bulk_transfer_cb(struct libusb_transfer *transfer)
611 int *completed = transfer->user_data;
613 usbi_dbg("actual_length=%d", transfer->actual_length);
614 /* caller interprets results and frees transfer */
617 static int do_sync_bulk_transfer(struct libusb_dev_handle *dev_handle,
618 unsigned char endpoint, unsigned char *buffer, int length,
619 int *transferred, unsigned int timeout, unsigned char endpoint_type)
621 struct libusb_transfer *transfer = libusb_alloc_transfer();
628 libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
629 bulk_transfer_cb, &completed, timeout);
630 transfer->endpoint_type = endpoint_type;
632 r = libusb_submit_transfer(transfer);
634 libusb_free_transfer(transfer);
641 libusb_cancel_transfer_sync(dev_handle, transfer);
642 libusb_free_transfer(transfer);
647 *transferred = transfer->actual_length;
648 switch (transfer->status) {
649 case LIBUSB_TRANSFER_COMPLETED:
652 case LIBUSB_TRANSFER_TIMED_OUT:
656 usbi_warn("unrecognised status code %d", transfer->status);
660 libusb_free_transfer(transfer);
664 /* FIXME: should transferred be the return value? */
665 API_EXPORTED int libusb_bulk_transfer(struct libusb_dev_handle *dev_handle,
666 unsigned char endpoint, unsigned char *data, int length, int *transferred,
667 unsigned int timeout)
669 return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
670 transferred, timeout, LIBUSB_ENDPOINT_TYPE_BULK);
673 /* FIXME: do we need an interval param here? usbfs doesn't expose it? */
674 API_EXPORTED int libusb_interrupt_transfer(struct libusb_dev_handle *dev_handle,
675 unsigned char endpoint, unsigned char *data, int length, int *transferred,
676 unsigned int timeout)
678 return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
679 transferred, timeout, LIBUSB_ENDPOINT_TYPE_INTERRUPT);
682 API_EXPORTED void libusb_free_transfer(struct libusb_transfer *transfer)
684 struct usbi_transfer *itransfer;
688 itransfer = TRANSFER_TO_PRIV(transfer);
692 API_EXPORTED void libusb_set_pollfd_notifiers(libusb_pollfd_added_cb added_cb,
693 libusb_pollfd_removed_cb removed_cb)
695 fd_added_cb = added_cb;
696 fd_removed_cb = removed_cb;
699 void usbi_add_pollfd(int fd, short events)
701 usbi_dbg("add fd %d events %d", fd, events);
703 fd_added_cb(fd, events);
706 void usbi_remove_pollfd(int fd)
708 usbi_dbg("remove fd %d", fd);