Beispiel #1
0
UsbEndpoint *
usbGetEndpoint (UsbDevice *device, unsigned char endpointAddress) {
  UsbEndpoint *endpoint;
  const UsbEndpointDescriptor *descriptor;

  if ((endpoint = findItem(device->endpoints, usbTestEndpoint, &endpointAddress))) return endpoint;

  if ((descriptor = usbEndpointDescriptor(device, endpointAddress))) {
    {
      const char *direction;
      const char *transfer;

      switch (USB_ENDPOINT_DIRECTION(descriptor)) {
        default:                            direction = "?";   break;
        case UsbEndpointDirection_Input:  direction = "in";  break;
        case UsbEndpointDirection_Output: direction = "out"; break;
      }

      switch (USB_ENDPOINT_TRANSFER(descriptor)) {
        default:                                transfer = "?";   break;
        case UsbEndpointTransfer_Control:     transfer = "ctl"; break;
        case UsbEndpointTransfer_Isochronous: transfer = "iso"; break;
        case UsbEndpointTransfer_Bulk:        transfer = "blk"; break;
        case UsbEndpointTransfer_Interrupt:   transfer = "int"; break;
      }

      logMessage(LOG_DEBUG, "USB: ept=%02X dir=%s xfr=%s pkt=%d ivl=%dms",
                 descriptor->bEndpointAddress, direction, transfer,
                 getLittleEndian16(descriptor->wMaxPacketSize),
                 descriptor->bInterval);
    }

    if ((endpoint = malloc(sizeof(*endpoint)))) {
      memset(endpoint, 0, sizeof(*endpoint));
      endpoint->device = device;
      endpoint->descriptor = descriptor;

      switch (USB_ENDPOINT_DIRECTION(endpoint->descriptor)) {
        case UsbEndpointDirection_Input:
          endpoint->direction.input.pending = NULL;
          endpoint->direction.input.completed = NULL;
          endpoint->direction.input.buffer = NULL;
          endpoint->direction.input.length = 0;
          endpoint->direction.input.asynchronous = 0;
          break;
      }

      endpoint->extension = NULL;
      if (usbAllocateEndpointExtension(endpoint)) {
        if (enqueueItem(device->endpoints, endpoint)) return endpoint;
        usbDeallocateEndpointExtension(endpoint->extension);
      }

      free(endpoint);
    }
  }

  return NULL;
}
Beispiel #2
0
static ssize_t
usbBulkTransfer (
  UsbEndpoint *endpoint,
  void *buffer,
  size_t length,
  int timeout
) {
  UsbDeviceExtension *devx = endpoint->device->extension;

  if (usbOpenUsbfsFile(devx)) {
    struct usbdevfs_bulktransfer arg;

    memset(&arg, 0, sizeof(arg));
    arg.ep = endpoint->descriptor->bEndpointAddress;
    arg.data = buffer;
    arg.len = length;
    arg.timeout = timeout;

    {
      int count = ioctl(devx->usbfsFile, USBDEVFS_BULK, &arg);
      if (count != -1) return count;
      if (USB_ENDPOINT_DIRECTION(endpoint->descriptor) == UsbEndpointDirection_Input)
        if (errno == ETIMEDOUT)
          errno = EAGAIN;
      if (errno != EAGAIN) logSystemError("USB bulk transfer");
    }
  }

  return -1;
}
Beispiel #3
0
static void
usbDeallocateEndpoint (void *item, void *data) {
  UsbEndpoint *endpoint = item;

  switch (USB_ENDPOINT_DIRECTION(endpoint->descriptor)) {
    case UsbEndpointDirection_Input:
      if (endpoint->direction.input.pending) {
        deallocateQueue(endpoint->direction.input.pending);
        endpoint->direction.input.pending = NULL;
      }

      if (endpoint->direction.input.completed) {
        free(endpoint->direction.input.completed);
        endpoint->direction.input.completed = NULL;
      }

      break;
  }

  if (endpoint->extension) {
    usbDeallocateEndpointExtension(endpoint->extension);
    endpoint->extension = NULL;
  }

  free(endpoint);
}
Beispiel #4
0
static void
usbDeallocateEndpoint (void *item, void *data) {
  UsbEndpoint *endpoint = item;

  switch (USB_ENDPOINT_DIRECTION(endpoint->descriptor)) {
    case UsbEndpointDirection_Input:
      if (endpoint->direction.input.pending.alarm) {
        asyncCancelRequest(endpoint->direction.input.pending.alarm);
        endpoint->direction.input.pending.alarm = NULL;
      }

      if (endpoint->direction.input.pending.requests) {
        deallocateQueue(endpoint->direction.input.pending.requests);
        endpoint->direction.input.pending.requests = NULL;
      }

      if (endpoint->direction.input.completed.request) {
        free(endpoint->direction.input.completed.request);
        endpoint->direction.input.completed.request = NULL;
      }

      break;

    default:
      break;
  }

  if (endpoint->extension) {
    usbDeallocateEndpointExtension(endpoint->extension);
    endpoint->extension = NULL;
  }

  switch (USB_ENDPOINT_DIRECTION(endpoint->descriptor)) {
    case UsbEndpointDirection_Input:
      usbDestroyInputPipe(endpoint);
      break;

    default:
      break;
  }

  free(endpoint);
}
Beispiel #5
0
void *
usbSubmitRequest (
  UsbDevice *device,
  unsigned char endpointAddress,
  void *buffer,
  size_t length,
  void *context
) {
  UsbEndpoint *endpoint;

  if ((endpoint = usbGetEndpoint(device, endpointAddress))) {
    UsbEndpointExtension *eptx = endpoint->extension;
    UsbAsynchronousRequest *request;

    if ((request = malloc(sizeof(*request) + length))) {
      UsbEndpointDirection direction = USB_ENDPOINT_DIRECTION(endpoint->descriptor);

      request->endpoint = endpoint;
      request->context = context;
      request->buffer = (request->length = length)? (request + 1): NULL;
      request->result.aio_return = AIO_INPROGRESS;

      switch (direction) {
        case UsbEndpointDirection_Input:
          if (aioread(eptx->data, request->buffer, request->length, 0, SEEK_CUR, &request->result) != -1) return request;
          logSystemError("USB asynchronous read");
          break;

        case UsbEndpointDirection_Output:
          if (request->buffer) memcpy(request->buffer, buffer, length);
          if (aiowrite(eptx->data, request->buffer, request->length, 0, SEEK_CUR, &request->result) != -1) return request;
          logSystemError("USB asynchronous write");
          break;

        default:
          logMessage(LOG_ERR, "USB unsupported asynchronous direction: %02X", direction);
          errno = ENOSYS;
          break;
      }

      free(request);
    } else {
      logSystemError("USB asynchronous request allocate");
    }
  }

  return NULL;
}
Beispiel #6
0
static int
usbFinishEndpoint (void *item, void *data) {
  UsbEndpoint *endpoint = item;

  switch (USB_ENDPOINT_DIRECTION(endpoint->descriptor)) {
    case UsbEndpointDirection_Input:
      if (endpoint->direction.input.pending.requests) {
        deleteElements(endpoint->direction.input.pending.requests);
      }
      break;

    default:
      break;
  }

  return 0;
}
Beispiel #7
0
void *
usbReapResponse (
  UsbDevice *device,
  unsigned char endpointAddress,
  UsbResponse *response,
  int wait
) {
  UsbEndpoint *endpoint;

  if ((endpoint = usbGetEndpoint(device, endpointAddress))) {
    UsbEndpointExtension *eptx = endpoint->extension;
    struct usbdevfs_urb *urb;

    while (!(urb = dequeueItem(eptx->completedRequests))) {
      if (!usbReapUrb(device, wait)) return NULL;
    }

    response->context = urb->usercontext;
    response->buffer = urb->buffer;
    response->size = urb->buffer_length;

    if ((response->error = urb->status)) {
      if (response->error < 0) response->error = -response->error;
      errno = response->error;
      logSystemError("USB URB status");
      response->count = -1;
    } else {
      response->count = urb->actual_length;

      switch (USB_ENDPOINT_DIRECTION(endpoint->descriptor)) {
        case UsbEndpointDirection_Input:
          if (!usbApplyInputFilters(device, response->buffer, response->size, &response->count)) {
            response->error = EIO;
            response->count = -1;
          }
          break;
      }
    }

    return urb;
  }

  return NULL;
}
Beispiel #8
0
static const UsbEndpointDescriptor *
usbFindInterruptInputEndpoint (UsbDevice *device, const UsbInterfaceDescriptor *interface) {
  const UsbDescriptor *descriptor = (const UsbDescriptor *)interface;

  while (usbNextDescriptor(device, &descriptor)) {
    if (descriptor->header.bDescriptorType == UsbDescriptorType_Interface) break;

    if (descriptor->header.bDescriptorType == UsbDescriptorType_Endpoint) {
      if (USB_ENDPOINT_DIRECTION(&descriptor->endpoint) == UsbEndpointDirection_Input) {
        if (USB_ENDPOINT_TRANSFER(&descriptor->endpoint) == UsbEndpointTransfer_Interrupt) {
          return &descriptor->endpoint;
        }
      }
    }
  }

  logMessage(LOG_WARNING, "USB: interrupt input endpoint descriptor not found");
  errno = ENOENT;
  return NULL;
}
Beispiel #9
0
void *
usbSubmitRequest (
  UsbDevice *device,
  unsigned char endpointAddress,
  void *buffer,
  size_t length,
  void *context
) {
  UsbDeviceExtension *devx = device->extension;

  if (usbOpenUsbfsFile(devx)) {
    UsbEndpoint *endpoint;

    if ((endpoint = usbGetEndpoint(device, endpointAddress))) {
      struct usbdevfs_urb *urb;

      if ((urb = malloc(sizeof(*urb) + length))) {
        memset(urb, 0, sizeof(*urb));
        urb->endpoint = endpointAddress;
        urb->flags = 0;
        urb->signr = 0;
        urb->usercontext = context;

        urb->buffer = (urb->buffer_length = length)? (urb + 1): NULL;
        if (buffer)
          if (USB_ENDPOINT_DIRECTION(endpoint->descriptor) == UsbEndpointDirection_Output)
            memcpy(urb->buffer, buffer, length);

        switch (USB_ENDPOINT_TRANSFER(endpoint->descriptor)) {
          case UsbEndpointTransfer_Control:
            urb->type = USBDEVFS_URB_TYPE_CONTROL;
            break;

          case UsbEndpointTransfer_Isochronous:
            urb->type = USBDEVFS_URB_TYPE_ISO;
            break;

          case UsbEndpointTransfer_Interrupt:
          case UsbEndpointTransfer_Bulk:
            urb->type = USBDEVFS_URB_TYPE_BULK;
            break;
        }

      /*
        logMessage(LOG_DEBUG, "USB submit: urb=%p typ=%02X ept=%02X flg=%X sig=%d buf=%p len=%d ctx=%p",
                   urb, urb->type, urb->endpoint, urb->flags, urb->signr,
                   urb->buffer, urb->buffer_length, urb->usercontext);
      */
      submit:
        if (ioctl(devx->usbfsFile, USBDEVFS_SUBMITURB, urb) != -1) return urb;
        if ((errno == EINVAL) &&
            (USB_ENDPOINT_TRANSFER(endpoint->descriptor) == UsbEndpointTransfer_Interrupt) &&
            (urb->type == USBDEVFS_URB_TYPE_BULK)) {
          urb->type = USBDEVFS_URB_TYPE_INTERRUPT;
          goto submit;
        }

        /* UHCI support returns ENXIO if a URB is already submitted. */
        if (errno != ENXIO) logSystemError("USB URB submit");

        free(urb);
      } else {
        logSystemError("USB URB allocate");
      }
    }
  }

  return NULL;
}
Beispiel #10
0
int
usbAllocateEndpointExtension (UsbEndpoint *endpoint) {
  UsbDevice *device = endpoint->device;
  UsbDeviceExtension *devx = device->extension;
  UsbEndpointExtension *eptx;

  if ((eptx = malloc(sizeof(*eptx)))) {
    if ((eptx->requests = newQueue(NULL, NULL))) {
      int flags;
  
      {
        char name[0X80];
        int length = 0;
  
        if (devx->configuration != 1) {
          int count;
          sprintf(&name[length], "cfg%d%n", devx->configuration, &count);
          length += count;
        }
  
        {
          int count;
          sprintf(&name[length], "if%d%n", devx->interface, &count);
          length += count;
        }
  
        if (devx->alternative != 0) {
          int count;
          sprintf(&name[length], ".%d%n", devx->alternative, &count);
          length += count;
        }
  
        {
          const UsbEndpointDescriptor *descriptor = endpoint->descriptor;
          UsbEndpointDirection direction = USB_ENDPOINT_DIRECTION(descriptor);
          const char *prefix;
  
          switch (direction) {
            case UsbEndpointDirection_Input:
              prefix = "in";
              flags = O_RDONLY;
              break;
  
            case UsbEndpointDirection_Output:
              prefix = "out";
              flags = O_WRONLY;
              break;
  
            default:
              logMessage(LOG_ERR, "USB unsupported endpoint direction: %02X", direction);
              goto nameError;
          }
  
          {
            int count;
            sprintf(&name[length], "%s%d%n", prefix, USB_ENDPOINT_NUMBER(descriptor), &count);
            length += count;
          }
        }
  
        eptx->name = strdup(name);
      }
  
      if (eptx->name) {
        if (usbOpenEndpointFiles(devx->path, eptx->name, &eptx->data, &eptx->status,  flags)) {
          endpoint->extension = eptx;
          return 1;
        }
  
        free(eptx->name);
      }
    nameError:

      deallocateQueue(eptx->requests);
    }

    free(eptx);
  }

  return 0;
}
Beispiel #11
0
void *
usbReapResponse (
  UsbDevice *device,
  unsigned char endpointAddress,
  UsbResponse *response,
  int wait
) {
  UsbEndpoint *endpoint;

  if ((endpoint = usbGetEndpoint(device, endpointAddress))) {
    UsbEndpointExtension *eptx = endpoint->extension;
    struct timeval timeout;
    UsbAsynchronousRequest *request;

    timeout.tv_sec = 0;
    timeout.tv_usec = 0;

    while (!(request = dequeueItem(eptx->requests))) {
      aio_result_t *result;

    doWait:
      if ((int)(result = aiowait(wait? NULL: &timeout)) == -1) {
        if (errno == EINTR) goto doWait;

        if (errno != EINVAL) {
          logSystemError("USB asynchronous wait");
          return NULL;
        }

        result = NULL;
      }

      if (!result) {
        errno = EAGAIN;
        return NULL;
      }

      request = (UsbAsynchronousRequest *)result;
      {
        UsbEndpoint *ep = request->endpoint;
        UsbEndpointExtension *epx = ep->extension;
        if (!enqueueItem(epx->requests, request)) {
          logSystemError("USB asynchronous enqueue");
        }
      }
    }

    response->context = request->context;
    response->buffer = request->buffer;
    response->size = request->length;
    response->count = request->result.aio_return;
    response->error = request->result.aio_errno;

    if (response->count == -1) {
      errno = response->error;
      logSystemError("USB asynchronous completion");
    } else {
      switch (USB_ENDPOINT_DIRECTION(endpoint->descriptor)) {
        case UsbEndpointDirection_Input:
          if (!usbApplyInputFilters(endpoint, response->buffer, response->size, &response->count)) {
            response->error = EIO;
            response->count = -1;
          }
          break;
      }
    }

    return request;
  }

  return NULL;
}
Beispiel #12
0
UsbEndpoint *
usbGetEndpoint (UsbDevice *device, unsigned char endpointAddress) {
  UsbEndpoint *endpoint;
  const UsbEndpointDescriptor *descriptor;

  if ((endpoint = findItem(device->endpoints, usbTestEndpoint, &endpointAddress))) return endpoint;

  if ((descriptor = usbEndpointDescriptor(device, endpointAddress))) {
    {
      const char *direction;
      const char *transfer;

      switch (USB_ENDPOINT_DIRECTION(descriptor)) {
        default:                          direction = "?";   break;
        case UsbEndpointDirection_Input:  direction = "in";  break;
        case UsbEndpointDirection_Output: direction = "out"; break;
      }

      switch (USB_ENDPOINT_TRANSFER(descriptor)) {
        default:                              transfer = "?";   break;
        case UsbEndpointTransfer_Control:     transfer = "ctl"; break;
        case UsbEndpointTransfer_Isochronous: transfer = "iso"; break;
        case UsbEndpointTransfer_Bulk:        transfer = "blk"; break;
        case UsbEndpointTransfer_Interrupt:   transfer = "int"; break;
      }

      logMessage(LOG_CATEGORY(USB_IO), "ept=%02X dir=%s xfr=%s pkt=%d ivl=%dms",
                 descriptor->bEndpointAddress, direction, transfer,
                 getLittleEndian16(descriptor->wMaxPacketSize),
                 descriptor->bInterval);
    }

    if ((endpoint = malloc(sizeof(*endpoint)))) {
      memset(endpoint, 0, sizeof(*endpoint));
      endpoint->device = device;
      endpoint->descriptor = descriptor;
      endpoint->extension = NULL;
      endpoint->prepare = NULL;

      switch (USB_ENDPOINT_DIRECTION(endpoint->descriptor)) {
        case UsbEndpointDirection_Input:
          endpoint->direction.input.pending.requests = NULL;
          endpoint->direction.input.pending.alarm = NULL;
          endpoint->direction.input.pending.delay = 0;

          endpoint->direction.input.completed.request = NULL;
          endpoint->direction.input.completed.buffer = NULL;
          endpoint->direction.input.completed.length = 0;

          endpoint->direction.input.pipe.input = INVALID_FILE_DESCRIPTOR;
          endpoint->direction.input.pipe.output = INVALID_FILE_DESCRIPTOR;
          endpoint->direction.input.pipe.monitor = NULL;
          endpoint->direction.input.pipe.error = 0;

          break;
      }

      if (usbAllocateEndpointExtension(endpoint)) {
        if (enqueueItem(device->endpoints, endpoint)) {
          if (device->disableEndpointReset) {
            logMessage(LOG_CATEGORY(USB_IO), "endpoint reset disabled");
          } else {
            usbClearHalt(device, endpoint->descriptor->bEndpointAddress);
          }

          if (!endpoint->prepare || endpoint->prepare(endpoint)) return endpoint;
          deleteItem(device->endpoints, endpoint);
        }

        usbDeallocateEndpointExtension(endpoint->extension);
        usbDestroyInputPipe(endpoint);
      }

      free(endpoint);
    }
  }

  return NULL;
}