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
#include <errno.h>
#include <fcntl.h>
#include <features.h>
+#include <poll.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
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, ...)
{
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
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;
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;
}
free(urbh);
}
-API_EXPORTED int libusb_get_pollfd(void)
+int usbi_get_signalfd(void)
{
return sigfd;
}
/* 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);
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 */