hdjd

Hercules DJ controller driver for Linux
git clone https://git.woozle.org/neale/hdjd.git

Neale Pickett  ·  2024-02-24

usb.c

  1#include <libusb.h>
  2#include <stdio.h>
  3#include <poll.h>
  4#include <stdint.h>
  5#include <string.h>
  6#include <sys/select.h>
  7#include "usb.h"
  8#include "alsa.h"
  9#include "log.h"
 10#include "dump.h"
 11
 12#define MAX_PFDS 20
 13
 14struct device {
 15  uint16_t product_id;
 16  uint8_t interface_number;
 17  uint8_t ep_in;
 18  uint8_t ep_out;
 19  uint8_t ep_in2;
 20  uint8_t interface_number2;
 21};
 22const struct device devices[] = {
 23  { 0xb102, 1, 0x83, 0x04, 0x0, 0 }, // Steel
 24  { 0xb105, 1, 0x81, 0x03, 0x0, 0 }, // MP3e2
 25  { 0xb120, 1, 0x82, 0x03, 0x0, 0 }, // Hercules MP3 LE / Glow
 26  { 0xb107, 5, 0x83, 0x03, 0x0, 0 }, // Hercules Mk4
 27  { 0xb100, 1, 0x86, 0x06, 0x0, 0 }, // Hercules Mk2
 28  { 0xb109, 5, 0x83, 0x03, 0x84, 0}, // 4-Mx
 29  { 0xb10c, 5, 0x83, 0x03, 0x84, 0}, // Hercules DJ 4Set
 30  { 0xb10d, 5, 0x83, 0x03, 0x84, 0}, // Hercules DJ 4Set, second variant(?)
 31  { 0, 0, 0, 0 }
 32};
 33
 34static const int MANUFACTURER_HERCULES = 0x6f8;
 35static libusb_context *context = NULL;
 36static struct libusb_device_handle *usb_dev = NULL;
 37static const struct device *dev_info;
 38const struct libusb_pollfd **usb_fds = NULL;
 39struct libusb_transfer *xfer_in;
 40struct libusb_transfer *xfer_in2;
 41
 42static int writes_pending = 0;
 43static int reads_pending = 0;
 44
 45void
 46usb_debug_msg(char *action, int ep, uint8_t data[], size_t datalen)
 47{
 48#ifdef DEBUG
 49  fprintf(stderr, "%s on ep%02x:", action, ep);
 50  for (int i = 0; i < datalen; i += 1) {
 51    fprintf(stderr, " %02x", data[i]);
 52  }
 53  fprintf(stderr, "\n");
 54#endif
 55}
 56
 57void usb_xfer_done(struct libusb_transfer *xfer);
 58void usb_xfer_done_additional(struct libusb_transfer *xfer);
 59
 60void 
 61usb_interrupting()
 62{
 63  libusb_cancel_transfer(xfer_in);
 64  if (dev_info->ep_in2 != 0x0) {
 65    libusb_cancel_transfer(xfer_in2);
 66  }
 67}
 68static void
 69usb_initiate_transfer()
 70{
 71  static const int buffsize = 256;
 72  unsigned char *buf;
 73	
 74  buf = (unsigned char *)malloc(buffsize);
 75	
 76  // Tell libusb we want to know about bulk transfers
 77  xfer_in = libusb_alloc_transfer(0);
 78  //timeout if in 1000 milliseconds it hasn't been sent
 79  xfer_in->timeout=1000;
 80  xfer_in->flags |=LIBUSB_TRANSFER_ADD_ZERO_PACKET;
 81  libusb_fill_bulk_transfer(xfer_in, usb_dev, dev_info->ep_in, buf, buffsize, usb_xfer_done, NULL, 0);
 82  libusb_submit_transfer(xfer_in);
 83  reads_pending += 1;
 84}
 85
 86static void
 87usb_initiate_transfer_additional()
 88{
 89  static const int buffsize = 256;
 90  unsigned char *buf;
 91	
 92  buf = (unsigned char *)malloc(buffsize);
 93	
 94  // Tell libusb we want to know about bulk transfers
 95  xfer_in2 = libusb_alloc_transfer(0);
 96  //timeout if in 1000 milliseconds it hasn't been sent
 97  xfer_in2->timeout=1000;
 98  xfer_in2->flags |=LIBUSB_TRANSFER_ADD_ZERO_PACKET;
 99  libusb_fill_bulk_transfer(xfer_in2, usb_dev, dev_info->ep_in2, buf, buffsize, usb_xfer_done_additional, NULL, 0);
100  libusb_submit_transfer(xfer_in2);
101}
102
103void LIBUSB_CALL
104usb_xfer_done(struct libusb_transfer *xfer)
105{
106  uint8_t *data = xfer->buffer;
107  int datalen = xfer->actual_length;
108  reads_pending -= 1;
109  if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
110    usb_debug_msg("Receiving", dev_info->ep_in, data, datalen);
111    alsa_write(data, datalen);
112  }
113  if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
114    usb_initiate_transfer();
115  } else if ( xfer->status != LIBUSB_TRANSFER_CANCELLED ) {
116    fatal("Stopping EP_IN, because of status %d.\nSoftware needs restarting", xfer->status);
117  }
118
119  free(data);
120  libusb_free_transfer(xfer);
121}
122void LIBUSB_CALL
123usb_xfer_done_additional(struct libusb_transfer *xfer)
124{
125  if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
126    // We don't need to use the information of this call, but it is needed that we
127    // poll this, or else it hangs and doesn't receive more data.
128    usb_debug_msg("Receiving", dev_info->ep_in2, xfer->buffer, xfer->actual_length);
129  }
130
131  if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
132    usb_initiate_transfer_additional();
133  } else if ( xfer->status != LIBUSB_TRANSFER_CANCELLED ) {
134    fatal("Stopping EP_IN2, because of status %d\nSoftware needs restarting", xfer->status);
135  }
136
137  free(xfer->buffer);
138  libusb_free_transfer(xfer);
139}
140
141int
142usb_setup(char *name, size_t namelen)
143{
144  int ret;
145  ret=libusb_init(&context);
146  if (ret < 0) {
147    fatal("ERROR: %s\n%s", libusb_error_name(ret), libusb_strerror(ret));
148    return -1; 
149  }
150  //----------------------------------------------------------------------------
151  // Enable debug
152  //----------------------------------------------------------------------------
153#ifdef DEBUG
154  libusb_set_debug(context, LIBUSB_LOG_LEVEL_WARNING); 
155#endif
156
157  if (libusb_pollfds_handle_timeouts(context) == 0) {
158    fatal("I'm too dumb to handle events on such an old system.");
159    return -1;
160  }
161  //----------------------------------------------------------------------------
162  // Get device list
163  //----------------------------------------------------------------------------
164  struct libusb_device_descriptor founddesc = {0};
165  {
166    libusb_device        **devs;
167    ssize_t              count; //holding number of devices in list
168    printf("Locating Hercules USB devices...\n(You can also use the lsusb command to locate this information)\n");
169    count = libusb_get_device_list(context, &devs);
170    if ( count < 0) {
171      fatal("Error getting the device list: %s\n%s", libusb_error_name(count), libusb_strerror(count));
172      return -1;
173    } else if (count == 0) {
174      warn("Seems that the USB device list is empty. Is the controller connected? ");
175    }
176    size_t idx;
177    for (idx = 0; idx < count; idx+=1) {
178      libusb_device *device = devs[idx];
179      struct libusb_device_descriptor listdesc = {0};
180
181      ret = libusb_get_device_descriptor(device, &listdesc);
182      if ( ret  != 0) {
183	warn("Could not get descriptor for device index %ld: %s\n%s", 
184	     (long int)idx, libusb_error_name(count), libusb_strerror(count));
185      } else if (listdesc.idVendor == MANUFACTURER_HERCULES) {
186	printf("Vendor:Device = %04x:%04x\n", listdesc.idVendor, listdesc.idProduct);
187	founddesc = listdesc;
188      }
189    }
190
191    libusb_free_device_list(devs, 1); //free the list, unref the devices in it
192    //----------------------------------------------------------------------------
193  }
194  for (dev_info = devices; dev_info->product_id; dev_info += 1) {
195    usb_dev = libusb_open_device_with_vid_pid(context, MANUFACTURER_HERCULES, dev_info->product_id);
196    if (usb_dev) {
197      break;
198    } else if (dev_info->product_id == founddesc.idProduct) {
199      fatal("The controller %04x:%04x could not be opened.\n"
200            "Check that you have enough permissions over /dev/bus/usb/ subfolder elements.\n."
201            "You might need to create an udev rule at /etc/udev/rules.d/", founddesc.idVendor,founddesc.idProduct);
202    }
203  }
204  if (! usb_dev) {
205    if (founddesc.idVendor != MANUFACTURER_HERCULES) {
206      fatal("Couldn't find a Hercules controller.");
207    }
208    else {
209      fatal("The controller %04x:%04x is not supported.", founddesc.idVendor,founddesc.idProduct);
210    }
211    return -1;
212  }
213	
214  // Figure out what it's called
215  {
216    struct libusb_device_descriptor ddesc;
217    name[0]='\0';
218    libusb_get_device_descriptor(libusb_get_device(usb_dev), &ddesc);
219    ret = libusb_get_string_descriptor_ascii(usb_dev, ddesc.iManufacturer, (unsigned char *)name, namelen);
220    if (ret > 0) {
221      char *p = name + ret;
222			
223      *p = ' ';
224      p += 1;
225      ret = libusb_get_string_descriptor_ascii(usb_dev, ddesc.iProduct, (unsigned char *)p, namelen - ret - 1);
226    }
227    if (ret < 0) {
228      warn("I can't figure out what to call this thing.");
229    }
230    printf("Opened [%s]\n", name);
231  }
232
233  ret = libusb_claim_interface(usb_dev, dev_info->interface_number);
234  if (ret == 0 ) {
235    if (dev_info->ep_in2 != 0x0) {
236      libusb_claim_interface(usb_dev, dev_info->interface_number2);
237      usb_initiate_transfer_additional();
238    }
239    usb_initiate_transfer();
240    return 0;
241  } else {
242    if (ret == LIBUSB_ERROR_BUSY) {
243      fatal("Couldn't claim interface %d. Already in use?", dev_info->interface_number);
244    } else {
245      fatal("Couldn't claim interface %d. %s\n%s", dev_info->interface_number,
246	    libusb_error_name(ret), libusb_strerror(ret));
247    }
248    return -1;
249  }
250}
251
252void
253usb_finish() {
254  int ret;
255  if (usb_dev) {
256    ret = libusb_release_interface(usb_dev, dev_info->interface_number);
257    if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND) {
258      warn("Couldn't release interface %d. %s\n%s", dev_info->interface_number,
259	   libusb_error_name(ret), libusb_strerror(ret));
260    }
261    libusb_close(usb_dev);
262    usb_dev=NULL;
263  }
264  libusb_exit(context);
265}
266
267void
268usb_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds)
269{
270  usb_fds = libusb_get_pollfds(context);
271  if (usb_fds == NULL) {
272    warn("could not get the filedescriptors! This is unexpected");
273  }
274
275  int i;
276  for (i = 0; usb_fds[i]; i += 1) {
277    const struct libusb_pollfd *ufd = usb_fds[i];
278		
279    if (ufd->fd > *nfds) {
280      *nfds = ufd->fd;
281    }
282    if (ufd->events & POLLIN) {
283      FD_SET(ufd->fd, rfds);
284    }
285    if (ufd->events & POLLOUT) {
286      FD_SET(ufd->fd, wfds);
287    }
288  }
289 
290  if (reads_pending + writes_pending > 100) {
291    warn("%d(r)+%d(w) = %d outstanding USB transactions!", reads_pending, writes_pending, reads_pending + writes_pending);
292  }
293}
294
295void 
296usb_check_fds(fd_set *rfds, fd_set *wfds)
297{
298  if (usb_fds == NULL) {
299    return;
300  }
301
302  int i;
303  for (i = 0; usb_fds[i]; i += 1) {
304    int fd = usb_fds[i]->fd;
305
306    if (FD_ISSET(fd, rfds) || FD_ISSET(fd, wfds)) {
307      libusb_handle_events(context);
308      return;
309    }
310  }
311 
312#if LIBUSB_API_VERSION >= 0x01000104
313  libusb_free_pollfds(usb_fds);
314  usb_fds = NULL;
315#endif // LIBUSB_API_VERSION >= 0x01000104
316}
317
318
319void LIBUSB_CALL
320usb_write_done(struct libusb_transfer *xfer)
321{
322  if ( xfer->status == LIBUSB_TRANSFER_TIMED_OUT ) {
323    warn("Send timed out");
324  } else if ( xfer->status && xfer->status != LIBUSB_TRANSFER_CANCELLED) {
325    warn("USB Write status %d", xfer->status);
326  }
327  writes_pending -= 1;
328  usb_debug_msg("Sent", dev_info->ep_out, xfer->buffer, xfer->actual_length);
329  free(xfer->buffer);
330  libusb_free_transfer(xfer);
331}
332
333void
334usb_write(uint8_t *data, size_t datalen)
335{
336  struct libusb_transfer *xfer;
337  unsigned char *buf;
338
339  writes_pending += 1;
340  xfer = libusb_alloc_transfer(0);
341  //timeout if in 1000 milliseconds it hasn't been sent
342  xfer->timeout=1000;
343  buf = (unsigned char *)malloc(datalen);
344  memcpy(buf, data, datalen);
345  libusb_fill_bulk_transfer(xfer, usb_dev, dev_info->ep_out, buf, datalen, usb_write_done, NULL, 0);
346  libusb_submit_transfer(xfer);
347
348  usb_debug_msg("Preparing to send", dev_info->ep_out, data, datalen);
349}