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; }
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; }
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); }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }