4 #include <ucw/bitops.h>
5 #include <ucw/clists.h>
7 #include <ucw/mainloop.h>
8 #include <ucw/string.h>
17 #include <pulse/pulseaudio.h>
20 * Interface to Novation Nocturn
22 * Protocol reverse-engineered by De Wet van Niekerk <dewert@gmail.com>,
23 * see https://github.com/dewert/nocturn-linux-midi for inspiration.
26 static libusb_context *usb_ctx;
27 static libusb_device_handle *usb_dev;
29 static struct main_file **usb_fds;
31 static int usb_fd_ready(struct main_file *f UNUSED)
33 DBG("USB: Handling events (ready on fd %d)", f->fd);
34 struct timeval tv = { 0, 0 };
36 int err = libusb_handle_events_timeout_completed(usb_ctx, &tv, &comp);
38 msg(L_ERROR, "libusb_handle_events: error %d", err);
42 static void usb_added_fd(int fd, short events, void *user_data UNUSED)
44 if (fd >= (int) GARY_SIZE(usb_fds))
45 GARY_RESIZE(usb_fds, fd + 1);
47 struct main_file *f = usb_fds[fd];
50 f = xmalloc_zero(sizeof(*f));
53 else if (file_is_active(f))
55 DBG("USB: Releasing fd %d", fd);
59 DBG("USB: Adding fd %d with event mask %u", fd, events);
61 f->read_handler = (events & POLLIN) ? usb_fd_ready : NULL;
62 f->write_handler = (events & POLLOUT) ? usb_fd_ready : NULL;
66 static void usb_removed_fd(int fd, void *user_data UNUSED)
68 DBG("USB: Releasing fd %d", fd);
69 ASSERT(fd < (int) GARY_SIZE(usb_fds));
70 struct main_file *f = usb_fds[fd];
72 ASSERT(file_is_active(f));
76 static const char noct_init[4][9] = {
77 { 3, 0xb0, 0x00, 0x00 },
78 { 8, 0x28, 0x00, 0x2b, 0x4a, 0x2c, 0x00, 0x2e, 0x35 },
79 { 6, 0x2a, 0x02, 0x2c, 0x72, 0x2e, 0x30 },
83 static void noct_read_done(struct libusb_transfer *xfer)
85 byte *pkt = xfer->buffer;
86 int len = xfer->actual_length;
87 DBG("USB: Read done: status %d, length %d", xfer->status, len);
89 if (xfer->status != LIBUSB_TRANSFER_COMPLETED)
91 msg(L_ERROR, "USB read failed with status %d, not submitting again", xfer->status);
97 mem_to_hex(buf, pkt, len, ' ');
98 DBG("USB: Read <%s>", buf);
106 msg(L_ERROR, "Unknown USB packet: length %d not divisible by 3", len);
111 msg(L_ERROR, "Unknown USB packet: expected 0xb0 at position %d", i);
120 // Unknown packet sent during init
126 int delta = (arg < 0x40 ? arg : arg - 0x80);
127 DBG("Noct: Rotary %d = %d", r, delta);
134 DBG("Noct: Slider value = %d", arg);
139 // Unknown packet, maybe least significant bit of slider
144 int delta = (arg < 0x40 ? arg : arg - 0x80);
145 DBG("Noct: Center = %d", delta);
150 if (arg == 0x00 || arg == 0x7f)
153 DBG("Noct: Center touch = %d", state);
158 if (arg == 0x00 || arg == 0x7f)
161 DBG("Noct: Slider touch = %d", state);
166 if (arg == 0x00 || arg == 0x7f)
170 DBG("Noct: Rotary %d touch = %d", r, state);
175 if (arg == 0x00 || arg == 0x7f)
179 DBG("Noct: Button %d = %d", b, state);
184 msg(L_ERROR, "Unknown USB packet: unrecognized cmd=%02x arg=%02x", cmd, arg);
188 if ((err = libusb_submit_transfer(xfer)) < 0)
189 die("Cannot submit transfer: error %d", err);
192 static void noct_read_init(void)
194 DBG("Noct: Read init");
196 struct libusb_transfer *xfer = libusb_alloc_transfer(0);
197 libusb_fill_interrupt_transfer(xfer, usb_dev, 0x81, xmalloc(8), 8, noct_read_done, NULL, 0);
200 if ((err = libusb_submit_transfer(xfer)) < 0)
201 die("Cannot submit transfer: error %d", err);
204 static byte noct_button_state[16];
205 static byte noct_ring_mode[8]; // 0=from-min, 1=from-max, 2=from-mid-right, 3=from-mid-both, 4=single-on, 5=single-off
206 static byte noct_ring_val[9];
208 static uns noct_dirty_button;
209 static uns noct_dirty_ring_mode;
210 static uns noct_dirty_ring_val;
212 static struct libusb_transfer *noct_write_xfer;
213 static uns noct_write_pending;
214 static void noct_sched_write(void);
216 static void noct_write_done(struct libusb_transfer *xfer)
218 int len = xfer->actual_length;
219 DBG("USB: Write done: status %d, length %d", xfer->status, len);
221 if (xfer->status != LIBUSB_TRANSFER_COMPLETED)
223 msg(L_ERROR, "USB write failed with status %d", xfer->status);
227 noct_write_pending = 0;
231 static void noct_do_write(uns cmd, uns arg)
233 DBG("USB: Submitting write %02x %02x", cmd, arg);
234 ASSERT(!noct_write_pending);
235 noct_write_pending = 1;
237 struct libusb_transfer *xfer = noct_write_xfer;
238 byte *pkt = xfer->buffer;
244 if ((err = libusb_submit_transfer(xfer)) < 0)
245 die("Cannot submit transfer: error %d", err);
248 static void noct_sched_write(void)
250 if (noct_write_pending)
253 if (noct_dirty_button)
255 int i = bit_ffs(noct_dirty_button);
256 noct_dirty_button ^= 1U << i;
257 noct_do_write(0x70 + i, noct_button_state[i]);
259 else if (noct_dirty_ring_mode)
261 int i = bit_ffs(noct_dirty_ring_mode);
262 noct_dirty_ring_mode ^= 1U << i;
263 noct_do_write(0x48 + i, noct_ring_mode[i] << 4);
265 else if (noct_dirty_ring_val)
267 int i = bit_ffs(noct_dirty_ring_val);
268 noct_dirty_ring_val ^= 1U << i;
270 noct_do_write(0x50 + i, noct_ring_val[i]);
272 noct_do_write(0x40 + i, noct_ring_val[i]);
276 static void noct_write_init(void)
278 DBG("Noct: Write init");
280 noct_write_xfer = libusb_alloc_transfer(0);
281 libusb_fill_interrupt_transfer(noct_write_xfer, usb_dev, 0x02, xmalloc(8), 0, noct_write_done, NULL, 1000);
284 noct_button_state[2] = 1;
285 noct_ring_mode[0] = 4;
286 noct_ring_val[0] = 0x40;
289 noct_dirty_button = 0xffff;
290 noct_dirty_ring_mode = 0xff;
291 noct_dirty_ring_val = 0x1ff;
295 static void usb_init(void)
299 if ((err = libusb_init(&usb_ctx)) < 0)
300 die("libusb_init failed: error %d", err);
301 libusb_set_debug(usb_ctx, 3);
303 libusb_device **dev_list;
304 libusb_device *found_dev = NULL;
305 ssize_t len = libusb_get_device_list(usb_ctx, &dev_list);
306 for (ssize_t i=0; i < len; i++)
308 libusb_device *dev = dev_list[i];
309 struct libusb_device_descriptor desc;
310 if (libusb_get_device_descriptor(dev, &desc) >= 0 &&
311 desc.idVendor == 0x1235 &&
312 desc.idProduct == 0x000a)
314 msg(L_DEBUG, "Found device: bus %d, addr %d", libusb_get_bus_number(dev), libusb_get_device_address(dev));
316 die("Multiple Nocturn devices found. Please fix me to handle it.");
317 found_dev = libusb_ref_device(dev);
320 libusb_free_device_list(dev_list, 1);
323 die("No Nocturn device found");
325 msg(L_DEBUG, "Initializing device");
327 if ((err = libusb_open(found_dev, &usb_dev)) < 0)
328 die("libusb_open failed: error %d", err);
330 // There exist configurations 1 (high brightness) and 2 (power-save)
331 if ((err = libusb_set_configuration(usb_dev, 1)) < 0)
332 die("libusb_set_configuration: error %d", err);
334 if ((err = libusb_claim_interface(usb_dev, 0)) < 0)
335 die("libusb_claim_interface: error %d", err);
337 for (int i=0; i<4; i++)
340 if ((err = libusb_interrupt_transfer(usb_dev, 0x02, (byte *) noct_init[i] + 1, noct_init[i][0], &done, 5000)) < 0)
341 die("Cannot send init packets: error %d", err);
342 if (done != noct_init[i][0])
343 die("Partial send of init packet: %d < %d", done, noct_init[i][0]);
347 byte xxx[] = { 0x7f, 0x01 };
349 libusb_interrupt_transfer(usb_dev, 0x02, xxx, 2, &done, 5000);
352 DBG("USB: Connecting libusb to mainloop");
354 if (!libusb_pollfds_handle_timeouts(usb_ctx))
355 die("Unsupported version of libusb, please fix me");
357 GARY_INIT_ZERO(usb_fds, 0);
358 libusb_set_pollfd_notifiers(usb_ctx, usb_added_fd, usb_removed_fd, NULL);
360 const struct libusb_pollfd **fds = libusb_get_pollfds(usb_ctx);
362 for (int i=0; fds[i]; i++)
363 usb_added_fd(fds[i]->fd, fds[i]->events, NULL);
371 * Interface to PulseAudio
382 static clist pmain_io_list;
388 pa_io_event_flags_t events;
389 pa_io_event_cb_t callback;
390 pa_io_event_destroy_cb_t destroy_callback;
394 static clist pmain_io_gc_list;
396 static pa_io_event *pmain_io_new(pa_mainloop_api *api, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata);
397 static void pmain_io_enable(pa_io_event *e, pa_io_event_flags_t events);
398 static void pmain_io_free(pa_io_event *e);
399 static void pmain_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb);
401 struct pa_time_event {
404 pa_time_event_cb_t callback;
405 pa_time_event_destroy_cb_t destroy_callback;
410 static clist pmain_time_gc_list;
412 static pa_time_event *pmain_time_new(pa_mainloop_api *api, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata);
413 static void pmain_time_restart(pa_time_event *e, const struct timeval *tv);
414 static void pmain_time_free(pa_time_event *e);
415 static void pmain_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb);
417 struct pa_defer_event {
420 pa_defer_event_cb_t callback;
421 pa_defer_event_destroy_cb_t destroy_callback;
425 static clist pmain_defer_gc_list;
427 static pa_defer_event *pmain_defer_new(pa_mainloop_api *api, pa_defer_event_cb_t cb, void *userdata);
428 static void pmain_defer_enable(pa_defer_event *e, int b);
429 static void pmain_defer_free(pa_defer_event *e);
430 static void pmain_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb);
432 static void pmain_quit(pa_mainloop_api *a, int retval);
434 static struct main_hook pmain_gc_hook;
436 static void pmain_trigger_gc(void);
438 static struct pa_mainloop_api pmainloop_api = {
439 .io_new = pmain_io_new,
440 .io_enable = pmain_io_enable,
441 .io_free = pmain_io_free,
442 .io_set_destroy = pmain_io_set_destroy,
444 .time_new = pmain_time_new,
445 .time_restart = pmain_time_restart,
446 .time_free = pmain_time_free,
447 .time_set_destroy = pmain_time_set_destroy,
449 .defer_new = pmain_defer_new,
450 .defer_enable = pmain_defer_enable,
451 .defer_free = pmain_defer_free,
452 .defer_set_destroy = pmain_defer_set_destroy,
457 static struct pmain_io *pmain_get_io(int fd)
459 CLIST_FOR_EACH(struct pmain_io *, io, pmain_io_list)
462 DBG("Pulse: Recycling IO master");
466 struct pmain_io *io = xmalloc(sizeof(*io));
469 clist_add_tail(&pmain_io_list, &io->n);
470 clist_init(&io->io_events);
474 static pa_io_event *pmain_io_new(pa_mainloop_api *api UNUSED, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata)
476 struct pa_io_event *e = xmalloc_zero(sizeof(*e));
477 DBG("Pulse: Creating new IO %p for fd %u", e, fd);
479 e->io = pmain_get_io(fd);
481 e->userdata = userdata;
482 clist_add_head(&e->io->io_events, &e->n); // Do not call the new IO if created from another IO on the same fd
483 pmain_io_enable(e, events);
487 static int pmain_io_read(struct main_file *f)
489 struct pmain_io *io = f->data;
490 DBG("Pulse: fd %d ready for read", io->f.fd);
492 CLIST_FOR_EACH(struct pa_io_event *, e, io->io_events)
493 if (e->events & PA_IO_EVENT_INPUT)
495 DBG("Pulse: Callback on IO %p", e);
496 e->callback(&pmainloop_api, e, io->f.fd, PA_IO_EVENT_INPUT, e->userdata);
499 DBG("Pulse: fd %d read done", io->f.fd);
503 static int pmain_io_write(struct main_file *f)
505 struct pmain_io *io = f->data;
506 DBG("Pulse: fd %d ready for write", io->f.fd);
508 CLIST_FOR_EACH(struct pa_io_event *, e, io->io_events)
509 if (e->events & PA_IO_EVENT_OUTPUT)
511 DBG("Pulse: Callback on IO %p", e);
512 e->callback(&pmainloop_api, e, io->f.fd, PA_IO_EVENT_OUTPUT, e->userdata);
515 DBG("Pulse: fd %d write done", io->f.fd);
519 static void pmain_io_enable(pa_io_event *e, pa_io_event_flags_t events)
521 struct pmain_io *io = e->io;
522 DBG("Pulse: Changing IO event mask for IO %p on fd %d to %02x", e, io->f.fd, events);
525 pa_io_event_flags_t mask = 0;
526 CLIST_FOR_EACH(struct pa_io_event *, f, io->io_events)
528 DBG("Pulse: Recalculated IO mask for fd %d to %02x", io->f.fd, mask);
532 io->f.read_handler = (mask & PA_IO_EVENT_INPUT) ? pmain_io_read : NULL;
533 io->f.write_handler = (mask & PA_IO_EVENT_OUTPUT) ? pmain_io_write : NULL;
534 if (file_is_active(&io->f))
543 static void pmain_io_free(pa_io_event *e)
545 DBG("Pulse: Deleting IO %p for fd %d", e, e->io->f.fd);
546 pmain_io_enable(e, 0);
547 clist_add_tail(&pmain_io_gc_list, &e->gc_n);
551 static void pmain_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb)
553 e->destroy_callback = cb;
556 static void pmain_time_handler(struct main_timer *t)
558 struct pa_time_event *e = t->data;
559 DBG("Pulse: Timer %p triggered", e);
561 e->callback(&pmainloop_api, e, &e->tv, e->userdata);
562 DBG("Pulse: Timer %p done", e);
565 static pa_time_event *pmain_time_new(pa_mainloop_api *api UNUSED, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata)
567 struct pa_time_event *e = xmalloc_zero(sizeof(*e));
568 DBG("Pulse: Creating timer %p", e);
570 e->userdata = userdata;
571 e->t.handler = pmain_time_handler;
573 pmain_time_restart(e, tv);
577 static timestamp_t timeval_to_timestamp(const struct timeval *tv)
579 return 1000 * (timestamp_t) tv->tv_sec + tv->tv_usec / 1000;
582 static void pmain_time_restart(pa_time_event *e, const struct timeval *tv)
585 gettimeofday(&now, NULL);
586 timestamp_t ts_now = timeval_to_timestamp(&now);
587 timestamp_t ts_fire = timeval_to_timestamp(tv);
588 timestamp_t ts_delta = ts_fire - ts_now;
589 DBG("Pulse: Setting timer %p to %+d", e, (int) ts_delta);
592 timer_add_rel(&e->t, ts_delta);
595 static void pmain_time_free(pa_time_event *e)
597 DBG("Pulse: Timer %p deleted", e);
599 clist_add_tail(&pmain_time_gc_list, &e->n);
603 static void pmain_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb)
605 e->destroy_callback = cb;
608 static int pmain_defer_handler(struct main_hook *h)
610 struct pa_defer_event *e = h->data;
611 DBG("Pulse: Deferred event %p triggered", e);
612 e->callback(&pmainloop_api, e, e->userdata);
613 DBG("Pulse: Deferred event done");
614 return hook_is_active(&e->h) ? HOOK_RETRY : HOOK_IDLE;
617 static pa_defer_event *pmain_defer_new(pa_mainloop_api *api UNUSED, pa_defer_event_cb_t cb, void *userdata)
619 struct pa_defer_event *e = xmalloc_zero(sizeof(*e));
620 DBG("Pulse: Creating defer %p", e);
622 e->userdata = userdata;
623 e->h.handler = pmain_defer_handler;
625 pmain_defer_enable(e, 1);
629 static void pmain_defer_enable(pa_defer_event *e, int b)
631 DBG("Pulse: %sabling defer %p", (b ? "En" : "Dis"), e);
638 static void pmain_defer_free(pa_defer_event *e)
640 DBG("Pulse: Deferred event %p deleted", e);
642 clist_add_tail(&pmain_defer_gc_list, &e->n);
646 static void pmain_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb)
648 e->destroy_callback = cb;
651 static void pmain_quit(pa_mainloop_api *a UNUSED, int retval UNUSED)
653 DBG("Pulse: Main loop quit not implemented");
656 static int pmain_gc_handler(struct main_hook *h)
658 DBG("Pulse: Garbage collector");
662 while (n = clist_remove_head(&pmain_io_gc_list))
664 struct pa_io_event *ei = SKIP_BACK(struct pa_io_event, gc_n, n);
665 struct pmain_io *io = ei->io;
666 DBG("Pulse: GC of IO event %p on fd %d", ei, io->f.fd);
667 if (ei->destroy_callback)
668 ei->destroy_callback(&pmainloop_api, ei, ei->userdata);
669 clist_remove(&ei->n);
670 if (clist_empty(&io->io_events))
672 ASSERT(!file_is_active(&io->f));
673 DBG("Pulse: GC of IO master for fd %d", io->f.fd);
674 clist_remove(&io->n);
680 struct pa_time_event *et;
681 while (et = (struct pa_time_event *) clist_remove_head(&pmain_time_gc_list))
683 DBG("Pulse: GC for timer %p", et);
684 if (et->destroy_callback)
685 et->destroy_callback(&pmainloop_api, et, et->userdata);
689 struct pa_defer_event *ed;
690 while (ed = (struct pa_defer_event *) clist_remove_head(&pmain_defer_gc_list))
692 DBG("Pulse: GC for defer %p", ed);
693 if (ed->destroy_callback)
694 ed->destroy_callback(&pmainloop_api, ed, ed->userdata);
698 DBG("Pulse: Garbage collector done");
702 static void pmain_trigger_gc(void)
704 hook_add(&pmain_gc_hook);
707 static pa_context *pulse_ctx;
708 static bool pulse_ready;
710 static void pulse_client_info_cb(pa_context *ctx, const pa_client_info *i, int eol, void *userdata)
714 DBG("Pulse: CLIENT DONE");
718 DBG("Pulse: CLIENT #%u: %s mod=%u drv=%s", i->index, i->name, i->owner_module, i->driver);
721 static void pulse_state_cb(pa_context *ctx, void *userdata UNUSED)
723 int state = pa_context_get_state(ctx);
724 DBG("Pulse: State callback, new state = %d", state);
725 if (state == PA_CONTEXT_READY)
730 DBG("Pulse: ONLINE");
731 pa_context_get_client_info_list(ctx, pulse_client_info_cb, NULL);
732 // FIXME: Discard the operation when server goes offline
740 DBG("Pulse: OFFLINE");
745 static void pulse_init(void)
747 clist_init(&pmain_io_list);
748 clist_init(&pmain_io_gc_list);
749 clist_init(&pmain_time_gc_list);
750 clist_init(&pmain_defer_gc_list);
751 pmain_gc_hook.handler = pmain_gc_handler;
753 pulse_ctx = pa_context_new(&pmainloop_api, "ursaryd");
754 pa_context_set_state_callback(pulse_ctx, pulse_state_cb, NULL);
755 pa_context_connect(pulse_ctx, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
758 int main(int argc UNUSED, char **argv)
763 // msg(L_INFO, "Initializing USB");
766 msg(L_INFO, "Initializing PulseAudio");
769 msg(L_INFO, "Entering main loop");