Exemple #1
0
/*
 * FIXME: Packetize large buffers here. 2.4 HCDs (atleast, haven't checked
 * 2.5 HCDs yet) don't handle multi-packet Interrupt transfers. So we need
 * to lookup the endpoint packet size and packetize appropriately here.
 */
int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
	int timeout)
{
  /* Ensure the endpoint address is correct */
  return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
		timeout);
}
int usb_bulk_write(usb_dev_handle *dev, int ep, const char *bytes, int size,
	int timeout)
{
  /* Ensure the endpoint address is correct */
  return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, (char *)bytes, size,
		timeout);
}
Exemple #3
0
int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
	int timeout)
{
  /* Ensure the endpoint address is correct */
  ep |= USB_ENDPOINT_IN;
  return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
		timeout);
}
Exemple #4
0
/* Reading and writing are the same except for the endpoint */
static int usb_urb_transfer_sp(usb_dev_handle *dev, int ep, int urbtype,
	char *bytes, int size, int timeout, int *actual_length, int max_rw)
{
  struct usb_urb urb;
  int bytesdone = 0, requested;
  struct timeval tv, tv_ref, tv_now;
  struct usb_urb *context;
  int ret, waiting;

  /*
   * HACK: The use of urb.usercontext is a hack to get threaded applications
   * sort of working again. Threaded support is still not recommended, but
   * this should allow applications to work in the common cases. Basically,
   * if we get the completion for an URB we're not waiting for, then we update
   * the usercontext pointer to 1 for the other threads URB and it will see
   * the change after it wakes up from the the timeout. Ugly, but it works.
   */

  /*
   * Get actual time, and add the timeout value. The result is the absolute
   * time where we have to quit waiting for an message.
   */
  gettimeofday(&tv_ref, NULL);
  tv_ref.tv_sec = tv_ref.tv_sec + timeout / 1000;
  tv_ref.tv_usec = tv_ref.tv_usec + (timeout % 1000) * 1000;

  if (tv_ref.tv_usec > 1000000) {
    tv_ref.tv_usec -= 1000000;
    tv_ref.tv_sec++;
  }

  do {
    fd_set writefds;

    requested = size - bytesdone;
    if (requested > max_rw)
      requested = max_rw;

    urb.type = urbtype;
    urb.endpoint = ep;
    urb.flags = 0;
    urb.buffer = bytes + bytesdone;
    urb.buffer_length = requested;
    urb.signr = 0;
    urb.actual_length = 0;
    urb.number_of_packets = 0;	/* don't do isochronous yet */
    urb.usercontext = NULL;

    ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urb);
    if (ret < 0) {
      USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno));
      return ret;
    }

    FD_ZERO(&writefds);
    FD_SET(dev->fd, &writefds);

restart:
    waiting = 1;
    context = NULL;
    while (!urb.usercontext && ((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && waiting) {
      tv.tv_sec = 0;
      tv.tv_usec = 1000; // 1 msec
      select(dev->fd + 1, NULL, &writefds, NULL, &tv); //sub second wait
#if 0
      if (timeout) {
#else /* 32767 is a magic number for no timeout */
      if (timeout && timeout != 32767) {
#endif
        /* compare with actual time, as the select timeout is not that precise */
        gettimeofday(&tv_now, NULL);

        if ((tv_now.tv_sec > tv_ref.tv_sec) ||
            ((tv_now.tv_sec == tv_ref.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec)))
          waiting = 0;
      }
    }

    if (context && context != &urb) {
      context->usercontext = URB_USERCONTEXT_COOKIE;
      /* We need to restart since we got a successful URB, but not ours */
      goto restart;
    }

    /*
     * If there was an error, that wasn't EAGAIN (no completion), then
     * something happened during the reaping and we should return that
     * error now
     */
    if (ret < 0 && !urb.usercontext && errno != EAGAIN)
      USB_ERROR_STR(-errno, "error reaping URB: %s", strerror(errno));

    bytesdone += urb.actual_length;
    *actual_length = bytesdone;
  } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested);

  /* If the URB didn't complete in success or error, then let's unlink it */
  if (ret < 0 && !urb.usercontext) {
    int rc;

    if (!waiting)
      rc = -ETIMEDOUT;
    else
      rc = urb.status;

    ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &urb);
    if (ret < 0 && errno != EINVAL && usb_debug >= 1)
      fprintf(stderr, "error discarding URB: %s", strerror(errno));

    /*
     * When the URB is unlinked, it gets moved to the completed list and
     * then we need to reap it or else the next time we call this function,
     * we'll get the previous completion and exit early
     */
    ioctl(dev->fd, IOCTL_USB_REAPURB, &context);

    return rc;
  }

  return bytesdone;
}

int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
	int timeout)
{
  /* Ensure the endpoint address is correct */
  return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
		timeout);
}

int usb_bulk_write_sp(usb_dev_handle *dev, int ep, char *bytes, int size,
	int timeout, int *actual_length, int max_rw)
{
  /* Ensure the endpoint address is correct */
  return usb_urb_transfer_sp(dev, ep, USB_URB_TYPE_BULK, bytes, size,
		timeout, actual_length, max_rw);
}

int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
	int timeout)
{
  /* Ensure the endpoint address is correct */
  ep |= USB_ENDPOINT_IN;
  return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
		timeout);
}