hdjd/usb.c

181 lines
3.7 KiB
C
Raw Normal View History

2013-05-27 22:11:48 -06:00
#include <libusb.h>
#include <stdio.h>
#include <poll.h>
#include <stdint.h>
#include <string.h>
2013-05-27 22:11:48 -06:00
#include <sys/select.h>
#include "usb.h"
2013-09-08 17:45:44 -06:00
#include "alsa.h"
2014-12-14 20:29:21 -07:00
#include "log.h"
2013-05-27 22:11:48 -06:00
#include "dump.h"
static struct libusb_device_handle *usb_dev;
static const struct device *d;
2013-09-15 21:42:33 -06:00
static int writes_pending = 0;
static int reads_pending = 0;
2013-05-27 22:11:48 -06:00
struct device {
uint16_t product_id;
2014-12-14 20:29:21 -07:00
uint8_t interface_number;
2013-05-27 22:11:48 -06:00
uint8_t ep_in;
uint8_t ep_out;
};
const struct device devices[] = {
2014-12-14 20:29:21 -07:00
{ 0xb102, 1, 0x83, 0x04 }, // Steel
{ 0xb105, 1, 0x82, 0x03 }, // MP3e2
{ 0xb109, 0, 0x84, 0x01 }, // 4-MX
2014-12-14 20:29:21 -07:00
{ 0, 0, 0, 0 }
2013-05-27 22:11:48 -06:00
};
void usb_xfer_done(struct libusb_transfer *transfer);
static void
usb_initiate_transfer()
{
unsigned char *buf;
buf = (unsigned char *)malloc(256);
2013-05-27 22:11:48 -06:00
// Tell libusb we want to know about bulk transfers
struct libusb_transfer *xfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(xfer, usb_dev, d->ep_in, buf, 256, usb_xfer_done, NULL, 0);
2013-05-27 22:11:48 -06:00
libusb_submit_transfer(xfer);
2013-09-15 21:42:33 -06:00
reads_pending += 1;
2013-05-27 22:11:48 -06:00
}
void
usb_xfer_done(struct libusb_transfer *xfer)
2013-05-27 22:11:48 -06:00
{
uint8_t *data = xfer->buffer;
int datalen = xfer->actual_length;
2013-09-15 21:42:33 -06:00
reads_pending -= 1;
2013-05-27 22:11:48 -06:00
2013-09-08 17:45:44 -06:00
alsa_write(data, datalen);
free(data);
libusb_free_transfer(xfer);
usb_initiate_transfer();
2013-05-27 22:11:48 -06:00
}
int
2013-09-08 17:45:44 -06:00
usb_setup(char *name, size_t namelen)
2013-05-27 22:11:48 -06:00
{
if (libusb_init(NULL) < 0) {
2013-09-15 21:42:33 -06:00
return -1;
2013-05-27 22:11:48 -06:00
}
if (libusb_pollfds_handle_timeouts(NULL) == 0) {
2014-12-14 20:29:21 -07:00
fatal("I'm too dumb to handle events on such an old system.");
return -1;
}
2013-05-27 22:11:48 -06:00
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) {
2014-12-14 20:29:21 -07:00
fatal("Couldn't find a controller.");
2013-05-27 22:11:48 -06:00
}
// Figure out what it's called
{
int ret;
struct libusb_device_descriptor ddesc;
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) {
2013-09-08 17:45:44 -06:00
char *p = name + ret;
2013-05-27 22:11:48 -06:00
*p = ' ';
p += 1;
ret = libusb_get_string_descriptor_ascii(usb_dev, ddesc.iProduct, (unsigned char *)p, namelen - ret - 1);
}
if (ret < 0) {
2014-12-14 20:29:21 -07:00
warn("I can't figure out what to call this thing.");
2013-05-27 22:11:48 -06:00
}
2013-09-08 17:45:44 -06:00
printf("Opened [%s]\n", name);
2013-05-27 22:11:48 -06:00
}
2014-12-14 20:29:21 -07:00
if (0 != libusb_claim_interface(usb_dev, d->interface_number)) {
fatal("Couldn't claim interface %d", d->interface_number);
}
2013-05-27 22:11:48 -06:00
2013-09-15 21:42:33 -06:00
usb_initiate_transfer();
2013-05-27 22:11:48 -06:00
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);
}
}
2013-09-15 21:42:33 -06:00
if (reads_pending + writes_pending > 10) {
2014-12-14 20:29:21 -07:00
warn("%d(r)+%d(w) = %d outstanding USB transactions!", reads_pending, writes_pending, reads_pending + writes_pending);
2013-09-15 21:42:33 -06:00
}
2013-05-27 22:11:48 -06:00
}
void
usb_check_fds(fd_set *rfds, fd_set *wfds)
2013-05-27 22:11:48 -06:00
{
const struct libusb_pollfd **usb_fds = libusb_get_pollfds(NULL);
int i;
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);
return;
}
}
2013-05-27 22:11:48 -06:00
}
2013-09-08 17:45:44 -06:00
2013-09-08 19:06:25 -06:00
void
usb_write_done(struct libusb_transfer *xfer)
2013-09-08 19:06:25 -06:00
{
2014-12-14 21:26:01 -07:00
if (xfer->status) {
warn("USB Write status %d", xfer->status);
}
2013-09-15 21:42:33 -06:00
writes_pending -= 1;
free(xfer->buffer);
libusb_free_transfer(xfer);
2013-09-08 19:06:25 -06:00
}
2013-09-08 17:45:44 -06:00
void
usb_write(uint8_t *data, size_t datalen)
{
2013-09-08 19:06:25 -06:00
struct libusb_transfer *xfer;
unsigned char *buf;
2014-12-14 21:26:01 -07:00
2013-09-15 21:42:33 -06:00
writes_pending += 1;
2013-09-08 19:06:25 -06:00
xfer = libusb_alloc_transfer(0);
buf = (unsigned char *)malloc(datalen);
memcpy(buf, data, datalen);
libusb_fill_bulk_transfer(xfer, usb_dev, d->ep_out, buf, datalen, usb_write_done, NULL, 0);
2013-09-08 19:06:25 -06:00
libusb_submit_transfer(xfer);
}