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