diff options
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | libusb/core.c | 30 | ||||
-rw-r--r-- | libusb/io.c | 59 | ||||
-rw-r--r-- | libusb/libusb.h | 7 |
4 files changed, 68 insertions, 31 deletions
@@ -1,10 +1,9 @@ isochronous endpoint I/O optional timerfd support (runtime detection) +timer (call me back in 2 seconds) implementation (then remove signalfd) API docs notifications of hotplugged/unplugged devices thread safety -signalfd emulation through pipes and sigaction() for older kernels -signalfd not needed for usbfs? can we poll on the fd? use poll() rather than select()? abstraction for cross-platform-ness diff --git a/libusb/core.c b/libusb/core.c index 9fca011..8fb8fd7 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -24,6 +24,7 @@ #include <errno.h> #include <fcntl.h> #include <features.h> +#include <poll.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -306,6 +307,35 @@ API_EXPORTED void libusb_exit(void) usbi_io_exit(); } +API_EXPORTED size_t libusb_get_pollfds(struct libusb_pollfd **pollfds) +{ + struct libusb_dev_handle *devh; + struct libusb_pollfd *ret; + /* initialise to 1 for signalfd */ + size_t cnt = 1; + size_t i = 0; + + /* count number of open devices */ + list_for_each_entry(devh, &open_devs, list) + cnt++; + + /* create array */ + ret = calloc(cnt, sizeof(struct libusb_pollfd)); + + /* add fds */ + list_for_each_entry(devh, &open_devs, list) { + ret[i++].fd = devh->fd; + ret[i].events = POLLOUT; + } + + /* add signalfd */ + ret[i].fd = usbi_get_signalfd(); + ret[i].events = POLLIN; + + *pollfds = ret; + return cnt; +} + void usbi_log(enum usbi_log_level level, const char *function, const char *format, ...) { diff --git a/libusb/io.c b/libusb/io.c index 06b7666..65edede 100644 --- a/libusb/io.c +++ b/libusb/io.c @@ -176,7 +176,6 @@ static int submit_urb(struct libusb_dev_handle *devh, urb->endpoint = urbh->endpoint; urb->buffer = urbh->buffer + urbh->transferred; urb->buffer_length = MIN(to_be_transferred, MAX_URB_BUFFER_LENGTH); - urb->signr = signum; /* FIXME: for requests that we have to split into multiple URBs, we should * submit all the URBs instantly: submit, submit, submit, reap, reap, reap @@ -492,24 +491,6 @@ static int handle_timeouts(void) return 0; } -static int reap(void) -{ - struct libusb_dev_handle *devh; - int r; - - list_for_each_entry(devh, &open_devs, list) { - r = reap_for_devh(devh); - if (r == -1 && errno == EAGAIN) - continue; - if (r < 0) - return r; - } - - r = handle_timeouts(); - - return 0; -} - static int flush_sigfd(void) { int r; @@ -528,24 +509,46 @@ static int flush_sigfd(void) static int poll_io(struct timeval *tv) { + struct libusb_dev_handle *devh; int r; - fd_set fds; + int maxfd = sigfd; + fd_set readfds; + fd_set writefds; + + FD_ZERO(&readfds); + FD_SET(sigfd, &readfds); + + FD_ZERO(&writefds); + list_for_each_entry(devh, &open_devs, list) { + int fd = devh->fd; + FD_SET(fd, &writefds); + if (fd > maxfd) + maxfd = fd; + } - FD_ZERO(&fds); - FD_SET(sigfd, &fds); - r = select(sigfd + 1, &fds, NULL, NULL, tv); - if (r == -1 && errno == EINTR) + r = select(maxfd + 1, &readfds, &writefds, NULL, tv); + if (r == 0 || (r == -1 && errno == EINTR)) { return 0; - if (r < 0) { + } else if (r < 0) { usbi_err("select failed %d err=%d\n", r, errno); return r; } - if (r > 0) { + if (FD_ISSET(sigfd, &readfds)) flush_sigfd(); - return reap(); + + list_for_each_entry(devh, &open_devs, list) { + if (!FD_ISSET(devh->fd, &writefds)) + continue; + r = reap_for_devh(devh); + if (r == -1 && errno == EAGAIN) + continue; + if (r < 0) + return r; } + /* FIXME check return value? */ + handle_timeouts(); return 0; } @@ -702,7 +705,7 @@ API_EXPORTED void libusb_urb_handle_free(struct libusb_urb_handle *urbh) free(urbh); } -API_EXPORTED int libusb_get_pollfd(void) +int usbi_get_signalfd(void) { return sigfd; } diff --git a/libusb/libusb.h b/libusb/libusb.h index bff48f2..1358680 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -235,6 +235,11 @@ int libusb_release_interface(libusb_dev_handle *dev, int iface); /* async I/O */ +struct libusb_pollfd { + int fd; + short events; +}; + libusb_urb_handle *libusb_async_control_transfer(libusb_dev_handle *devh, struct libusb_control_transfer *transfer, libusb_ctrl_cb_fn callback, void *user_data, unsigned int timeout); @@ -252,7 +257,7 @@ void libusb_urb_handle_free(libusb_urb_handle *urbh); int libusb_poll_timeout(struct timeval *tv); int libusb_poll(void); -int libusb_get_pollfd(void); +size_t libusb_get_pollfds(struct libusb_pollfd **pollfds); /* sync I/O */ |