2 #include <aura/private.h>
3 #include <aura/usb_helpers.h>
6 struct usb_interrupt_packet {
10 #define usbdev_is_be(pck) (pck->flags & (1<<0))
12 struct usb_info_packet {
18 struct usb_event_packet {
29 AUSB_DEVICE_SEARCHING,
32 AUSB_DEVICE_OPERATIONAL,
55 struct aura_node *node;
57 struct aura_export_table *etbl;
65 struct libusb_context *ctx;
66 libusb_device_handle *handle;
69 unsigned char *ctrlbuf;
70 struct libusb_transfer* ctransfer;
73 bool itransfer_enabled;
74 struct libusb_transfer* itransfer;
75 unsigned char ibuffer[8];
78 struct ncusb_devwatch_data dev_descr;
90 #define failing(inf) (inf->state == AUSB_DEVICE_FAILING)
92 static void usb_panic_and_reset_state(
struct aura_node *node)
96 slog(4, SLOG_DEBUG,
"usb: pending transfers: %s %s",
97 inf->ibusy ?
"interrupt " :
"",
98 inf->cbusy ?
"control" :
"" );
100 if (inf->state != AUSB_DEVICE_SEARCHING) {
101 slog(4, SLOG_DEBUG,
"usb: Entering 'failing' state");
102 inf->state = AUSB_DEVICE_FAILING;
104 libusb_cancel_transfer(inf->itransfer);
105 slog(4, SLOG_DEBUG,
"usb: cancelling itransfer");
108 libusb_cancel_transfer(inf->ctransfer);
109 slog(4, SLOG_DEBUG,
"usb: cancelling ctransfer");
113 if ((!inf->ibusy) && (!inf->cbusy)) {
114 slog(4, SLOG_DEBUG,
"usb: Cleanup done, entering 'restart' state");
121 inf->state = AUSB_DEVICE_RESTART;
125 static void submit_control(
struct aura_node *node)
130 ret = libusb_submit_transfer(inf->ctransfer);
132 slog(0, SLOG_ERROR,
"usb: error submitting control transfer");
133 usb_panic_and_reset_state(node);
138 static void submit_interrupt(
struct aura_node *node)
144 ret = libusb_submit_transfer(inf->itransfer);
147 slog(0, SLOG_ERROR,
"usb: error submitting interrupt transfer");
148 usb_panic_and_reset_state(node);
152 static int check_interrupt(
struct libusb_transfer *transfer)
154 struct aura_node *node = transfer->user_data;
160 if (failing(inf) || (transfer->status != LIBUSB_TRANSFER_COMPLETED)) {
161 usb_panic_and_reset_state(node);
167 static int check_control(
struct libusb_transfer *transfer)
169 struct aura_node *node = transfer->user_data;
175 if (failing(inf) || (transfer->status != LIBUSB_TRANSFER_COMPLETED)) {
176 usb_panic_and_reset_state(node);
183 static inline char *next(
char *nx)
185 return &nx[strlen(nx)+1];
188 static void itransfer_enable(
struct aura_node *node,
bool enable)
192 inf->itransfer_enabled = enable;
194 usb_panic_and_reset_state(node);
201 submit_interrupt(node);
204 static void cb_interrupt(
struct libusb_transfer *transfer)
206 struct aura_node *node = transfer->user_data;
209 if (0 != check_interrupt(transfer))
212 struct usb_interrupt_packet *pck = (
struct usb_interrupt_packet *) inf->ibuffer;
213 inf->pending = (
int) pck->pending_evts;
214 itransfer_enable(node, inf->itransfer_enabled);
217 static void request_object(
struct aura_node *node,
int id);
218 static void cb_parse_object(
struct libusb_transfer *transfer)
220 struct aura_node *node = transfer->user_data;
223 char *name, *afmt, *rfmt;
225 check_control(transfer);
226 name = (
char *) libusb_control_transfer_get_data(transfer);
232 slog(4, SLOG_DEBUG,
"usb: got %s %s / '%s' '%s'",
233 is_method ?
"method" :
"event",
236 aura_etable_add(inf->etbl, name,
237 is_method ? afmt : NULL,
240 if (inf->current_object == inf->num_objects) {
241 slog(4, SLOG_DEBUG,
"etable becomes active");
242 aura_etable_activate(inf->etbl);
244 inf->state = AUSB_DEVICE_OPERATIONAL;
245 itransfer_enable(node,
true);
249 slog(4, SLOG_DEBUG,
"Requesting info about obj %d", inf->current_object);
251 request_object(node, inf->current_object++);
254 static void request_object(
struct aura_node *node,
int id)
257 libusb_fill_control_setup(inf->ctrlbuf,
258 LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
260 0,
id, inf->io_buf_size - LIBUSB_CONTROL_SETUP_SIZE);
261 libusb_fill_control_transfer(inf->ctransfer, inf->handle, inf->ctrlbuf, cb_parse_object, node, 1500);
262 submit_control(node);
265 static void cb_got_dev_info(
struct libusb_transfer *transfer)
267 struct aura_node *node = transfer->user_data;
269 struct usb_info_packet *pck;
273 check_control(transfer);
274 slog(4, SLOG_DEBUG,
"usb: Got info packet from device");
276 if (transfer->actual_length <
sizeof(
struct usb_info_packet)) {
277 slog(0, SLOG_ERROR,
"usb: short-read on info packet want %d got %d (API mismatch?)",
278 sizeof(
struct usb_info_packet), transfer->actual_length);
279 usb_panic_and_reset_state(node);
283 pck = (
struct usb_info_packet *)libusb_control_transfer_get_data(transfer);
285 AURA_ENDIAN_BIG : AURA_ENDIAN_LITTLE);
287 newbufsize = pck->io_buf_size + LIBUSB_CONTROL_SETUP_SIZE;
288 inf->num_objects = pck->num_objs;
290 if (newbufsize > inf->io_buf_size) {
291 slog(4, SLOG_DEBUG,
"usb: adjusting control buffer size: %d->%d bytes",
292 inf->io_buf_size, newbufsize);
293 tmp = realloc(inf->ctrlbuf, newbufsize);
295 slog(0, SLOG_ERROR,
"Allocation error while adjusting control buffer size");
298 inf->io_buf_size = newbufsize;
299 inf->ctrlbuf = (
unsigned char *)tmp;
301 slog(4, SLOG_DEBUG,
"usb: Device has %d objects, now running discovery", inf->num_objects);
302 inf->etbl = aura_etable_create(node, inf->num_objects);
305 slog(0, SLOG_ERROR,
"usb: etable creation failed");
309 inf->current_object = 0;
310 request_object(node, inf->current_object++);
313 static int usb_start_ops(
struct libusb_device_handle *hndl,
void *arg)
322 struct usb_dev_info *inf = arg;
323 struct aura_node *node = inf->node;
327 libusb_fill_interrupt_transfer(inf->itransfer, inf->handle, 0x81,
329 cb_interrupt, node, 10000);
331 libusb_fill_control_setup(inf->ctrlbuf,
332 LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
334 0, 0, inf->io_buf_size);
335 libusb_fill_control_transfer(inf->ctransfer, inf->handle, inf->ctrlbuf, cb_got_dev_info, node, 1500);
337 ret = libusb_submit_transfer(inf->ctransfer);
339 libusb_close(inf->handle);
343 inf->state = AUSB_DEVICE_INIT;
346 slog(4, SLOG_DEBUG,
"usb: Device opened, info packet requested");
351 static void parse_params(
struct usb_dev_info *inf)
356 tmp = strtok_r(inf->optbuf,
":", &sptr);
359 inf->dev_descr.vid = strtoul(tmp, NULL, 16);
361 tmp = strtok_r(NULL,
";", &sptr);
364 inf->dev_descr.pid = strtoul(tmp, NULL, 16);
366 tmp = strtok_r(NULL,
";", &sptr);
369 inf->dev_descr.vendor = tmp;
371 tmp = strtok_r(NULL,
";", &sptr);
374 inf->dev_descr.product = tmp;
376 tmp = strtok_r(NULL,
";", &sptr);
379 inf->dev_descr.serial = tmp;
382 static int usb_open(
struct aura_node *node,
const char *opts)
385 struct usb_dev_info *inf = calloc(1,
sizeof(*inf));
390 ret = libusb_init(&inf->ctx);
394 inf->io_buf_size = 256;
395 inf->optbuf = strdup(opts);
396 inf->dev_descr.device_found_func = usb_start_ops;
397 inf->dev_descr.arg = inf;
401 ncusb_start_descriptor_watching(node, inf->ctx);
404 slog(4, SLOG_INFO,
"usb: vid 0x%x pid 0x%x vendor %s product %s serial %s",
405 inf->dev_descr.vid, inf->dev_descr.pid, inf->dev_descr.vendor,
406 inf->dev_descr.product, inf->dev_descr.serial);
408 inf->ctrlbuf = malloc(inf->io_buf_size);
411 inf->itransfer = libusb_alloc_transfer(0);
415 inf->ctransfer = libusb_alloc_transfer(0);
419 slog(1, SLOG_INFO,
"usb: Now looking for a matching device");
421 ncusb_watch_for_device(inf->ctx, &inf->dev_descr);
426 libusb_free_transfer(inf->itransfer);
430 libusb_exit(inf->ctx);
435 static void usb_close(
struct aura_node *node)
438 inf->itransfer_enabled =
false;
440 slog(4, SLOG_INFO,
"usb: Waiting for transport to close...");
441 usb_panic_and_reset_state(node);
443 while (inf->state != AUSB_DEVICE_RESTART)
444 libusb_handle_events(inf->ctx);
446 slog(4, SLOG_INFO,
"usb: Cleaning up...");
447 libusb_free_transfer(inf->ctransfer);
448 libusb_free_transfer(inf->itransfer);
451 libusb_close(inf->handle);
452 libusb_exit(inf->ctx);
458 static void cb_event_readout_done(
struct libusb_transfer *transfer)
460 struct aura_node *node = transfer->user_data;
462 struct usb_event_packet *evt;
464 struct aura_object *o;
466 if (0 != check_control(transfer))
469 if (transfer->actual_length <
sizeof(
struct usb_event_packet))
473 evt = (
struct usb_event_packet *) libusb_control_transfer_get_data(transfer);
474 o = aura_etable_find_id(node->tbl, evt->id);
476 slog(0, SLOG_ERROR,
"usb: got bogus event id from device %d, resetting", evt->id);
480 if ((transfer->actual_length - LIBUSB_CONTROL_SETUP_SIZE) <
481 (
sizeof(
struct usb_event_packet) + o->retlen)) {
482 slog(0, SLOG_ERROR,
"usb: short read for evt %d: %d bytes expected %d got",
483 evt->id, o->retlen +
sizeof(
struct usb_event_packet),
484 transfer->actual_length);
489 slog(4, SLOG_DEBUG,
"Event readout completed, %d bytes, %d evt left",
490 transfer->actual_length, inf->pending);
493 buf->
pos = LIBUSB_CONTROL_SETUP_SIZE +
sizeof(
struct usb_event_packet);
498 usb_panic_and_reset_state(node);
501 inf->current_buffer = NULL;
505 static void submit_event_readout(
struct aura_node *node)
512 slog(0, SLOG_DEBUG,
"Starting evt readout, max %d bytes, pending %d",
513 inf->io_buf_size, inf->pending);
514 libusb_fill_control_setup((
unsigned char *)buf->
data,
515 LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
517 0, 0, buf->
size - LIBUSB_CONTROL_SETUP_SIZE);
518 libusb_fill_control_transfer(inf->ctransfer, inf->handle, (
unsigned char *)buf->
data,
519 cb_event_readout_done, node, 1500);
520 inf->current_buffer = buf;
521 submit_control(node);
524 static void cb_call_write_done(
struct libusb_transfer *transfer)
526 struct aura_node *node = transfer->user_data;
529 if (0 != check_control(transfer)) {
534 if (transfer->actual_length - LIBUSB_CONTROL_SETUP_SIZE < transfer->length) {
535 slog(0, SLOG_ERROR,
"usb: short-write on call packet want %d got %d (API mismatch?)",
536 transfer->length, transfer->actual_length);
537 usb_panic_and_reset_state(node);
542 inf->current_buffer = NULL;
543 slog(4, SLOG_DEBUG,
"Call write done");
547 inf->current_buffer = NULL;
551 static void submit_call_write(
struct aura_node *node,
struct aura_buffer *buf)
553 struct aura_object *o = buf->
object;
556 slog(4, SLOG_DEBUG,
"Writing call %s data to device, %d bytes", o->name, o->arglen);
557 inf->current_buffer = buf;
558 libusb_fill_control_setup((
unsigned char *)buf->
data,
559 LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
562 libusb_fill_control_transfer(inf->ctransfer, inf->handle,
563 (
unsigned char *) buf->
data,
564 cb_call_write_done, node, 1500);
565 submit_control(node);
568 static void usb_loop(
struct aura_node *node,
const struct aura_pollfds *fd)
572 struct timeval tv = {
577 libusb_handle_events_timeout(inf->ctx, &tv);
582 if (inf->state == AUSB_DEVICE_RESTART) {
583 slog(4, SLOG_DEBUG,
"usb: transport offlined, starting to look for a device");
585 libusb_close(inf->handle);
587 inf->state = AUSB_DEVICE_SEARCHING;
588 ncusb_watch_for_device(inf->ctx, &inf->dev_descr);
592 if (inf->state == AUSB_DEVICE_OPERATIONAL) {
594 submit_event_readout(node);
596 submit_call_write(node, buf);
606 .buffer_overhead = LIBUSB_CONTROL_SETUP_SIZE,
607 .buffer_offset = LIBUSB_CONTROL_SETUP_SIZE
void aura_requeue_buffer(struct list_head *head, struct aura_buffer *buf)
void aura_set_status(struct aura_node *node, int status)
struct aura_buffer * aura_buffer_request(struct aura_node *nd, int size)
struct aura_buffer * aura_dequeue_buffer(struct list_head *head)
const char * name
Required.
static void aura_set_transportdata(struct aura_node *node, void *udata)
static void * aura_get_transportdata(struct aura_node *node)
void aura_queue_buffer(struct list_head *list, struct aura_buffer *buf)
void __attribute__((noreturn)) aura_panic(struct aura_node *node)
void aura_buffer_release(struct aura_buffer *buf)
void aura_set_node_endian(struct aura_node *node, enum aura_endianness en)
struct aura_object * object