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 /* list of poll fd's */
44 static struct list_head pollfds;
46 /* user callbacks for pollfd changes */
47 static libusb_pollfd_added_cb fd_added_cb = NULL;
48 static libusb_pollfd_removed_cb fd_removed_cb = NULL;
52 list_init(&flying_transfers);
58 static int calculate_timeout(struct usbi_transfer *transfer)
61 struct timespec current_time;
62 unsigned int timeout = transfer->pub.timeout;
67 r = clock_gettime(CLOCK_MONOTONIC, ¤t_time);
69 usbi_err("failed to read monotonic clock, errno=%d", errno);
73 current_time.tv_sec += timeout / 1000;
74 current_time.tv_nsec += (timeout % 1000) * 1000000;
76 if (current_time.tv_nsec > 1000000000) {
77 current_time.tv_nsec -= 1000000000;
78 current_time.tv_sec++;
81 TIMESPEC_TO_TIMEVAL(&transfer->timeout, ¤t_time);
85 static void add_to_flying_list(struct usbi_transfer *transfer)
87 struct usbi_transfer *cur;
88 struct timeval *timeout = &transfer->timeout;
90 /* if we have no other flying transfers, start the list with this one */
91 if (list_empty(&flying_transfers)) {
92 list_add(&transfer->list, &flying_transfers);
96 /* if we have infinite timeout, append to end of list */
97 if (!timerisset(timeout)) {
98 list_add_tail(&transfer->list, &flying_transfers);
102 /* otherwise, find appropriate place in list */
103 list_for_each_entry(cur, &flying_transfers, list) {
104 /* find first timeout that occurs after the transfer in question */
105 struct timeval *cur_tv = &cur->timeout;
107 if (!timerisset(cur_tv) || (cur_tv->tv_sec > timeout->tv_sec) ||
108 (cur_tv->tv_sec == timeout->tv_sec &&
109 cur_tv->tv_usec > timeout->tv_usec)) {
110 list_add_tail(&transfer->list, &cur->list);
115 /* otherwise we need to be inserted at the end */
116 list_add_tail(&transfer->list, &flying_transfers);
119 static int submit_transfer(struct usbi_transfer *itransfer)
121 int r = usbi_backend->submit_transfer(itransfer);
125 add_to_flying_list(itransfer);
129 API_EXPORTED size_t libusb_get_transfer_alloc_size(void)
131 return sizeof(struct usbi_transfer) + usbi_backend->transfer_priv_size;
134 void __init_transfer(struct usbi_transfer *transfer)
136 memset(transfer, 0, sizeof(*transfer));
139 API_EXPORTED void libusb_init_transfer(struct libusb_transfer *transfer)
141 __init_transfer(TRANSFER_TO_PRIV(transfer));
144 API_EXPORTED struct libusb_transfer *libusb_alloc_transfer(void)
146 struct usbi_transfer *transfer =
147 malloc(sizeof(*transfer) + usbi_backend->transfer_priv_size);
151 __init_transfer(transfer);
152 return &transfer->pub;
155 API_EXPORTED int libusb_submit_transfer(struct libusb_transfer *transfer)
157 struct usbi_transfer *itransfer = TRANSFER_TO_PRIV(transfer);
160 itransfer->transferred = 0;
161 r = calculate_timeout(itransfer);
165 if (transfer->endpoint_type == LIBUSB_ENDPOINT_TYPE_CONTROL) {
166 struct libusb_control_setup *setup =
167 (struct libusb_control_setup *) transfer->buffer;
169 usbi_dbg("RQT=%02x RQ=%02x VAL=%04x IDX=%04x length=%d",
170 setup->bRequestType, setup->bRequest, setup->wValue, setup->wIndex,
173 setup->wValue = cpu_to_le16(setup->wValue);
174 setup->wIndex = cpu_to_le16(setup->wIndex);
175 setup->wLength = cpu_to_le16(setup->wLength);
178 return submit_transfer(itransfer);
181 API_EXPORTED int libusb_cancel_transfer(struct libusb_transfer *transfer)
183 struct usbi_transfer *itransfer = TRANSFER_TO_PRIV(transfer);
187 r = usbi_backend->cancel_transfer(itransfer);
189 usbi_err("cancel transfer failed error %d", r);
193 API_EXPORTED int libusb_cancel_transfer_sync(struct libusb_transfer *transfer)
195 struct usbi_transfer *itransfer = TRANSFER_TO_PRIV(transfer);
199 r = usbi_backend->cancel_transfer(itransfer);
201 usbi_err("cancel transfer failed error %d", r);
205 itransfer->flags |= USBI_TRANSFER_SYNC_CANCELLED;
206 while (itransfer->flags & USBI_TRANSFER_SYNC_CANCELLED) {
215 void usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
216 enum libusb_transfer_status status)
218 struct libusb_transfer *transfer = &itransfer->pub;
220 if (status == LIBUSB_TRANSFER_SILENT_COMPLETION)
223 if (status == LIBUSB_TRANSFER_COMPLETED
224 && transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
225 int rqlen = transfer->length;
226 if (transfer->endpoint_type == LIBUSB_ENDPOINT_TYPE_CONTROL)
227 rqlen -= LIBUSB_CONTROL_SETUP_SIZE;
228 if (rqlen != itransfer->transferred) {
229 usbi_dbg("interpreting short transfer as error");
230 status = LIBUSB_TRANSFER_ERROR;
234 transfer->status = status;
235 transfer->actual_length = itransfer->transferred;
236 if (transfer->callback)
237 transfer->callback(transfer);
238 if (transfer->flags & LIBUSB_TRANSFER_FREE_TRANSFER)
239 libusb_free_transfer(transfer);
242 void usbi_handle_transfer_cancellation(struct usbi_transfer *transfer)
244 /* if the URB is being cancelled synchronously, raise cancellation
245 * completion event by unsetting flag, and ensure that user callback does
248 if (transfer->flags & USBI_TRANSFER_SYNC_CANCELLED) {
249 transfer->flags &= ~USBI_TRANSFER_SYNC_CANCELLED;
250 usbi_dbg("detected sync. cancel");
251 usbi_handle_transfer_completion(transfer,
252 LIBUSB_TRANSFER_SILENT_COMPLETION);
256 /* if the URB was cancelled due to timeout, report timeout to the user */
257 if (transfer->flags & USBI_TRANSFER_TIMED_OUT) {
258 usbi_dbg("detected timeout cancellation");
259 usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_TIMED_OUT);
263 /* otherwise its a normal async cancel */
264 usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_CANCELLED);
267 static void handle_timeout(struct usbi_transfer *itransfer)
269 /* handling timeouts is tricky, as we may race with the kernel: we may
270 * detect a timeout racing with the condition that the urb has actually
271 * completed. we asynchronously cancel the URB and report timeout
272 * to the user when the URB cancellation completes (or not at all if the
273 * URB actually gets delivered as per this race) */
274 struct libusb_transfer *transfer = &itransfer->pub;
277 itransfer->flags |= USBI_TRANSFER_TIMED_OUT;
278 r = libusb_cancel_transfer(transfer);
280 usbi_warn("async cancel failed %d errno=%d", r, errno);
283 static int handle_timeouts(void)
285 struct timespec systime_ts;
286 struct timeval systime;
287 struct usbi_transfer *transfer;
290 if (list_empty(&flying_transfers))
293 /* get current time */
294 r = clock_gettime(CLOCK_MONOTONIC, &systime_ts);
298 TIMESPEC_TO_TIMEVAL(&systime, &systime_ts);
300 /* iterate through flying transfers list, finding all transfers that
301 * have expired timeouts */
302 list_for_each_entry(transfer, &flying_transfers, list) {
303 struct timeval *cur_tv = &transfer->timeout;
305 /* if we've reached transfers of infinite timeout, we're all done */
306 if (!timerisset(cur_tv))
309 /* ignore timeouts we've already handled */
310 if (transfer->flags & USBI_TRANSFER_TIMED_OUT)
313 /* if transfer has non-expired timeout, nothing more to do */
314 if ((cur_tv->tv_sec > systime.tv_sec) ||
315 (cur_tv->tv_sec == systime.tv_sec &&
316 cur_tv->tv_usec > systime.tv_usec))
319 /* otherwise, we've got an expired timeout to handle */
320 handle_timeout(transfer);
326 static int poll_io(struct timeval *tv)
330 fd_set readfds, writefds;
331 fd_set *_readfds = NULL;
332 fd_set *_writefds = NULL;
333 struct usbi_pollfd *ipollfd;
334 int have_readfds = 0;
335 int have_writefds = 0;
336 struct timeval select_timeout;
337 struct timeval timeout;
339 r = libusb_get_next_timeout(&timeout);
341 /* timeout already expired? */
342 if (!timerisset(&timeout))
343 return handle_timeouts();
345 /* choose the smallest of next URB timeout or user specified timeout */
346 if (timercmp(&timeout, tv, <))
347 select_timeout = timeout;
349 select_timeout = *tv;
351 select_timeout = *tv;
356 list_for_each_entry(ipollfd, &pollfds, list) {
357 struct libusb_pollfd *pollfd = &ipollfd->pollfd;
359 if (pollfd->events & POLLIN) {
361 FD_SET(fd, &readfds);
363 if (pollfd->events & POLLOUT) {
365 FD_SET(fd, &writefds);
374 _writefds = &writefds;
376 usbi_dbg("select() with timeout in %d.%06ds", select_timeout.tv_sec,
377 select_timeout.tv_usec);
378 r = select(maxfd + 1, _readfds, _writefds, NULL, &select_timeout);
379 usbi_dbg("select() returned %d with %d.%06ds remaining",
380 r, select_timeout.tv_sec, select_timeout.tv_usec);
382 *tv = select_timeout;
383 return handle_timeouts();
384 } else if (r == -1 && errno == EINTR) {
387 usbi_err("select failed %d err=%d\n", r, errno);
391 r = usbi_backend->handle_events(_readfds, _writefds);
395 /* FIXME check return value? */
396 return handle_timeouts();
399 API_EXPORTED int libusb_poll_timeout(struct timeval *tv)
404 API_EXPORTED int libusb_poll(void)
412 API_EXPORTED int libusb_get_next_timeout(struct timeval *tv)
414 struct usbi_transfer *transfer;
415 struct timespec cur_ts;
416 struct timeval cur_tv;
417 struct timeval *next_timeout;
421 if (list_empty(&flying_transfers)) {
422 usbi_dbg("no URBs, no timeout!");
426 /* find next transfer which hasn't already been processed as timed out */
427 list_for_each_entry(transfer, &flying_transfers, list) {
428 if (!(transfer->flags & USBI_TRANSFER_TIMED_OUT)) {
435 usbi_dbg("all URBs have already been processed for timeouts");
439 next_timeout = &transfer->timeout;
441 /* no timeout for next transfer */
442 if (!timerisset(next_timeout)) {
443 usbi_dbg("no URBs with timeouts, no timeout!");
447 r = clock_gettime(CLOCK_MONOTONIC, &cur_ts);
449 usbi_err("failed to read monotonic clock, errno=%d", errno);
452 TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts);
454 if (timercmp(&cur_tv, next_timeout, >=)) {
455 usbi_dbg("first timeout already expired");
458 timersub(next_timeout, &cur_tv, tv);
459 usbi_dbg("next timeout in %d.%06ds", tv->tv_sec, tv->tv_usec);
465 API_EXPORTED void libusb_free_transfer(struct libusb_transfer *transfer)
467 struct usbi_transfer *itransfer;
471 if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
472 free(transfer->buffer);
474 itransfer = TRANSFER_TO_PRIV(transfer);
478 API_EXPORTED void libusb_set_pollfd_notifiers(libusb_pollfd_added_cb added_cb,
479 libusb_pollfd_removed_cb removed_cb)
481 fd_added_cb = added_cb;
482 fd_removed_cb = removed_cb;
485 int usbi_add_pollfd(int fd, short events)
487 struct usbi_pollfd *ipollfd = malloc(sizeof(*ipollfd));
491 usbi_dbg("add fd %d events %d", fd, events);
492 ipollfd->pollfd.fd = fd;
493 ipollfd->pollfd.events = events;
494 list_add(&ipollfd->list, &pollfds);
497 fd_added_cb(fd, events);
501 void usbi_remove_pollfd(int fd)
503 struct usbi_pollfd *ipollfd;
506 usbi_dbg("remove fd %d", fd);
507 list_for_each_entry(ipollfd, &pollfds, list)
508 if (ipollfd->pollfd.fd == fd) {
514 usbi_err("couldn't find fd %d to remove", fd);
518 list_del(&ipollfd->list);
524 API_EXPORTED struct libusb_pollfd **libusb_get_pollfds(void)
526 struct libusb_pollfd **ret;
527 struct usbi_pollfd *ipollfd;
531 list_for_each_entry(ipollfd, &pollfds, list)
534 ret = calloc(cnt + 1, sizeof(struct libusb_pollfd *));
538 list_for_each_entry(ipollfd, &pollfds, list)
539 ret[i++] = (struct libusb_pollfd *) ipollfd;