Separate transfer allocation and submission
[platform/upstream/libusb.git] / libusb / io.c
1 /*
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>
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <config.h>
22
23 #include <errno.h>
24 #include <signal.h>
25 #include <stdint.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <sys/select.h>
29 #include <sys/time.h>
30 #include <time.h>
31 #include <unistd.h>
32
33 #include "libusbi.h"
34
35 #define TRANSFER_TO_PRIV(trf) (container_of((trf), struct usbi_transfer, pub))
36
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;
42
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;
46
47 void usbi_io_init()
48 {
49         list_init(&flying_transfers);
50         fd_added_cb = NULL;
51         fd_removed_cb = NULL;
52 }
53
54 static int calculate_timeout(struct usbi_transfer *transfer)
55 {
56         int r;
57         struct timespec current_time;
58         unsigned int timeout = transfer->pub.timeout;
59
60         if (!timeout)
61                 return 0;
62
63         r = clock_gettime(CLOCK_MONOTONIC, &current_time);
64         if (r < 0) {
65                 usbi_err("failed to read monotonic clock, errno=%d", errno);
66                 return r;
67         }
68
69         current_time.tv_sec += timeout / 1000;
70         current_time.tv_nsec += (timeout % 1000) * 1000000;
71
72         if (current_time.tv_nsec > 1000000000) {
73                 current_time.tv_nsec -= 1000000000;
74                 current_time.tv_sec++;
75         }
76
77         TIMESPEC_TO_TIMEVAL(&transfer->timeout, &current_time);
78         return 0;
79 }
80
81 static void add_to_flying_list(struct usbi_transfer *transfer)
82 {
83         struct usbi_transfer *cur;
84         struct timeval *timeout = &transfer->timeout;
85
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);
89                 return;
90         }
91
92         /* if we have infinite timeout, append to end of list */
93         if (!timerisset(timeout)) {
94                 list_add_tail(&transfer->list, &flying_transfers);
95                 return;
96         }
97
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;
102
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);
107                         return;
108                 }
109         }
110
111         /* otherwise we need to be inserted at the end */
112         list_add_tail(&transfer->list, &flying_transfers);
113 }
114
115 static int submit_transfer(struct usbi_transfer *itransfer)
116 {
117         int r;
118         struct usb_urb *urb = &itransfer->urb;
119         struct libusb_transfer *transfer = &itransfer->pub;
120         int to_be_transferred = transfer->length - itransfer->transferred;
121
122         switch (transfer->endpoint_type) {
123         case LIBUSB_ENDPOINT_TYPE_CONTROL:
124                 urb->type = USB_URB_TYPE_CONTROL;
125                 break;
126         case LIBUSB_ENDPOINT_TYPE_BULK:
127                 urb->type = USB_URB_TYPE_BULK;
128                 break;
129         case LIBUSB_ENDPOINT_TYPE_INTERRUPT:
130                 urb->type = USB_URB_TYPE_INTERRUPT;
131                 break;
132         default:
133                 usbi_err("unknown endpoint type %d", transfer->endpoint_type);
134                 return -EINVAL;
135         }
136
137         urb->endpoint = transfer->endpoint;
138         urb->buffer = transfer->buffer + itransfer->transferred;
139         urb->buffer_length = MIN(to_be_transferred, MAX_URB_BUFFER_LENGTH);
140
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,
147                 to_be_transferred);
148
149         r = ioctl(transfer->dev_handle->fd, IOCTL_USB_SUBMITURB, urb);
150         if (r < 0) {
151                 usbi_err("submiturb failed error %d errno=%d", r, errno);
152                 return r;
153         }
154
155         add_to_flying_list(itransfer);
156         return 0;
157 }
158
159 API_EXPORTED size_t libusb_get_transfer_alloc_size(void)
160 {
161         return sizeof(struct usbi_transfer);
162 }
163
164 void __init_transfer(struct usbi_transfer *transfer)
165 {
166         memset(transfer, 0, sizeof(*transfer));
167 }
168
169 API_EXPORTED void libusb_init_transfer(struct libusb_transfer *transfer)
170 {
171         __init_transfer(TRANSFER_TO_PRIV(transfer));
172 }
173
174 API_EXPORTED struct libusb_transfer *libusb_alloc_transfer(void)
175 {
176         struct usbi_transfer *transfer = malloc(sizeof(*transfer));
177         if (!transfer)
178                 return NULL;
179
180         __init_transfer(transfer);
181         return &transfer->pub;
182 }
183
184 API_EXPORTED int libusb_submit_transfer(struct libusb_transfer *transfer)
185 {
186         struct usbi_transfer *itransfer = TRANSFER_TO_PRIV(transfer);
187         int r;
188
189         itransfer->transferred = 0;
190         r = calculate_timeout(itransfer);
191         if (r < 0)
192                 return r;
193
194         if (transfer->endpoint_type == LIBUSB_ENDPOINT_TYPE_CONTROL) {
195                 struct libusb_control_setup *setup =
196                         (struct libusb_control_setup *) transfer->buffer;
197         
198                 usbi_dbg("RQT=%02x RQ=%02x VAL=%04x IDX=%04x length=%d",
199                         setup->bRequestType, setup->bRequest, setup->wValue, setup->wIndex,
200                         setup->wLength);
201
202                 setup->wValue = cpu_to_le16(setup->wValue);
203                 setup->wIndex = cpu_to_le16(setup->wIndex);
204                 setup->wLength = cpu_to_le16(setup->wLength);
205         }
206
207         return submit_transfer(itransfer);
208 }
209
210 API_EXPORTED int libusb_cancel_transfer(struct libusb_dev_handle *devh,
211         struct libusb_transfer *transfer)
212 {
213         struct usbi_transfer *itransfer = TRANSFER_TO_PRIV(transfer);
214         int r;
215
216         usbi_dbg("");
217         r = ioctl(devh->fd, IOCTL_USB_DISCARDURB, &itransfer->urb);
218         if (r < 0)
219                 usbi_err("cancel transfer failed error %d", r);
220         return r;
221 }
222
223 API_EXPORTED int libusb_cancel_transfer_sync(struct libusb_dev_handle *devh,
224         struct libusb_transfer *transfer)
225 {
226         struct usbi_transfer *itransfer = TRANSFER_TO_PRIV(transfer);
227         int r;
228
229         usbi_dbg("");
230         r = ioctl(devh->fd, IOCTL_USB_DISCARDURB, &itransfer->urb);
231         if (r < 0) {
232                 usbi_err("cancel transfer failed error %d", r);
233                 return r;
234         }
235
236         itransfer->flags |= USBI_TRANSFER_SYNC_CANCELLED;
237         while (itransfer->flags & USBI_TRANSFER_SYNC_CANCELLED) {
238                 r = libusb_poll();
239                 if (r < 0)
240                         return r;
241         }
242
243         return 0;
244 }
245
246 static void handle_transfer_completion(struct usbi_transfer *itransfer,
247         enum libusb_transfer_status status)
248 {
249         struct libusb_transfer *transfer = &itransfer->pub;
250
251         if (status == LIBUSB_TRANSFER_SILENT_COMPLETION)
252                 return;
253
254         transfer->status = status;
255         transfer->actual_length = itransfer->transferred;
256         if (transfer->callback)
257                 transfer->callback(transfer);
258 }
259
260 static void handle_transfer_cancellation(struct libusb_dev_handle *devh,
261         struct usbi_transfer *transfer)
262 {
263         /* if the URB is being cancelled synchronously, raise cancellation
264          * completion event by unsetting flag, and ensure that user callback does
265          * not get called.
266          */
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);
271                 return;
272         }
273
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);
278                 return;
279         }
280
281         /* otherwise its a normal async cancel */
282         handle_transfer_completion(transfer, LIBUSB_TRANSFER_CANCELLED);
283 }
284
285 static int reap_for_devh(struct libusb_dev_handle *devh)
286 {
287         int r;
288         struct usb_urb *urb;
289         struct usbi_transfer *itransfer;
290         struct libusb_transfer *transfer;
291         int trf_requested;
292         int length;
293
294         r = ioctl(devh->fd, IOCTL_USB_REAPURBNDELAY, &urb);
295         if (r == -1 && errno == EAGAIN)
296                 return r;
297         if (r < 0) {
298                 usbi_err("reap failed error %d errno=%d", r, errno);
299                 return r;
300         }
301
302         itransfer = container_of(urb, struct usbi_transfer, urb);
303         transfer = &itransfer->pub;
304
305         usbi_dbg("urb type=%d status=%d transferred=%d", urb->type, urb->status,
306                 urb->actual_length);
307         list_del(&itransfer->list);
308
309         if (urb->status == -2) {
310                 handle_transfer_cancellation(devh, itransfer);
311                 return 0;
312         }
313
314         /* FIXME: research what other status codes may exist */
315         if (urb->status != 0)
316                 usbi_warn("unrecognised urb status %d", urb->status);
317
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);
324
325         itransfer->transferred += urb->actual_length;
326
327         /* if we were provided less data than requested, then our transfer is
328          * done */
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);
333                 return 0;
334         }
335
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);
340                 return 0;
341         }
342
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);
347 }
348
349 static void handle_timeout(struct usbi_transfer *itransfer)
350 {
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;
357         int r;
358
359         itransfer->flags |= USBI_TRANSFER_TIMED_OUT;
360         r = libusb_cancel_transfer(transfer->dev_handle, transfer);
361         if (r < 0)
362                 usbi_warn("async cancel failed %d errno=%d", r, errno);
363 }
364
365 static int handle_timeouts(void)
366 {
367         struct timespec systime_ts;
368         struct timeval systime;
369         struct usbi_transfer *transfer;
370         int r;
371
372         if (list_empty(&flying_transfers))
373                 return 0;
374
375         /* get current time */
376         r = clock_gettime(CLOCK_MONOTONIC, &systime_ts);
377         if (r < 0)
378                 return r;
379
380         TIMESPEC_TO_TIMEVAL(&systime, &systime_ts);
381
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;
386
387                 /* if we've reached transfers of infinite timeout, we're all done */
388                 if (!timerisset(cur_tv))
389                         return 0;
390
391                 /* ignore timeouts we've already handled */
392                 if (transfer->flags & USBI_TRANSFER_TIMED_OUT)
393                         continue;
394
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))
399                         return 0;
400         
401                 /* otherwise, we've got an expired timeout to handle */
402                 handle_timeout(transfer);
403         }
404
405         return 0;
406 }
407
408 static int poll_io(struct timeval *tv)
409 {
410         struct libusb_dev_handle *devh;
411         int r;
412         int maxfd = 0;
413         fd_set writefds;
414         struct timeval select_timeout;
415         struct timeval timeout;
416
417         r = libusb_get_next_timeout(&timeout);
418         if (r) {
419                 /* timeout already expired? */
420                 if (!timerisset(&timeout))
421                         return handle_timeouts();
422
423                 /* choose the smallest of next URB timeout or user specified timeout */
424                 if (timercmp(&timeout, tv, <))
425                         select_timeout = timeout;
426                 else
427                         select_timeout = *tv;
428         } else {
429                 select_timeout = *tv;
430         }
431
432         FD_ZERO(&writefds);
433         list_for_each_entry(devh, &open_devs, list) {
434                 int fd = devh->fd;
435                 FD_SET(fd, &writefds);
436                 if (fd > maxfd)
437                         maxfd = fd;
438         }
439
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);
445         if (r == 0) {
446                 *tv = select_timeout;
447                 return handle_timeouts();
448         } else if (r == -1 && errno == EINTR) {
449                 return 0;
450         } else if (r < 0) {
451                 usbi_err("select failed %d err=%d\n", r, errno);
452                 return r;
453         }
454
455         list_for_each_entry(devh, &open_devs, list) {
456                 if (!FD_ISSET(devh->fd, &writefds))
457                         continue;
458                 r = reap_for_devh(devh);
459                 if (r == -1 && errno == EAGAIN)
460                         continue;
461                 if (r < 0)
462                         return r;
463         }
464
465         /* FIXME check return value? */
466         return handle_timeouts();
467 }
468
469 API_EXPORTED int libusb_poll_timeout(struct timeval *tv)
470 {
471         return poll_io(tv);
472 }
473
474 API_EXPORTED int libusb_poll(void)
475 {
476         struct timeval tv;
477         tv.tv_sec = 2;
478         tv.tv_usec = 0;
479         return poll_io(&tv);
480 }
481
482 API_EXPORTED int libusb_get_next_timeout(struct timeval *tv)
483 {
484         struct usbi_transfer *transfer;
485         struct timespec cur_ts;
486         struct timeval cur_tv;
487         struct timeval *next_timeout;
488         int r;
489         int found = 0;
490
491         if (list_empty(&flying_transfers)) {
492                 usbi_dbg("no URBs, no timeout!");
493                 return 0;
494         }
495
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)) {
499                         found = 1;
500                         break;
501                 }
502         }
503
504         if (!found) {
505                 usbi_dbg("all URBs have already been processed for timeouts");
506                 return 0;
507         }
508
509         next_timeout = &transfer->timeout;
510
511         /* no timeout for next transfer */
512         if (!timerisset(next_timeout)) {
513                 usbi_dbg("no URBs with timeouts, no timeout!");
514                 return 0;
515         }
516
517         r = clock_gettime(CLOCK_MONOTONIC, &cur_ts);
518         if (r < 0) {
519                 usbi_err("failed to read monotonic clock, errno=%d", errno);
520                 return r;
521         }
522         TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts);
523
524         if (timercmp(&cur_tv, next_timeout, >=)) {
525                 usbi_dbg("first timeout already expired");
526                 timerclear(tv);
527         } else {
528                 timersub(next_timeout, &cur_tv, tv);
529                 usbi_dbg("next timeout in %d.%06ds", tv->tv_sec, tv->tv_usec);
530         }
531
532         return 1;
533 }
534
535 static void ctrl_transfer_cb(struct libusb_transfer *transfer)
536 {
537         int *completed = transfer->user_data;
538         *completed = 1;
539         usbi_dbg("actual_length=%d", transfer->actual_length);
540         /* caller interprets result and frees transfer */
541 }
542
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)
546 {
547         struct libusb_transfer *transfer = libusb_alloc_transfer();
548         unsigned char *buffer;
549         int length = wLength + LIBUSB_CONTROL_SETUP_SIZE;
550         int completed = 0;
551         int r;
552
553         if (!transfer)
554                 return -ENOMEM;
555         
556         buffer = malloc(length);
557         if (!buffer) {
558                 libusb_free_transfer(transfer);
559                 return -ENOMEM;
560         }
561
562         libusb_fill_control_setup(buffer, bRequestType, bRequest, wValue, wIndex,
563                 wLength);
564         if ((bRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
565                 memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength);
566
567         libusb_fill_control_transfer(transfer, dev_handle, buffer, length,
568                 ctrl_transfer_cb, &completed, timeout);
569         r = libusb_submit_transfer(transfer);
570         if (r < 0) {
571                 libusb_free_transfer(transfer);
572                 return r;
573         }
574
575         while (!completed) {
576                 r = libusb_poll();
577                 if (r < 0) {
578                         libusb_cancel_transfer_sync(dev_handle, transfer);
579                         libusb_free_transfer(transfer);
580                         return r;
581                 }
582         }
583
584         if ((bRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
585                 memcpy(data, libusb_control_transfer_get_data(transfer),
586                         transfer->actual_length);
587
588         switch (transfer->status) {
589         case LIBUSB_TRANSFER_COMPLETED:
590                 r = transfer->actual_length;
591                 break;
592         case LIBUSB_TRANSFER_TIMED_OUT:
593                 r = -ETIMEDOUT;
594                 break;
595         default:
596                 usbi_warn("unrecognised status code %d", transfer->status);
597                 r = -1;
598         }
599
600         libusb_free_transfer(transfer);
601         return r;
602 }
603
604 struct sync_bulk_handle {
605         enum libusb_transfer_status status;
606         int actual_length;
607 };
608
609 static void bulk_transfer_cb(struct libusb_transfer *transfer)
610 {
611         int *completed = transfer->user_data;
612         *completed = 1;
613         usbi_dbg("actual_length=%d", transfer->actual_length);
614         /* caller interprets results and frees transfer */
615 }
616
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)
620 {
621         struct libusb_transfer *transfer = libusb_alloc_transfer();
622         int completed = 0;
623         int r;
624
625         if (!transfer)
626                 return -ENOMEM;
627
628         libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
629                 bulk_transfer_cb, &completed, timeout);
630         transfer->endpoint_type = endpoint_type;
631
632         r = libusb_submit_transfer(transfer);
633         if (r < 0) {
634                 libusb_free_transfer(transfer);
635                 return r;
636         }
637
638         while (!completed) {
639                 r = libusb_poll();
640                 if (r < 0) {
641                         libusb_cancel_transfer_sync(dev_handle, transfer);
642                         libusb_free_transfer(transfer);
643                         return r;
644                 }
645         }
646
647         *transferred = transfer->actual_length;
648         switch (transfer->status) {
649         case LIBUSB_TRANSFER_COMPLETED:
650                 r = 0;
651                 break;
652         case LIBUSB_TRANSFER_TIMED_OUT:
653                 r = -ETIMEDOUT;
654                 break;
655         default:
656                 usbi_warn("unrecognised status code %d", transfer->status);
657                 r = -1;
658         }
659
660         libusb_free_transfer(transfer);
661         return r;
662 }
663
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)
668 {
669         return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
670                 transferred, timeout, LIBUSB_ENDPOINT_TYPE_BULK);
671 }
672
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)
677 {
678         return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
679                 transferred, timeout, LIBUSB_ENDPOINT_TYPE_INTERRUPT);
680 }
681
682 API_EXPORTED void libusb_free_transfer(struct libusb_transfer *transfer)
683 {
684         struct usbi_transfer *itransfer;
685         if (!transfer)
686                 return;
687
688         itransfer = TRANSFER_TO_PRIV(transfer);
689         free(itransfer);
690 }
691
692 API_EXPORTED void libusb_set_pollfd_notifiers(libusb_pollfd_added_cb added_cb,
693         libusb_pollfd_removed_cb removed_cb)
694 {
695         fd_added_cb = added_cb;
696         fd_removed_cb = removed_cb;
697 }
698
699 void usbi_add_pollfd(int fd, short events)
700 {
701         usbi_dbg("add fd %d events %d", fd, events);
702         if (fd_added_cb)
703                 fd_added_cb(fd, events);
704 }
705
706 void usbi_remove_pollfd(int fd)
707 {
708         usbi_dbg("remove fd %d", fd);
709         if (fd_removed_cb)
710                 fd_removed_cb(fd);
711 }
712