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;
}
Пример #2
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);
	}
}
Пример #3
0
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);
	}
}
Пример #4
0
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++;
}
Пример #5
0
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);
}
Пример #6
0
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);
}
Пример #7
0
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);	
}
Пример #8
0
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);
}
Пример #9
0
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;
}
Пример #11
0
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);
}
Пример #12
0
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++;
}
Пример #13
0
/**
 * 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;
}
Пример #14
0
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));
  }
}
Пример #15
0
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;
};
Пример #16
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);
}
Пример #17
0
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;
}
Пример #18
0
/** \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;
}
Пример #19
0
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;
}