]> mj.ucw.cz Git - ursary.git/blob - usb.c
Better IR control of lights
[ursary.git] / usb.c
1 /*
2  *      LibUSB over LibUCW Mainloop
3  *
4  *      (c) 2014--2020 Martin Mares <mj@ucw.cz>
5  */
6
7 #undef LOCAL_DEBUG
8
9 #include <ucw/lib.h>
10 #include <ucw/clists.h>
11 #include <ucw/gary.h>
12 #include <ucw/mainloop.h>
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <sys/poll.h>
18
19 #include "ursaryd.h"
20 #include "usb.h"
21
22 libusb_context *usb_ctx;
23
24 static struct main_file **usb_fds;
25
26 static int usb_fd_ready(struct main_file *f UNUSED)
27 {
28   DBG("USB: Handling events (ready on fd %d)", f->fd);
29   struct timeval tv = { 0, 0 };
30   int comp = 0;
31   int err = libusb_handle_events_timeout_completed(usb_ctx, &tv, &comp);
32   if (err < 0)
33     msg(L_ERROR, "libusb_handle_events: error %d", err);
34   return HOOK_IDLE;
35 }
36
37 static void usb_added_fd(int fd, short events, void *user_data UNUSED)
38 {
39   if (fd >= (int) GARY_SIZE(usb_fds))
40     GARY_RESIZE(usb_fds, fd + 1);
41
42   struct main_file *f = usb_fds[fd];
43   if (!f)
44     {
45       f = xmalloc_zero(sizeof(*f));
46       usb_fds[fd] = f;
47     }
48   else if (file_is_active(f))
49     {
50       DBG("USB: Releasing fd %d", fd);
51       file_del(f);
52     }
53
54   DBG("USB: Adding fd %d with event mask %u", fd, events);
55   f->fd = fd;
56   f->read_handler = (events & POLLIN) ? usb_fd_ready : NULL;
57   f->write_handler = (events & POLLOUT) ? usb_fd_ready : NULL;
58   file_add(f);
59 }
60
61 static void usb_removed_fd(int fd, void *user_data UNUSED)
62 {
63   DBG("USB: Releasing fd %d", fd);
64   ASSERT(fd < (int) GARY_SIZE(usb_fds));
65   struct main_file *f = usb_fds[fd];
66   ASSERT(f);
67   ASSERT(file_is_active(f));
68   file_del(f);
69 }
70
71 void usb_init(void)
72 {
73   int err;
74
75   // Initialize libusb
76   if ((err = libusb_init(&usb_ctx)) < 0)
77     die("libusb_init failed: error %d", err);
78
79   // Connect libusb to UCW mainloop
80
81   if (!libusb_pollfds_handle_timeouts(usb_ctx))
82     die("Unsupported version of libusb, please fix me");
83
84   GARY_INIT_ZERO(usb_fds, 0);
85   libusb_set_pollfd_notifiers(usb_ctx, usb_added_fd, usb_removed_fd, NULL);
86
87   const struct libusb_pollfd **fds = libusb_get_pollfds(usb_ctx);
88   ASSERT(fds);
89   for (int i=0; fds[i]; i++)
90     usb_added_fd(fds[i]->fd, fds[i]->events, NULL);
91   free(fds);
92 }