mirror of https://github.com/nealey/hdjd.git
modularize
This commit is contained in:
parent
a843d39b79
commit
fbc59832be
9
Makefile
9
Makefile
|
@ -1,9 +1,14 @@
|
||||||
|
CFLAGS += -Wall
|
||||||
|
CFLAGS += -Werror
|
||||||
|
|
||||||
all: hdjd aac123
|
all: hdjd aac123
|
||||||
|
|
||||||
hdjd: CFLAGS += $(shell pkg-config --cflags libusb-1.0)
|
|
||||||
hdjd: LDFLAGS += $(shell pkg-config --libs libusb-1.0)
|
hdjd: LDFLAGS += $(shell pkg-config --libs libusb-1.0)
|
||||||
hdjd: CFLAGS += $(shell pkg-config --cflags alsa)
|
|
||||||
hdjd: LDFLAGS += $(shell pkg-config --libs alsa)
|
hdjd: LDFLAGS += $(shell pkg-config --libs alsa)
|
||||||
|
hdjd: hdjd.o usb.o alsa.o
|
||||||
|
|
||||||
|
alsa.o: CFLAGS += $(shell pkg-config --cflags alsa)
|
||||||
|
usb.o: CFLAGS += $(shell pkg-config --cflags libusb-1.0)
|
||||||
|
|
||||||
aac123: CFLAGS += $(shell pkg-config --cflags alsa)
|
aac123: CFLAGS += $(shell pkg-config --cflags alsa)
|
||||||
aac123: LDLIBS += $(shell pkg-config --libs alsa)
|
aac123: LDLIBS += $(shell pkg-config --libs alsa)
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <alsa/asoundlib.h>
|
||||||
|
#include "dump.h"
|
||||||
|
|
||||||
|
static snd_seq_t *snd_handle;
|
||||||
|
static int seq_port;
|
||||||
|
static snd_midi_event_t *midi_event_parser;
|
||||||
|
|
||||||
|
int
|
||||||
|
alsa_setup(const char *name)
|
||||||
|
{
|
||||||
|
if (snd_seq_open(&snd_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
|
||||||
|
perror("snd_seq_open");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
snd_seq_nonblock(snd_handle, 1);
|
||||||
|
snd_seq_set_client_name(snd_handle, name);
|
||||||
|
seq_port =
|
||||||
|
snd_seq_create_simple_port(snd_handle, name,
|
||||||
|
SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_READ |
|
||||||
|
SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC);
|
||||||
|
|
||||||
|
if (snd_seq_event_input(handle, &ev) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd_midi_event_new(256, &midi_event_parser) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_PFDS 20
|
||||||
|
int npfd;
|
||||||
|
struct pollfd pfd[MAX_PFDS];
|
||||||
|
|
||||||
|
void
|
||||||
|
alsa_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds)
|
||||||
|
{
|
||||||
|
npfd = snd_seq_poll_descriptors_count(snd_handle, POLLIN);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (npfd > MAX_PFDS) {
|
||||||
|
fprintf(stderr, "ALSA wants too many file descriptors\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_seq_poll_descriptors(snd_handle, pfd, npfd, POLLIN);
|
||||||
|
for (i = 0; i < npfd; i += 1) {
|
||||||
|
if (pfd[i].fd > *nfds) {
|
||||||
|
*nfds = pfd[i].fd;
|
||||||
|
}
|
||||||
|
if (pfd[i].events & POLLIN) {
|
||||||
|
FD_SET(pfd[i].fd, rfds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
alsa_read_ready()
|
||||||
|
{
|
||||||
|
snd_seq_event_t *ev;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
char buf[256];
|
||||||
|
long converted;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (snd_seq_event_input(handle, &ev) < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!midi_event_parser) {
|
||||||
|
if (snd_midi_event_new(256, &midi_event_parser) < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
converted = snd_midi_event_decode(midi_event_parser, buf, 256, ev);
|
||||||
|
printf(" << ");
|
||||||
|
for (i = 0; i < converted; i += 1) {
|
||||||
|
printf("%02x ", buf[i]);
|
||||||
|
}
|
||||||
|
printf(":\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
alsa_check_fds(fd_set *rfds, fd_set *wfds)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < npfd; i += 1) {
|
||||||
|
int fd = pfds[i]->fd;
|
||||||
|
|
||||||
|
if (FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds)) {
|
||||||
|
alsa_read_ready();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef _ALSA_H_
|
||||||
|
#define _ALSA_H_
|
||||||
|
|
||||||
|
#include <sys/select.h>
|
||||||
|
|
||||||
|
int alsa_setup(const char *name);
|
||||||
|
void alsa_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds);
|
||||||
|
void alsa_read_ready();
|
||||||
|
|
||||||
|
#endif
|
254
hdjd.c
254
hdjd.c
|
@ -1,262 +1,52 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <libusb.h>
|
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <alsa/asoundlib.h>
|
#include "alsa.h"
|
||||||
|
#include "usb.h"
|
||||||
#include "dump.h"
|
#include "dump.h"
|
||||||
|
|
||||||
/*
|
int
|
||||||
* Some things I use for debugging
|
setup()
|
||||||
*/
|
|
||||||
#ifdef NODUMP
|
|
||||||
#define DUMPf(fmt, args...)
|
|
||||||
#else
|
|
||||||
#define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args)
|
|
||||||
#endif
|
|
||||||
#define DUMP() DUMPf("")
|
|
||||||
#define DUMP_d(v) DUMPf("%s = %d", #v, v)
|
|
||||||
#define DUMP_x(v) DUMPf("%s = 0x%x", #v, v)
|
|
||||||
#define DUMP_s(v) DUMPf("%s = %s", #v, v)
|
|
||||||
#define DUMP_c(v) DUMPf("%s = '%c' (0x%02x)", #v, v, v)
|
|
||||||
#define DUMP_p(v) DUMPf("%s = %p", #v, v)
|
|
||||||
|
|
||||||
struct device {
|
|
||||||
uint16_t product_id;
|
|
||||||
uint8_t ep_in;
|
|
||||||
uint8_t ep_out;
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct device devices[] = {
|
|
||||||
{ 0xb102, 0x83, 0x04 }, // Steel
|
|
||||||
{ 0xb105, 0x82, 0x03 }, // MP3e2
|
|
||||||
{ 0, 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle to ALSA sequencer
|
|
||||||
static snd_seq_t *handle;
|
|
||||||
|
|
||||||
// Descriptor of our fake handle
|
|
||||||
int seq_port;
|
|
||||||
|
|
||||||
void
|
|
||||||
midi_send(uint8_t *data, size_t datalen)
|
|
||||||
{
|
{
|
||||||
snd_seq_event_t ev;
|
char name[100];
|
||||||
snd_midi_event_t *midi_event_parser;
|
|
||||||
|
|
||||||
snd_midi_event_new(datalen, &midi_event_parser);
|
if (usb_setup(name, sizeof(name)) < 0) {
|
||||||
|
return -1;
|
||||||
snd_midi_event_encode(midi_event_parser, data, datalen, &ev);
|
|
||||||
snd_seq_ev_set_direct(&ev);
|
|
||||||
snd_seq_ev_set_source(&ev, seq_port);
|
|
||||||
snd_seq_ev_set_subs(&ev);
|
|
||||||
snd_seq_event_output(handle, &ev);
|
|
||||||
snd_seq_drain_output(handle);
|
|
||||||
|
|
||||||
snd_midi_event_free(midi_event_parser);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
if (alsa_setup(name) < 0) {
|
||||||
usb_xfer_done(struct libusb_transfer *transfer)
|
return -1;
|
||||||
{
|
|
||||||
uint8_t *data = transfer->buffer;
|
|
||||||
int datalen = transfer->actual_length;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < datalen; i += 1) {
|
|
||||||
printf("%02x ", data[i]);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
midi_send(data, datalen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
return 0;
|
||||||
handle_alsa()
|
|
||||||
{
|
|
||||||
static snd_midi_event_t *midi_event_parser = NULL;
|
|
||||||
snd_seq_event_t *ev;
|
|
||||||
int ret = 1;
|
|
||||||
|
|
||||||
DUMP();
|
|
||||||
for (;;) {
|
|
||||||
char buf[256];
|
|
||||||
long converted;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (snd_seq_event_input(handle, &ev) < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (! midi_event_parser) {
|
|
||||||
if (snd_midi_event_new(256, &midi_event_parser) < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
converted = snd_midi_event_decode(midi_event_parser, buf, 256, ev);
|
|
||||||
printf(" << ");
|
|
||||||
for (i = 0; i < converted; i += 1) {
|
|
||||||
printf("%02x ", buf[i]);
|
|
||||||
}
|
|
||||||
printf(":\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct libusb_device_handle *dev;
|
if (setup() < 0) {
|
||||||
struct libusb_device_descriptor ddesc;
|
|
||||||
char name[100];
|
|
||||||
const struct device *d;
|
|
||||||
nfds_t nfds = 0;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (libusb_init(NULL) < 0) {
|
|
||||||
return 69;
|
return 69;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (d = devices; d->product_id; d += 1) {
|
for (;;) {
|
||||||
dev = libusb_open_device_with_vid_pid(NULL, 0x6f8, d->product_id);
|
fd_set rfds;
|
||||||
if (dev) {
|
fd_set wfds;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!dev) {
|
|
||||||
printf("Couldn't find a controller\n");
|
|
||||||
return 69;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out what this thing is called
|
|
||||||
libusb_get_device_descriptor(libusb_get_device(dev), &ddesc);
|
|
||||||
{
|
|
||||||
char *p = name;
|
|
||||||
|
|
||||||
ret = libusb_get_string_descriptor_ascii(dev, ddesc.iManufacturer, name, sizeof(name));
|
|
||||||
if (ret > 0) {
|
|
||||||
p = name + ret;
|
|
||||||
*p = ' ';
|
|
||||||
p += 1;
|
|
||||||
ret = libusb_get_string_descriptor_ascii(dev, ddesc.iProduct, p, sizeof(name) - ret - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("Can't figure out what to call this thing.\n");
|
|
||||||
return 69;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("Opened a %s\n", name);
|
|
||||||
|
|
||||||
// Initialize ALSA
|
|
||||||
if (snd_seq_open(&handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
|
|
||||||
perror("snd_seq_open");
|
|
||||||
return(69);
|
|
||||||
}
|
|
||||||
snd_seq_nonblock(handle, 1);
|
|
||||||
snd_seq_set_client_name(handle, name);
|
|
||||||
seq_port = snd_seq_create_simple_port(handle, name,
|
|
||||||
SND_SEQ_PORT_CAP_READ |
|
|
||||||
SND_SEQ_PORT_CAP_WRITE |
|
|
||||||
SND_SEQ_PORT_CAP_SUBS_READ |
|
|
||||||
SND_SEQ_PORT_CAP_SUBS_WRITE,
|
|
||||||
SND_SEQ_PORT_TYPE_MIDI_GENERIC);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
struct libusb_transfer *xfer = libusb_alloc_transfer(0);
|
|
||||||
uint8_t data[80];
|
|
||||||
int transferred;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if ((ret = libusb_bulk_transfer(dev, d->ep_in, data, sizeof data, &transferred, 0))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up transfer
|
|
||||||
libusb_fill_bulk_transfer(xfer, dev, d->ep_in, data, sizeof data, usb_xfer_done, NULL, 0);
|
|
||||||
libusb_submit_transfer(xfer);
|
|
||||||
|
|
||||||
// Select on our file descriptors
|
|
||||||
{
|
|
||||||
const struct libusb_pollfd **usb_fds = libusb_get_pollfds(NULL);
|
|
||||||
struct pollfd *pfd;
|
|
||||||
int npfd;
|
|
||||||
struct timeval tv;
|
|
||||||
struct timeval *timeout;
|
|
||||||
fd_set rfds, wfds;
|
|
||||||
int nfds = 0;
|
int nfds = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_ZERO(&wfds);
|
FD_ZERO(&wfds);
|
||||||
|
|
||||||
// ALSA shit
|
alsa_fd_setup(&nfds, &rfds, &wfds);
|
||||||
{
|
usb_fd_setup(&nfds, &rfds, &wfds);
|
||||||
|
|
||||||
npfd = snd_seq_poll_descriptors_count(handle, POLLIN);
|
ret = select(nfds + 1, &rfds, &wfds, NULL, NULL);
|
||||||
pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
|
if (-1 == ret) {
|
||||||
snd_seq_poll_descriptors(handle, pfd, npfd, POLLIN);
|
DUMP();
|
||||||
|
|
||||||
for (i = 0; i < npfd; i += 1) {
|
|
||||||
if (pfd[i].fd > nfds) {
|
|
||||||
nfds = pfd[i].fd;
|
|
||||||
}
|
|
||||||
if (pfd[i].events & POLLIN) {
|
|
||||||
FD_SET(pfd[i].fd, &rfds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// USB shit
|
DUMP();
|
||||||
{
|
|
||||||
|
|
||||||
ret = libusb_get_next_timeout(NULL, &tv);
|
|
||||||
if (0 == ret) {
|
|
||||||
timeout = NULL;
|
|
||||||
} else {
|
|
||||||
timeout = &tv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; usb_fds[i]; i += 1) {
|
|
||||||
const struct libusb_pollfd *ufd = usb_fds[i];
|
|
||||||
|
|
||||||
if (ufd->fd > nfds) {
|
|
||||||
nfds = ufd->fd;
|
|
||||||
}
|
|
||||||
if (ufd->events & POLLIN) {
|
|
||||||
FD_SET(ufd->fd, &rfds);
|
|
||||||
}
|
|
||||||
if (ufd->events & POLLOUT) {
|
|
||||||
FD_SET(ufd->fd, &wfds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = select(nfds + 1, &rfds, &wfds, NULL, timeout);
|
|
||||||
DUMP_d(rfds);
|
|
||||||
|
|
||||||
for (i = 0; usb_fds[i]; i += 1) {
|
|
||||||
int fd = usb_fds[i]->fd;
|
|
||||||
|
|
||||||
if (FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds)) {
|
|
||||||
libusb_handle_events(NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < npfd; i += 1) {
|
|
||||||
int fd = pfd[i].fd;
|
|
||||||
|
|
||||||
if (FD_ISSET(fd, &rfds)) {
|
|
||||||
handle_alsa();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_free_transfer(xfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("ERROR: %s\n", libusb_error_name(ret));
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_exit(NULL);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
#include <libusb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include "dump.h"
|
||||||
|
|
||||||
|
static struct libusb_device_handle *usb_dev;
|
||||||
|
static struct libusb_transfer *xfer;
|
||||||
|
static const struct device *d;
|
||||||
|
uint8_t data[80];
|
||||||
|
|
||||||
|
struct device {
|
||||||
|
uint16_t product_id;
|
||||||
|
uint8_t ep_in;
|
||||||
|
uint8_t ep_out;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct device devices[] = {
|
||||||
|
{ 0xb102, 0x83, 0x04 }, // Steel
|
||||||
|
{ 0xb105, 0x82, 0x03 }, // MP3e2
|
||||||
|
{ 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
void usb_xfer_done(struct libusb_transfer *transfer);
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_initiate_transfer()
|
||||||
|
{
|
||||||
|
// Tell libusb we want to know about bulk transfers
|
||||||
|
libusb_fill_bulk_transfer(xfer, usb_dev, d->ep_in, data, sizeof(data), usb_xfer_done, NULL, 0);
|
||||||
|
libusb_submit_transfer(xfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_xfer_done(struct libusb_transfer *transfer)
|
||||||
|
{
|
||||||
|
uint8_t *data = transfer->buffer;
|
||||||
|
int datalen = transfer->actual_length;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < datalen; i += 1) {
|
||||||
|
printf("%02x ", data[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
usb_initiate_transfer();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
usb_setup(char *name, size_t namelen)
|
||||||
|
{
|
||||||
|
if (libusb_init(NULL) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (d = devices; d->product_id; d += 1) {
|
||||||
|
usb_dev = libusb_open_device_with_vid_pid(NULL, 0x6f8, d->product_id);
|
||||||
|
if (usb_dev) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! usb_dev) {
|
||||||
|
printf("Couldn't find a controller.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out what it's called
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct libusb_device_descriptor ddesc;
|
||||||
|
char *p = name;
|
||||||
|
|
||||||
|
libusb_get_device_descriptor(libusb_get_device(usb_dev), &ddesc);
|
||||||
|
ret = libusb_get_string_descriptor_ascii(usb_dev, ddesc.iManufacturer, (unsigned char *)name, namelen);
|
||||||
|
if (ret > 0) {
|
||||||
|
p = name + ret;
|
||||||
|
*p = ' ';
|
||||||
|
p += 1;
|
||||||
|
ret = libusb_get_string_descriptor_ascii(usb_dev, ddesc.iProduct, (unsigned char *)p, namelen - ret - 1);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
printf("Warning: I can't figure out what to call this thing.\n");
|
||||||
|
}
|
||||||
|
printf("Opened a %s\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
xfer = libusb_alloc_transfer(0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds)
|
||||||
|
{
|
||||||
|
const struct libusb_pollfd **usb_fds = libusb_get_pollfds(NULL);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; usb_fds[i]; i += 1) {
|
||||||
|
const struct libusb_pollfd *ufd = usb_fds[i];
|
||||||
|
|
||||||
|
if (ufd->fd > *nfds) {
|
||||||
|
*nfds = ufd->fd;
|
||||||
|
}
|
||||||
|
if (ufd->events & POLLIN) {
|
||||||
|
FD_SET(ufd->fd, rfds);
|
||||||
|
}
|
||||||
|
if (ufd->events & POLLOUT) {
|
||||||
|
FD_SET(ufd->fd, wfds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
usb_initiate_transfer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_read_ready()
|
||||||
|
{
|
||||||
|
libusb_handle_events(NULL);
|
||||||
|
}
|
Loading…
Reference in New Issue