static int usbReapUrb ( UsbDevice *device, int wait ) { UsbDeviceExtension *devx = device->extension; if (usbOpenUsbfsFile(devx)) { struct usbdevfs_urb *urb; if (ioctl(devx->usbfsFile, wait? USBDEVFS_REAPURB: USBDEVFS_REAPURBNDELAY, &urb) != -1) { if (urb) { UsbEndpoint *endpoint; if ((endpoint = usbGetEndpoint(device, urb->endpoint))) { UsbEndpointExtension *eptx = endpoint->extension; if (enqueueItem(eptx->completedRequests, urb)) return 1; logSystemError("USB completed request enqueue"); free(urb); } } else { errno = EAGAIN; } } else { if (wait || (errno != EAGAIN)) logSystemError("USB URB reap"); } } return 0; }
int usbCancelRequest ( UsbDevice *device, void *request ) { UsbDeviceExtension *devx = device->extension; if (usbOpenUsbfsFile(devx)) { int reap = 1; if (ioctl(devx->usbfsFile, USBDEVFS_DISCARDURB, request) == -1) { if (errno == ENODEV) { reap = 0; } else if (errno != EINVAL) { logSystemError("USB URB discard"); } } { struct usbdevfs_urb *urb = request; UsbEndpoint *endpoint; if ((endpoint = usbGetEndpoint(device, urb->endpoint))) { UsbEndpointExtension *eptx = endpoint->extension; int found = 1; while (!deleteItem(eptx->completedRequests, request)) { if (!reap) break; if (!usbReapUrb(device, 0)) { found = 0; break; } } if (found) { free(request); return 1; } logMessage(LOG_ERR, "USB request not found: urb=%p ept=%02X", urb, urb->endpoint); } } } return 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; }
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; }
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; }
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 * usbGetOutputEndpoint (UsbDevice *device, unsigned char endpointNumber) { return usbGetEndpoint(device, endpointNumber|UsbEndpointDirection_Output); }