static void cb_parse_object(struct libusb_transfer *transfer) { struct aura_node *node = transfer->user_data; struct usb_dev_info *inf = aura_get_transportdata(node); char is_method; char *name, *afmt, *rfmt; check_control(transfer); name = (char *) libusb_control_transfer_get_data(transfer); is_method = *name++; afmt = next(name); rfmt = next(afmt); slog(4, SLOG_DEBUG, "usb: got %s %s / '%s' '%s'", is_method ? "method" : "event", name, afmt, rfmt); aura_etable_add(inf->etbl, name, is_method ? afmt : NULL, rfmt); if (inf->current_object == inf->num_objects) { slog(4, SLOG_DEBUG, "etable becomes active"); aura_etable_activate(inf->etbl); aura_set_status(node, AURA_STATUS_ONLINE); inf->state = AUSB_DEVICE_OPERATIONAL; itransfer_enable(node, true); return; } slog(4, SLOG_DEBUG, "Requesting info about obj %d", inf->current_object); /* Resubmit the transfer for the next round */ request_object(node, inf->current_object++); }
void LibusbDevice::CtrlTransferCallback(libusb_transfer* transfer) { auto* device = static_cast<LibusbDevice*>(transfer->user_data); device->m_transfer_endpoints[0].HandleTransfer(transfer, [&](const auto& cmd) { cmd.FillBuffer(libusb_control_transfer_get_data(transfer), transfer->actual_length); // The return code is the total transfer length -- *including* the setup packet. return transfer->length; }); }
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; }
/** \ingroup syncio * Perform a USB control transfer. * * The direction of the transfer is inferred from the bmRequestType field of * the setup packet. * * The wValue, wIndex and wLength fields values should be given in host-endian * byte order. * * \param dev_handle a handle for the device to communicate with * \param bmRequestType the request type field for the setup packet * \param bRequest the request field for the setup packet * \param wValue the value field for the setup packet * \param wIndex the index field for the setup packet * \param data a suitably-sized data buffer for either input or output * (depending on direction bits within bmRequestType) * \param wLength the length field for the setup packet. The data buffer should * be at least this size. * \param timeout timeout (in millseconds) that this function should wait * before giving up due to no response being received. For an unlimited * timeout, use value 0. * \returns on success, the number of bytes actually transferred * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out * \returns LIBUSB_ERROR_PIPE if the control request was not supported by the * device * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failures */ API_EXPORTED int libusb_control_transfer(libusb_device_handle *dev_handle, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout) { struct libusb_transfer *transfer = libusb_alloc_transfer(0); unsigned char *buffer; int completed = 0; int r; if (!transfer) return LIBUSB_ERROR_NO_MEM; buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + wLength); if (!buffer) { libusb_free_transfer(transfer); return LIBUSB_ERROR_NO_MEM; } libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, wLength); if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength); libusb_fill_control_transfer(transfer, dev_handle, buffer, ctrl_transfer_cb, &completed, timeout); transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER; r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); return r; } while (!completed) { r = libusb_handle_events(HANDLE_CTX(dev_handle)); if (r < 0) { if (r == LIBUSB_ERROR_INTERRUPTED) continue; libusb_cancel_transfer(transfer); while (!completed) if (libusb_handle_events(HANDLE_CTX(dev_handle)) < 0) break; libusb_free_transfer(transfer); return r; } } if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) memcpy(data, libusb_control_transfer_get_data(transfer), transfer->actual_length); switch (transfer->status) { case LIBUSB_TRANSFER_COMPLETED: r = transfer->actual_length; break; case LIBUSB_TRANSFER_TIMED_OUT: r = LIBUSB_ERROR_TIMEOUT; break; case LIBUSB_TRANSFER_STALL: r = LIBUSB_ERROR_PIPE; break; case LIBUSB_TRANSFER_NO_DEVICE: r = LIBUSB_ERROR_NO_DEVICE; break; default: usbi_warn(HANDLE_CTX(dev_handle), "unrecognised status code %d", transfer->status); r = LIBUSB_ERROR_OTHER; } libusb_free_transfer(transfer); return r; }
void usb_callback(struct libusb_transfer* transfer) { int usb_number = *(int*)transfer->user_data; struct usb_state * state = usb_states+usb_number; struct libusb_control_setup* setup = libusb_control_transfer_get_setup(transfer); if(transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL) { if(transfer->status == LIBUSB_TRANSFER_COMPLETED) { if(setup->bmRequestType & LIBUSB_ENDPOINT_IN) { if(transfer->actual_length > 0xff) { fprintf(stderr, "wLength (%hu) is higher than %hu\n", transfer->actual_length, BUFFER_SIZE-LIBUSB_CONTROL_SETUP_SIZE); } else { unsigned char *data = libusb_control_transfer_get_data(transfer); if(adapter_forward_control_in(usb_number, data, transfer->actual_length) < 0) { fprintf(stderr, "can't forward control data to the adapter\n"); } } } } else { if(transfer->status != LIBUSB_TRANSFER_CANCELLED) { fprintf(stderr, "libusb_transfer failed with status %s (bmRequestType=0x%02x, bRequest=0x%02x, wValue=0x%04x)\n", libusb_error_name(transfer->status), setup->bmRequestType, setup->bRequest, setup->wValue); } } } else if(transfer->type == LIBUSB_TRANSFER_TYPE_INTERRUPT) { if(transfer->endpoint == controller[state->type].endpoints.in.address) { state->ack = 1; } if(transfer->status == LIBUSB_TRANSFER_COMPLETED) { if(transfer->endpoint == controller[state->type].endpoints.in.address) { // process joystick events if(transfer->actual_length <= controller[state->type].endpoints.in.size && transfer->actual_length > 0) { process_report(usb_number, state, transfer); } } } else { if(transfer->status != LIBUSB_TRANSFER_TIMED_OUT && transfer->status != LIBUSB_TRANSFER_CANCELLED) { fprintf(stderr, "libusb_transfer failed with status %s (endpoint=0x%02x)\n", libusb_error_name(transfer->status), transfer->endpoint); } } } remove_transfer(transfer); }