static int usb_open(struct aura_node *node, const char *opts) { int ret; struct usb_dev_info *inf = calloc(1, sizeof(*inf)); if (!inf) return -ENOMEM; ret = libusb_init(&inf->ctx); if (ret != 0) return -EIO; inf->io_buf_size = 256; inf->optbuf = strdup(opts); inf->dev_descr.device_found_func = usb_start_ops; inf->dev_descr.arg = inf; inf->node = node; parse_params(inf); ncusb_start_descriptor_watching(node, inf->ctx); aura_set_transportdata(node, inf); slog(4, SLOG_INFO, "usb: vid 0x%x pid 0x%x vendor %s product %s serial %s", inf->dev_descr.vid, inf->dev_descr.pid, inf->dev_descr.vendor, inf->dev_descr.product, inf->dev_descr.serial); inf->ctrlbuf = malloc(inf->io_buf_size); if (!inf->ctrlbuf) goto err_free_inf; inf->itransfer = libusb_alloc_transfer(0); if (!inf->itransfer) goto err_free_cbuf; inf->ctransfer = libusb_alloc_transfer(0); if (!inf->ctransfer) goto err_free_int; slog(1, SLOG_INFO, "usb: Now looking for a matching device"); ncusb_watch_for_device(inf->ctx, &inf->dev_descr); return 0; err_free_int: libusb_free_transfer(inf->itransfer); err_free_cbuf: free(inf->ctrlbuf); err_free_inf: libusb_exit(inf->ctx); free(inf); return -ENOMEM; }
static void usb_loop(struct aura_node *node, const struct aura_pollfds *fd) { struct aura_buffer *buf; struct usb_dev_info *inf = aura_get_transportdata(node); struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; libusb_handle_events_timeout(inf->ctx, &tv); if (inf->cbusy) return; if (inf->state == AUSB_DEVICE_RESTART) { slog(4, SLOG_DEBUG, "usb: transport offlined, starting to look for a device"); aura_set_status(node, AURA_STATUS_OFFLINE); libusb_close(inf->handle); inf->handle = NULL; inf->state = AUSB_DEVICE_SEARCHING; ncusb_watch_for_device(inf->ctx, &inf->dev_descr); return; } if (inf->state == AUSB_DEVICE_OPERATIONAL) { if (inf->pending) submit_event_readout(node); else if ( (buf = aura_dequeue_buffer(&node->outbound_buffers)) ) { submit_call_write(node, buf); } } } static struct aura_transport usb = { .name = "usb", .open = usb_open, .close = usb_close, .loop = usb_loop, .buffer_overhead = LIBUSB_CONTROL_SETUP_SIZE, /* Offset for usb SETUP structure */ .buffer_offset = LIBUSB_CONTROL_SETUP_SIZE }; AURA_TRANSPORT(usb);
static void susb_handle_event(struct aura_node *node, enum node_event evt, const struct aura_pollfds *fd) { struct aura_buffer *buf; struct usb_dev_info *inf = aura_get_transportdata(node); ncusb_handle_events_nonblock_once(node, inf->ctx, inf->timer); if (inf->cbusy) return; if (evt == NODE_EVENT_STARTED) { aura_etable_activate(inf->etbl); /* Activate our export table * Hack: Since libusb tends to send and receive data in one buffer, * we need to adjust argument buffer to fit in return values as well. * It helps us to avoid needless copying. */ int i; for (i = 0; i < inf->etbl->next; i++) { struct aura_object *tmp; tmp = &inf->etbl->objects[i]; tmp->arglen += tmp->retlen; } inf->etbl = NULL; ncusb_watch_for_device(inf->ctx, &inf->dev_descr); ncusb_start_descriptor_watching(node, inf->ctx); slog(1, SLOG_INFO, "usb: Now looking for a device %x:%x %s/%s/%s", inf->dev_descr.vid, inf->dev_descr.pid, inf->dev_descr.vendor, inf->dev_descr.product, inf->dev_descr.serial); } else if (inf->state == SUSB_DEVICE_RESTART) { susb_offline_transport(inf); } else if (inf->state == SUSB_DEVICE_OPERATIONAL) { buf = aura_peek_buffer(&node->outbound_buffers); if (buf) susb_issue_call(node, buf); } }