static int usb_send_cmd_packet(uint8_t *packet, int size){ int r; if (libusb_state != LIB_USB_TRANSFERS_ALLOCATED) return -1; // async libusb_fill_control_setup(hci_cmd_buffer, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 0, 0, 0, size); memcpy(hci_cmd_buffer + LIBUSB_CONTROL_SETUP_SIZE, packet, size); // prepare transfer int completed = 0; libusb_fill_control_transfer(command_out_transfer, handle, hci_cmd_buffer, async_callback, &completed, 0); command_out_transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER; // update stata before submitting transfer usb_command_active = 1; // submit transfer r = libusb_submit_transfer(command_out_transfer); if (r < 0) { usb_command_active = 0; log_error("Error submitting cmd transfer %d", r); return -1; } return 0; }
static void sm_write_reg(struct fpi_ssm *ssm, unsigned char reg, unsigned char value) { struct fp_img_dev *dev = ssm->priv; struct libusb_transfer *transfer = libusb_alloc_transfer(0); unsigned char *data; int r; if (!transfer) { fpi_ssm_mark_aborted(ssm, -ENOMEM); return; } fp_dbg("set %02x=%02x", reg, value); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_setup(data, CTRL_OUT, reg, value, 0, 0); libusb_fill_control_transfer(transfer, dev->udev, data, sm_write_reg_cb, ssm, CTRL_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); fpi_ssm_mark_aborted(ssm, r); } }
static void sm_exec_cmd(struct fpi_ssm *ssm, unsigned char cmd, unsigned char param) { struct fp_img_dev *dev = ssm->priv; struct libusb_transfer *transfer = libusb_alloc_transfer(0); unsigned char *data; int r; if (!transfer) { fpi_ssm_mark_aborted(ssm, -ENOMEM); return; } fp_dbg("cmd %02x param %02x", cmd, param); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_setup(data, CTRL_IN, cmd, param, 0, 0); libusb_fill_control_transfer(transfer, dev->udev, data, sm_exec_cmd_cb, ssm, CTRL_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); fpi_ssm_mark_aborted(ssm, r); } }
void cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep) { int p; int ret; if (cp->p == MAX_OUTSTANDING) cp_usb_async_sync(cp); p = cp->p; if (!cp->packet[p].transfer) cp->packet[p].transfer = libusb_alloc_transfer(0); cp->packet[p].valuep = valuep; cp->packet[p].direction = packet_read; libusb_fill_control_setup(cp->packet[p].data, 0xc0, /* request */ 0xff, /* request type */ 0x00c2, /* value */ 0, /* index */ 1); /* length */ libusb_fill_control_transfer(cp->packet[p].transfer, cp->handle, cp->packet[p].data, cp_usb_async_transfer_callback, cp, CP_TIMEOUT); ccdbg_debug(CC_DEBUG_USB_ASYNC, "Read packet %d\n", p); ret = libusb_submit_transfer(cp->packet[p].transfer); if (ret) fprintf(stderr, "libusb_submit_transfer failed %d\n", ret); cp->p++; }
int LibusbDevice::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd) { if (!m_device_attached) return LIBUSB_ERROR_NOT_FOUND; DEBUG_LOG(IOS_USB, "[%04x:%04x %d] Control: bRequestType=%02x bRequest=%02x wValue=%04x" " wIndex=%04x wLength=%04x", m_vid, m_pid, m_active_interface, cmd->request_type, cmd->request, cmd->value, cmd->index, cmd->length); switch ((cmd->request_type << 8) | cmd->request) { // The following requests have to go through libusb and cannot be directly sent to the device. case USBHDR(DIR_HOST2DEVICE, TYPE_STANDARD, REC_INTERFACE, REQUEST_SET_INTERFACE): { INFO_LOG(IOS_USB, "[%04x:%04x %d] REQUEST_SET_INTERFACE index=%04x value=%04x", m_vid, m_pid, m_active_interface, cmd->index, cmd->value); if (static_cast<u8>(cmd->index) != m_active_interface) { const int ret = ChangeInterface(static_cast<u8>(cmd->index)); if (ret < 0) { ERROR_LOG(IOS_USB, "[%04x:%04x %d] Failed to change interface to %d: %s", m_vid, m_pid, m_active_interface, cmd->index, libusb_error_name(ret)); return ret; } } const int ret = SetAltSetting(static_cast<u8>(cmd->value)); if (ret == 0) m_ios.EnqueueIPCReply(cmd->ios_request, cmd->length); return ret; } case USBHDR(DIR_HOST2DEVICE, TYPE_STANDARD, REC_DEVICE, REQUEST_SET_CONFIGURATION): { INFO_LOG(IOS_USB, "[%04x:%04x %d] REQUEST_SET_CONFIGURATION index=%04x value=%04x", m_vid, m_pid, m_active_interface, cmd->index, cmd->value); ReleaseAllInterfacesForCurrentConfig(); const int ret = libusb_set_configuration(m_handle, cmd->value); if (ret == 0) { ClaimAllInterfaces(cmd->value); m_ios.EnqueueIPCReply(cmd->ios_request, cmd->length); } return ret; } } const size_t size = cmd->length + LIBUSB_CONTROL_SETUP_SIZE; auto buffer = std::make_unique<u8[]>(size); libusb_fill_control_setup(buffer.get(), cmd->request_type, cmd->request, cmd->value, cmd->index, cmd->length); Memory::CopyFromEmu(buffer.get() + LIBUSB_CONTROL_SETUP_SIZE, cmd->data_address, cmd->length); libusb_transfer* transfer = libusb_alloc_transfer(0); transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; libusb_fill_control_transfer(transfer, m_handle, buffer.release(), CtrlTransferCallback, this, 0); m_transfer_endpoints[0].AddTransfer(std::move(cmd), transfer); return libusb_submit_transfer(transfer); }
static void susb_issue_call(struct aura_node *node, struct aura_buffer *buf) { struct aura_object *o = buf->object; struct usb_dev_info *inf = aura_get_transportdata(node); uint8_t rqtype; uint16_t wIndex, wValue, *ptr; size_t datalen; /*Actual data in packet, save for setup */ if (o->retlen) { rqtype = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN; datalen = o->retlen; } else { datalen = o->arglen - 2 * sizeof(uint16_t); rqtype = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT; } ptr = (uint16_t *)&buf->data[buf->pos]; wValue = *ptr++; wIndex = *ptr++; memmove(&buf->data[buf->pos], ptr, datalen); /* * VUSB-based devices (or libusb?) do not seem to play nicely when we have the * setup packet with no data. Transfers may fail instantly. * A typical run at my box gives: * * 9122 succeeded, 878 failed total 10000 * * See tests-transports/test-susb-stability-none * Adding just one byte of data to the packet fix the issue. * Posible workarounds are: * 1. Retry N times * 2. Add just one dummy byte for the transfer * Since nobody reported this workaround breaking support for their * hardware - we'll do it the second way. For now. */ if (!datalen) datalen++; /* buffer's big enough anyway */ /* e.g if device is big endian, but has le descriptors * we have to be extra careful here */ if (node->need_endian_swap) { wValue = __swap16(wValue); wIndex = __swap16(wValue); } inf->current_buffer = buf; libusb_fill_control_setup((unsigned char *)buf->data, rqtype, o->id, wValue, wIndex, datalen); libusb_fill_control_transfer(inf->ctransfer, inf->handle, (unsigned char *)buf->data, cb_call_done, node, 4000); inf->control_retry_count = 0; submit_control(node); }
static void request_object(struct aura_node *node, int id) { struct usb_dev_info *inf = aura_get_transportdata(node); libusb_fill_control_setup(inf->ctrlbuf, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, RQ_GET_OBJ_INFO, 0, id, inf->io_buf_size - LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_transfer(inf->ctransfer, inf->handle, inf->ctrlbuf, cb_parse_object, node, 1500); submit_control(node); }
static void submit_call_write(struct aura_node *node, struct aura_buffer *buf) { struct aura_object *o = buf->object; struct usb_dev_info *inf = aura_get_transportdata(node); slog(4, SLOG_DEBUG, "Writing call %s data to device, %d bytes", o->name, buf->size); inf->current_buffer = buf; libusb_fill_control_setup((unsigned char *)buf->data, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, RQ_PUT_CALL, 0, 0, buf->size - LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_transfer(inf->ctransfer, inf->handle, (unsigned char *) buf->data, cb_call_write_done, node, 1500); submit_control(node); }
static void submit_event_readout(struct aura_node *node) { struct usb_dev_info *inf = aura_get_transportdata(node); struct aura_buffer *buf = aura_buffer_request(node, inf->io_buf_size); if (!buf) return; /* Nothing bad, we'll try again later */ slog(0, SLOG_DEBUG, "Starting evt readout, max %d bytes, pending %d", inf->io_buf_size, inf->pending); libusb_fill_control_setup((unsigned char *)buf->data, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, RQ_GET_EVENT, 0, 0, buf->size - LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_transfer(inf->ctransfer, inf->handle, (unsigned char *)buf->data, cb_event_readout_done, node, 1500); inf->current_buffer = buf; submit_control(node); }
libusb_error LibusbSoundplaneDriver::processThreadSendControl( libusb_device_handle *device, uint8_t request, uint16_t value, uint16_t index, const unsigned char *data, size_t dataSize) { if (processThreadShouldStopTransfers()) { return LIBUSB_ERROR_OTHER; } unsigned char *buf = static_cast<unsigned char*>(malloc(LIBUSB_CONTROL_SETUP_SIZE + dataSize)); struct libusb_transfer *transfer; if (!buf) { return LIBUSB_ERROR_NO_MEM; } memcpy(buf + LIBUSB_CONTROL_SETUP_SIZE, data, dataSize); transfer = libusb_alloc_transfer(0); if (!transfer) { free(buf); return LIBUSB_ERROR_NO_MEM; } static constexpr auto kCtrlOut = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT; libusb_fill_control_setup(buf, kCtrlOut, request, value, index, dataSize); libusb_fill_control_transfer(transfer, device, buf, &LibusbSoundplaneDriver::processThreadControlTransferCallback, this, 1000); transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; const auto result = static_cast<libusb_error>(libusb_submit_transfer(transfer)); if (result >= 0) { mOutstandingTransfers++; } return result; }
int usb_send_control(int usb_number, unsigned char* buffer, unsigned char length) { struct usb_state* state = usb_states+usb_number; if(!state->devh) { fprintf(stderr, "no usb device opened for index %d\n", usb_number); return -1; } struct libusb_control_setup* control_setup = (struct libusb_control_setup*)buffer; if(control_setup->wLength > BUFFER_SIZE-LIBUSB_CONTROL_SETUP_SIZE) { fprintf(stderr, "wLength (%hu) is higher than %hu\n", control_setup->wLength, BUFFER_SIZE-LIBUSB_CONTROL_SETUP_SIZE); return -1; } unsigned int size = length; if(control_setup->bmRequestType & LIBUSB_ENDPOINT_IN) { size += control_setup->wLength; } unsigned char* buf = calloc(size, sizeof(char)); if(!buf) { fprintf(stderr, "calloc failed\n"); return -1; } memcpy(buf, buffer, length); struct libusb_transfer* transfer = libusb_alloc_transfer(0); transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; libusb_fill_control_transfer(transfer, state->devh, buf, (libusb_transfer_cb_fn)usb_callback, usb_state_indexes+usb_number, 1000); return submit_transfer(transfer); }
void cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value) { int p; uint16_t gpio_set; int ret; if (cp->set) { value = (cp->value & ~mask) | (value & mask); mask = value ^ cp->value; } cp->set = 1; cp->value = value; gpio_set = ((uint16_t) value << 8) | mask; if (cp->p == MAX_OUTSTANDING) cp_usb_async_sync(cp); p = cp->p; if (!cp->packet[p].transfer) cp->packet[p].transfer = libusb_alloc_transfer(0); cp->packet[p].direction = packet_write; libusb_fill_control_setup(cp->packet[p].data, 0x40, /* request */ 0xff, /* request type */ 0x37e1, /* value */ gpio_set, /* index */ 0); /* length */ libusb_fill_control_transfer(cp->packet[p].transfer, cp->handle, cp->packet[p].data, cp_usb_async_transfer_callback, cp, CP_TIMEOUT); ccdbg_debug(CC_DEBUG_USB_ASYNC, "Write packet %d 0x%x 0x%x\n", p, mask, value); ret = libusb_submit_transfer(cp->packet[p].transfer); if (ret) fprintf(stderr, "libusb_submit_transfer failed %d\n", ret); cp->p++; }
/** * cd_sensor_munki_refresh_state: **/ static gboolean cd_sensor_munki_refresh_state (CdSensor *sensor, GError **error) { gint retval; gboolean ret = FALSE; static guint8 *request; libusb_device_handle *handle; CdSensorMunkiPrivate *priv = cd_sensor_munki_get_private (sensor); /* do sync request */ handle = cd_usb_get_device_handle (priv->usb); /* request new button task */ request = g_new0 (guint8, LIBUSB_CONTROL_SETUP_SIZE + 2); libusb_fill_control_setup (request, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, MUNKI_REQUEST_GET_STATUS, 0x00, 0, 2); libusb_fill_control_transfer (priv->transfer_state, handle, request, &cd_sensor_munki_refresh_state_transfer_cb, sensor, 2000); /* submit transfer */ retval = libusb_submit_transfer (priv->transfer_state); if (retval < 0) { g_set_error (error, 1, 0, "failed to submit transfer: %s", libusb_strerror (retval)); goto out; } /* success */ ret = TRUE; out: return ret; }
void Chatpad::send_ctrl(uint8_t request_type, uint8_t request, uint16_t value, uint16_t index, uint8_t* data_in, uint16_t length, libusb_transfer_cb_fn callback, void* userdata) { libusb_transfer* transfer = libusb_alloc_transfer(0); transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER; transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; // create and fill control buffer uint8_t* data = static_cast<uint8_t*>(malloc(length + 8)); libusb_fill_control_setup(data, request_type, request, value, index, length); memcpy(data + 8, data_in, length); libusb_fill_control_transfer(transfer, m_handle, data, callback, userdata, 0); int ret; ret = libusb_submit_transfer(transfer); if (ret != LIBUSB_SUCCESS) { raise_exception(std::runtime_error, "libusb_submit_transfer(): " << usb_strerror(ret)); } }
static int usb_start_ops(struct libusb_device_handle *hndl, void *arg) { /* FixMe: Reading descriptors is synchronos. This is not needed * often, but leaves a possibility of a flaky usb device to * screw up the event processing. * A proper workaround would be manually reading out string descriptors * from a device in an async fasion in the background. */ int ret; struct usb_dev_info *inf = arg; struct aura_node *node = inf->node; inf->handle = hndl; libusb_fill_interrupt_transfer(inf->itransfer, inf->handle, 0x81, inf->ibuffer, 8, cb_interrupt, node, 10000); libusb_fill_control_setup(inf->ctrlbuf, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, RQ_GET_DEV_INFO, 0, 0, inf->io_buf_size); libusb_fill_control_transfer(inf->ctransfer, inf->handle, inf->ctrlbuf, cb_got_dev_info, node, 1500); ret = libusb_submit_transfer(inf->ctransfer); if (ret!= 0) { libusb_close(inf->handle); return -1; } inf->state = AUSB_DEVICE_INIT; /* Change our state */ inf->cbusy = true; slog(4, SLOG_DEBUG, "usb: Device opened, info packet requested"); return 0; };
static int set_mode_async(unsigned char data) { unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); struct libusb_transfer *transfer; if (!buf) return -ENOMEM; transfer = libusb_alloc_transfer(0); if (!transfer) { free(buf); return -ENOMEM; } printf("async set mode %02x\n", data); libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1); buf[LIBUSB_CONTROL_SETUP_SIZE] = data; libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL, 1000); transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; return libusb_submit_transfer(transfer); }
static int dev_open(struct sr_dev_inst *sdi) { struct drv_context *drvc; struct dev_context *devc; struct sr_usb_dev_inst *usb; uint8_t buffer[PACKET_LENGTH]; int ret; if (!(drvc = di->priv)) { sr_err("Driver was not initialized."); return SR_ERR; } usb = sdi->conn; devc = sdi->priv; if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK) return SR_ERR; /* * Determine if a kernel driver is active on this interface and, if so, * detach it. */ if (libusb_kernel_driver_active(usb->devhdl, USB_INTERFACE) == 1) { ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE); if (ret < 0) { sr_err("Failed to detach kernel driver: %s.", libusb_error_name(ret)); return SR_ERR; } } if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE)) < 0) { sr_err("Failed to claim interface: %s.", libusb_error_name(ret)); return SR_ERR; } libusb_fill_control_transfer(devc->xfer_in, usb->devhdl, devc->xfer_buf_in, sl2_receive_transfer_in, sdi, USB_TIMEOUT); libusb_fill_control_transfer(devc->xfer_out, usb->devhdl, devc->xfer_buf_out, sl2_receive_transfer_out, sdi, USB_TIMEOUT); memset(buffer, 0, sizeof(buffer)); buffer[0] = CMD_RESET; if ((ret = sl2_transfer_out(usb->devhdl, buffer)) != PACKET_LENGTH) { sr_err("Device reset failed: %s.", libusb_error_name(ret)); return SR_ERR; } /* * Set the device to idle state. If the device is not in idle state it * possibly will reset itself after a few seconds without being used * and thereby close the connection. */ buffer[0] = CMD_IDLE; if ((ret = sl2_transfer_out(usb->devhdl, buffer)) != PACKET_LENGTH) { sr_err("Failed to set device in idle state: %s.", libusb_error_name(ret)); return SR_ERR; } sdi->status = SR_ST_ACTIVE; return SR_OK; }
/** \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; }
bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress) { u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); u32 ReturnValue = 0; switch (Parameter) { case IOCTL_HID_GET_ATTACHED: { DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Get Attached) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", BufferIn, BufferInSize, BufferOut, BufferOutSize); deviceCommandAddress = _CommandAddress; return false; break; } case IOCTL_HID_OPEN: { DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Open) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", BufferIn, BufferInSize, BufferOut, BufferOutSize); //hid version, apparently ReturnValue = 0x40001; break; } case IOCTL_HID_SET_SUSPEND: { DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Set Suspend) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", BufferIn, BufferInSize, BufferOut, BufferOutSize); // not actually implemented in IOS ReturnValue = 0; break; } case IOCTL_HID_CANCEL_INTERRUPT: { DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Cancel Interrupt) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", BufferIn, BufferInSize, BufferOut, BufferOutSize); ReturnValue = 0; break; } case IOCTL_HID_CONTROL: { /* ERROR CODES: -4 Cant find device specified */ u32 dev_num = Memory::Read_U32(BufferIn+0x10); u8 bmRequestType = Memory::Read_U8(BufferIn+0x14); u8 bRequest = Memory::Read_U8(BufferIn+0x15); u16 wValue = Memory::Read_U16(BufferIn+0x16); u16 wIndex = Memory::Read_U16(BufferIn+0x18); u16 wLength = Memory::Read_U16(BufferIn+0x1A); u32 data = Memory::Read_U32(BufferIn+0x1C); ReturnValue = HIDERR_NO_DEVICE_FOUND; libusb_device_handle * dev_handle = GetDeviceByDevNum(dev_num); if (dev_handle == NULL) { DEBUG_LOG(WII_IPC_HID, "Could not find handle: %X", dev_num); break; } struct libusb_transfer *transfer = libusb_alloc_transfer(0); transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; u8 * buffer = (u8*)malloc(wLength + LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, wLength); memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, Memory::GetPointer(data), wLength); libusb_fill_control_transfer(transfer, dev_handle, buffer, handleUsbUpdates, (void*)(size_t)_CommandAddress, /* no timeout */ 0); libusb_submit_transfer(transfer); //DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Control)(%02X, %02X) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", // bmRequestType, bRequest, BufferIn, BufferInSize, BufferOut, BufferOutSize); // It's the async way! return false; break; } case IOCTL_HID_INTERRUPT_OUT: case IOCTL_HID_INTERRUPT_IN: { u32 dev_num = Memory::Read_U32(BufferIn+0x10); u32 endpoint = Memory::Read_U32(BufferIn+0x14); u32 length = Memory::Read_U32(BufferIn+0x18); u32 data = Memory::Read_U32(BufferIn+0x1C); ReturnValue = HIDERR_NO_DEVICE_FOUND; libusb_device_handle * dev_handle = GetDeviceByDevNum(dev_num); if (dev_handle == NULL) { DEBUG_LOG(WII_IPC_HID, "Could not find handle: %X", dev_num); break; } struct libusb_transfer *transfer = libusb_alloc_transfer(0); transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; libusb_fill_interrupt_transfer(transfer, dev_handle, endpoint, Memory::GetPointer(data), length, handleUsbUpdates, (void*)(size_t)_CommandAddress, 0); libusb_submit_transfer(transfer); //DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Interrupt %s)(%d,%d,%X) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", // Parameter == IOCTL_HID_INTERRUPT_IN ? "In" : "Out", endpoint, length, data, BufferIn, BufferInSize, BufferOut, BufferOutSize); // It's the async way! return false; break; } case IOCTL_HID_SHUTDOWN: { std::lock_guard<std::mutex> lk(s_device_list_reply); if (deviceCommandAddress != 0){ Memory::Write_U32(0xFFFFFFFF, Memory::Read_U32(deviceCommandAddress + 0x18)); Memory::Write_U32(8, deviceCommandAddress); // IOS seems to write back the command that was responded to Memory::Write_U32(/*COMMAND_IOCTL*/ 6, deviceCommandAddress + 8); // Return value Memory::Write_U32(-1, deviceCommandAddress + 4); WII_IPC_HLE_Interface::EnqueReplyCallback(deviceCommandAddress); deviceCommandAddress = 0; } DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Shutdown) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", BufferIn, BufferInSize, BufferOut, BufferOutSize); break; } default: { DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(0x%x) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize); break; } } Memory::Write_U32(ReturnValue, _CommandAddress + 4); return true; }