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; }
int usbClaimInterface ( UsbDevice *device, unsigned char interface ) { UsbDeviceExtension *devx = device->extension; if (usbOpenUsbfsFile(devx)) { int disconnected = 0; while (1) { unsigned int arg = interface; if (ioctl(devx->usbfsFile, USBDEVFS_CLAIMINTERFACE, &arg) != -1) return 1; if (errno != EBUSY) break; if (disconnected) break; if (!usbDisconnectInterface(device, interface)) { errno = EBUSY; break; } disconnected = 1; } logSystemError("USB interface claim"); } return 0; }
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 usbResetDevice (UsbDevice *device) { UsbDeviceExtension *devx = device->extension; if (usbOpenUsbfsFile(devx)) { if (ioctl(devx->usbfsFile, USBDEVFS_RESET, NULL) != -1) return 1; logSystemError("USB device reset"); } return 0; }
ssize_t usbControlTransfer ( UsbDevice *device, uint8_t direction, uint8_t recipient, uint8_t type, uint8_t request, uint16_t value, uint16_t index, void *buffer, uint16_t length, int timeout ) { UsbDeviceExtension *devx = device->extension; if (usbOpenUsbfsFile(devx)) { union { struct usbdevfs_ctrltransfer transfer; UsbSetupPacket setup; } arg; memset(&arg, 0, sizeof(arg)); arg.setup.bRequestType = direction | recipient | type; arg.setup.bRequest = request; putLittleEndian16(&arg.setup.wValue, value); putLittleEndian16(&arg.setup.wIndex, index); putLittleEndian16(&arg.setup.wLength, length); arg.transfer.data = buffer; arg.transfer.timeout = timeout; usbLogSetupPacket(&arg.setup); if (direction == UsbControlDirection_Output) { if (length) logBytes(LOG_CATEGORY(USB_IO), "control output", buffer, length); } { int count = ioctl(devx->usbfsFile, USBDEVFS_CONTROL, &arg); if (count != -1) { if (direction == UsbControlDirection_Input) { logBytes(LOG_CATEGORY(USB_IO), "control input", buffer, length); } return count; } logSystemError("USB control transfer"); } } return -1; }
int usbClearEndpoint (UsbDevice *device, unsigned char endpointAddress) { UsbDeviceExtension *devx = device->extension; if (usbOpenUsbfsFile(devx)) { unsigned int arg = endpointAddress; if (ioctl(devx->usbfsFile, USBDEVFS_CLEAR_HALT, &arg) != -1) return 1; logSystemError("USB endpoint clear"); } return 0; }
int usbReleaseInterface (UsbDevice *device, unsigned char interface) { UsbDeviceExtension *devx = device->extension; logMessage(LOG_CATEGORY(USB_IO), "releasing interface: %u", interface); if (usbOpenUsbfsFile(devx)) { unsigned int arg = interface; if (ioctl(devx->usbfsFile, USBDEVFS_RELEASEINTERFACE, &arg) != -1) return 1; if (errno == ENODEV) return 1; logSystemError("USB interface release"); } return 0; }
int usbSetConfiguration (UsbDevice *device, unsigned char configuration) { UsbDeviceExtension *devx = device->extension; logMessage(LOG_CATEGORY(USB_IO), "setting configuration: %u", configuration); if (usbOpenUsbfsFile(devx)) { unsigned int arg = configuration; if (ioctl(devx->usbfsFile, USBDEVFS_SETCONFIGURATION, &arg) != -1) return 1; logSystemError("USB configuration set"); } 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; }
int usbSetAlternative ( UsbDevice *device, unsigned char interface, unsigned char alternative ) { UsbDeviceExtension *devx = device->extension; if (usbOpenUsbfsFile(devx)) { struct usbdevfs_setinterface arg; memset(&arg, 0, sizeof(arg)); arg.interface = interface; arg.altsetting = alternative; if (ioctl(devx->usbfsFile, USBDEVFS_SETINTERFACE, &arg) != -1) return 1; logSystemError("USB alternative set"); } return 0; }
static char * usbGetDriver (UsbDevice *device, unsigned char interface) { UsbDeviceExtension *devx = device->extension; if (usbOpenUsbfsFile(devx)) { struct usbdevfs_getdriver arg; memset(&arg, 0, sizeof(arg)); arg.interface = interface; if (ioctl(devx->usbfsFile, USBDEVFS_GETDRIVER, &arg) != -1) { char *name = strdup(arg.driver); if (name) return name; logMallocError(); } else { logSystemError("USB get driver name"); } } return NULL; }
static int usbControlDriver ( UsbDevice *device, unsigned char interface, int code, void *data ) { UsbDeviceExtension *devx = device->extension; if (usbOpenUsbfsFile(devx)) { struct usbdevfs_ioctl arg; memset(&arg, 0, sizeof(arg)); arg.ifno = interface; arg.ioctl_code = code; arg.data = data; if (ioctl(devx->usbfsFile, USBDEVFS_IOCTL, &arg) != -1) return 1; logSystemError("USB driver control"); } return 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; }