summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO3
-rw-r--r--libusb/core.c30
-rw-r--r--libusb/io.c59
-rw-r--r--libusb/libusb.h7
4 files changed, 68 insertions, 31 deletions
diff --git a/TODO b/TODO
index f4becf6..cc3597b 100644
--- a/TODO
+++ b/TODO
@@ -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 */