static void cb_call_write_done(struct libusb_transfer *transfer) { struct aura_node *node = transfer->user_data; struct usb_dev_info *inf = aura_get_transportdata(node); if (0 != check_control(transfer)) { /* Put it back to queue. Core will deal with it later */ goto requeue; } if (transfer->actual_length - LIBUSB_CONTROL_SETUP_SIZE < transfer->length) { slog(0, SLOG_ERROR, "usb: short-write on call packet want %d got %d (API mismatch?)", transfer->length, transfer->actual_length); usb_panic_and_reset_state(node); goto requeue; } aura_buffer_release(node, inf->current_buffer); inf->current_buffer = NULL; slog(4, SLOG_DEBUG, "Call write done"); return; requeue: aura_requeue_buffer(&node->outbound_buffers, inf->current_buffer); inf->current_buffer = NULL; }
static void usb_stop_ops(void *arg) { struct usb_dev_info *inf = arg; usb_panic_and_reset_state(inf->node); slog(2, SLOG_INFO, "susb: Device disconnect detected!"); susb_offline_transport(inf); }
static void submit_control(struct aura_node *node) { int ret; struct usb_dev_info *inf = aura_get_transportdata(node); ret = libusb_submit_transfer(inf->ctransfer); if (ret!= 0) { slog(0, SLOG_ERROR, "usb: error submitting control transfer"); usb_panic_and_reset_state(node); } inf->cbusy=true; }
static void submit_interrupt(struct aura_node *node) { struct usb_dev_info *inf = aura_get_transportdata(node); int ret; if (inf->ibusy) return; ret = libusb_submit_transfer(inf->itransfer); inf->ibusy = true; if (ret!= 0) { slog(0, SLOG_ERROR, "usb: error submitting interrupt transfer"); usb_panic_and_reset_state(node); } }
static int check_control(struct libusb_transfer *transfer) { struct aura_node *node = transfer->user_data; struct usb_dev_info *inf = aura_get_transportdata(node); int ret = 0; inf->cbusy = false; if (failing(inf) || (transfer->status != LIBUSB_TRANSFER_COMPLETED)) { usb_panic_and_reset_state(node); ret = -EIO; } return ret; }
static void itransfer_enable(struct aura_node *node, bool enable) { struct usb_dev_info *inf = aura_get_transportdata(node); inf->itransfer_enabled = enable; if (failing(inf)) { usb_panic_and_reset_state(node); return; } if (!enable) return; submit_interrupt(node); }
static void cb_got_dev_info(struct libusb_transfer *transfer) { struct aura_node *node = transfer->user_data; struct usb_dev_info *inf = aura_get_transportdata(node); struct usb_info_packet *pck; int newbufsize; char *tmp; check_control(transfer); slog(4, SLOG_DEBUG, "usb: Got info packet from device"); if (transfer->actual_length < sizeof(struct usb_info_packet)) { slog(0, SLOG_ERROR, "usb: short-read on info packet want %d got %d (API mismatch?)", sizeof(struct usb_info_packet), transfer->actual_length); usb_panic_and_reset_state(node); return; } pck = (struct usb_info_packet *)libusb_control_transfer_get_data(transfer); aura_set_node_endian(node, usbdev_is_be(pck) ? AURA_ENDIAN_BIG : AURA_ENDIAN_LITTLE); newbufsize = pck->io_buf_size + LIBUSB_CONTROL_SETUP_SIZE; inf->num_objects = pck->num_objs; if (newbufsize > inf->io_buf_size) { slog(4, SLOG_DEBUG, "usb: adjusting control buffer size: %d->%d bytes", inf->io_buf_size, newbufsize); tmp = realloc(inf->ctrlbuf, newbufsize); if (!tmp) { slog(0, SLOG_ERROR, "Allocation error while adjusting control buffer size"); aura_panic(node); } inf->io_buf_size = newbufsize; inf->ctrlbuf = (unsigned char *)tmp; } slog(4, SLOG_DEBUG, "usb: Device has %d objects, now running discovery", inf->num_objects); inf->etbl = aura_etable_create(node, inf->num_objects); if (!inf->etbl) { slog(0, SLOG_ERROR, "usb: etable creation failed"); aura_panic(node); } inf->current_object = 0; request_object(node, inf->current_object++); }
static void cb_event_readout_done(struct libusb_transfer *transfer) { struct aura_node *node = transfer->user_data; struct usb_dev_info *inf = aura_get_transportdata(node); struct usb_event_packet *evt; struct aura_buffer *buf = inf->current_buffer; struct aura_object *o; if (0 != check_control(transfer)) goto ignore; if (transfer->actual_length < sizeof(struct usb_event_packet)) goto ignore; evt = (struct usb_event_packet *) libusb_control_transfer_get_data(transfer); o = aura_etable_find_id(node->tbl, evt->id); if (!o) { slog(0, SLOG_ERROR, "usb: got bogus event id from device %d, resetting", evt->id); goto panic; } if ((transfer->actual_length - LIBUSB_CONTROL_SETUP_SIZE) < (sizeof(struct usb_event_packet) + o->retlen)) { slog(0, SLOG_ERROR, "usb: short read for evt %d: %d bytes expected %d got", evt->id, o->retlen + sizeof(struct usb_event_packet), transfer->actual_length); goto panic; } inf->pending--; slog(4, SLOG_DEBUG, "Event readout completed, %d bytes, %d evt left", transfer->actual_length, inf->pending); buf->object = o; /* Position the buffer at the start of the responses */ buf->pos = LIBUSB_CONTROL_SETUP_SIZE + sizeof(struct usb_event_packet); aura_queue_buffer(&node->inbound_buffers, buf); return; panic: usb_panic_and_reset_state(node); ignore: aura_buffer_release(node, buf); inf->current_buffer = NULL; return; }
static int check_control(struct libusb_transfer *transfer) { struct aura_node *node = transfer->user_data; struct usb_dev_info *inf = aura_get_transportdata(node); int ret = 0; inf->cbusy = false; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { if (inf->control_retry_count++ < inf->control_retry_max) { slog(0, SLOG_WARN, "Control transfer failed, retrying (%d/%d)", inf->control_retry_count, inf->control_retry_max); submit_control(inf->node); return -EAGAIN; } slog(0, SLOG_ERROR, "usb: error completing control transfer"); ncusb_print_libusb_transfer(transfer); usb_panic_and_reset_state(node); ret = -EIO; } return ret; }
static void usb_close(struct aura_node *node) { struct usb_dev_info *inf = aura_get_transportdata(node); inf->itransfer_enabled = false; /* Waiting for pending transfers */ slog(4, SLOG_INFO, "usb: Waiting for transport to close..."); usb_panic_and_reset_state(node); while (inf->state != AUSB_DEVICE_RESTART) libusb_handle_events(inf->ctx); slog(4, SLOG_INFO, "usb: Cleaning up..."); libusb_free_transfer(inf->ctransfer); libusb_free_transfer(inf->itransfer); free(inf->ctrlbuf); if (inf->handle) libusb_close(inf->handle); libusb_exit(inf->ctx); if (inf->optbuf) free(inf->optbuf); free(inf); }