// Implements all the control transfers that are required by D1 of the // ACM descriptor bmCapabilities, (USBPSTN1.20 Table 4). void usbCallbackSetupHandler() { if ((usbSetupPacket.bmRequestType & 0x7F) != 0x21) // Require Type==Class and Recipient==Interface. return; if (!(usbSetupPacket.wIndex == CDC_CONTROL_INTERFACE_NUMBER || usbSetupPacket.wIndex == CDC_DATA_INTERFACE_NUMBER)) return; switch(usbSetupPacket.bRequest) { case ACM_REQUEST_SET_LINE_CODING: // SetLineCoding (USBPSTN1.20 Section 6.3.10 SetLineCoding) usbControlWrite(sizeof(usbComLineCoding), (uint8 XDATA *)&usbComLineCoding); break; case ACM_REQUEST_GET_LINE_CODING: // GetLineCoding (USBPSTN1.20 Section 6.3.11 GetLineCoding) usbControlRead(sizeof(usbComLineCoding), (uint8 XDATA *)&usbComLineCoding); break; case ACM_REQUEST_SET_CONTROL_LINE_STATE: // SetControlLineState (USBPSTN1.20 Section 6.3.12 SetControlLineState) usbComControlLineState = usbSetupPacket.wValue; usbControlAcknowledge(); if(pLineStateChangeCallback) pLineStateChangeCallback(usbComControlLineState); break; } }
const UsbConfigurationDescriptor * usbConfigurationDescriptor ( UsbDevice *device ) { if (!device->configuration) { unsigned char current; if (device->descriptor.bNumConfigurations < 2) { current = 1; } else if (!usbGetConfiguration(device, ¤t)) { current = 0; } if (current) { UsbDescriptor descriptor; unsigned char number; for (number=0; number<device->descriptor.bNumConfigurations; number++) { int size = usbGetDescriptor(device, UsbDescriptorType_Configuration, number, 0, &descriptor, 1000); if (size == -1) { logMessage(LOG_WARNING, "USB configuration descriptor not readable: %d", number); } else if (descriptor.configuration.bConfigurationValue == current) { break; } } if (number < device->descriptor.bNumConfigurations) { int length = getLittleEndian16(descriptor.configuration.wTotalLength); UsbDescriptor *descriptors; if ((descriptors = malloc(length))) { ssize_t size; if (length > sizeof(descriptor)) { size = usbControlRead(device, UsbControlRecipient_Device, UsbControlType_Standard, UsbStandardRequest_GetDescriptor, (UsbDescriptorType_Configuration << 8) | number, 0, descriptors, length, 1000); } else { memcpy(descriptors, &descriptor, (size = length)); } if (size != -1) { device->configuration = &descriptors->configuration; } else { free(descriptors); } } else { logSystemError("USB configuration descriptor allocate"); } } else { logMessage(LOG_ERR, "USB configuration descriptor not found: %d", current); } } } return device->configuration; }
static int usbGetParameters_CDC_ACM (UsbDevice *device, uint8_t request, uint16_t value, void *data, uint16_t size) { ssize_t result = usbControlRead(device, UsbControlRecipient_Interface, UsbControlType_Class, request, value, device->serial.data->interface->bInterfaceNumber, data, size, 1000); return result != -1; }
static ssize_t askUsbResource ( GioHandle *handle, uint8_t recipient, uint8_t type, uint8_t request, uint16_t value, uint16_t index, void *buffer, uint16_t size, int timeout ) { UsbChannel *channel = handle->channel; return usbControlRead(channel->device, recipient, type, request, value, index, buffer, size, timeout); }
int usbGetConfiguration ( UsbDevice *device, unsigned char *configuration ) { ssize_t size = usbControlRead(device, UsbControlRecipient_Device, UsbControlType_Standard, UsbStandardRequest_GetConfiguration, 0, 0, configuration, sizeof(*configuration), 1000); if (size != -1) return 1; logMessage(LOG_WARNING, "USB standard request not supported: get configuration"); return 0; }
ssize_t usbGetDescriptor ( UsbDevice *device, unsigned char type, unsigned char number, unsigned int index, UsbDescriptor *descriptor, int timeout ) { return usbControlRead(device, UsbControlRecipient_Device, UsbControlType_Standard, UsbStandardRequest_GetDescriptor, (type << 8) | number, index, descriptor->bytes, sizeof(descriptor->bytes), timeout); }
ssize_t usbHidGetFeature ( UsbDevice *device, unsigned char interface, unsigned char report, void *buffer, uint16_t length, int timeout ) { return usbControlRead(device, UsbControlRecipient_Interface, UsbControlType_Class, UsbHidRequest_GetReport, (UsbHidReportType_Feature << 8) | report, interface, buffer, length, timeout); }
static FLStatus getStatus(struct FLContext *handle, uint8 *statusBuffer, const char **error) { FLStatus retVal = FL_SUCCESS; USBStatus uStatus = usbControlRead( handle->device, CMD_MODE_STATUS, // bRequest 0x0000, // wValue : off 0x0000, // wMask statusBuffer, 16, // wLength 1000, // timeout (ms) error ); CHECK_STATUS(uStatus, FL_PROTOCOL_ERR, cleanup, "getStatus()"); cleanup: return retVal; }
ssize_t usbHidGetItems ( UsbDevice *device, unsigned char interface, unsigned char number, unsigned char **items, int timeout ) { const UsbHidDescriptor *hid = usbHidDescriptor(device); if (hid) { if (number < hid->bNumDescriptors) { const UsbClassDescriptor *descriptor = &hid->descriptors[number]; uint16_t length = getLittleEndian16(descriptor->wDescriptorLength); void *buffer = malloc(length); if (buffer) { ssize_t result = usbControlRead(device, UsbControlRecipient_Interface, UsbControlType_Standard, UsbStandardRequest_GetDescriptor, (descriptor->bDescriptorType << 8) | interface, number, buffer, length, timeout); if (result != -1) { *items = buffer; return result; } free(buffer); } else { logMallocError(); } } else { logMessage(LOG_WARNING, "USB report descriptor not found: %u[%u]", interface, number); } } return -1; }
// usbStandardDeviceRequestHandler(): Implementation of USB2.0 Section 9.4, Standard Device Requests. // This function gets called whenever we receive a SETUP packet on endpoint zero with the requestType // field set to STANDARD. This function reads the SETUP packet and uses that to set the control // transfer state variables with all the information needed to respond to the request. // Assumption: controlTransferState is CONTROL_TRANSFER_STATE_NONE when this function is called. static void usbStandardDeviceRequestHandler() { // Prepare a convenient two-byte buffer for sending 1 or 2 byte responses. static XDATA uint8 response[2]; response[0] = 0; response[1] = 0; // Now we decide how to handle the new setup packet. There are several possibilities: // * Invalid: The SETUP packet had a problem with it, or we don't support the feature, // so we need to STALL the next transaction to indicate an request error to the host. // * Control Read: We must send some data to the computer, so we need to decide // where the data is coming from (address, plus RAM/ROM selection) // * Control Write with no data phase: We need to prepare for the status phase, where // our device must send a zero-length EP0 IN packet to indicate success. // * Control Write with data phase: The computer will send data to us, and we need to // decide where in RAM to put it. (No standard device requests use this type, // so ignore this case.) switch(usbSetupPacket.bRequest) { case USB_REQUEST_GET_DESCRIPTOR: // USB Spec 9.4.3 Get Descriptor { switch(usbSetupPacket.wValue >> 8) { case USB_DESCRIPTOR_TYPE_DEVICE: { controlTransferPointer = (uint8 XDATA *)&usbDeviceDescriptor; controlTransferBytesLeft = sizeof(USB_DESCRIPTOR_DEVICE); break; } case USB_DESCRIPTOR_TYPE_CONFIGURATION: { if ((usbSetupPacket.wValue & 0xFF) != 0) { // Invalid configuration index. return; } // The configuration descriptor has an application-dependent size, which // we determine by reading the 3rd and 4th byte. controlTransferPointer = (uint8 XDATA *)usbConfigurationDescriptor; controlTransferBytesLeft = *(uint16 *)&usbConfigurationDescriptor[2]; break; } case USB_DESCRIPTOR_TYPE_STRING: { if ((usbSetupPacket.wValue & 0xFF) >= usbStringDescriptorCount) { // This is either an invalid string index or it is 0xEE, // which is defined by Microsoft OS Descriptors 1.0. // This library provides no features for handling such requests, // but we call the user's callback in case they want to. usbCallbackClassDescriptorHandler(); return; } controlTransferPointer = (uint8 XDATA *)usbStringDescriptors[usbSetupPacket.wValue & 0xFF]; controlTransferBytesLeft = controlTransferPointer[0]; break; } default: { // see if the class recognizes the descriptor type; it should call usbControlRead if it does usbCallbackClassDescriptorHandler(); if (controlTransferState == CONTROL_TRANSFER_STATE_NONE) { // unknown type of descriptor return; } break; } } controlTransferState = CONTROL_TRANSFER_STATE_READ; return; } case USB_REQUEST_SET_ADDRESS: // USB Spec, 9.4.6 Set Address { // Get ready to set the address when the status phase is complete. // We always set the most siginificant bit, because .device_address might be 0 // and that is a valid request, meaning we should revert to address 0. //pendingDeviceAddress = (usbSetupPacket.wValue & 0xFF) | 0x80; USBADDR = (uint8)usbSetupPacket.wValue; usbDeviceState = ((uint8)usbSetupPacket.wValue) ? USB_STATE_ADDRESS : USB_STATE_DEFAULT; // Get ready to provide a handshake. usbControlAcknowledge(); return; } case USB_REQUEST_SET_CONFIGURATION: // USB Spec, 9.4.7 Set Configuration { // Assumption: there is only one configuration and its value is 1. switch(usbSetupPacket.wValue) { case 0: { // We have been deconfigured. // TODO: Add resetNonzeroEndpoints() and call it here. if (usbDeviceState > USB_STATE_ADDRESS) { usbDeviceState = USB_STATE_ADDRESS; } break; } case 1: { // The device has been configured. This is normal operating // state of a USB device. We can now start using non-zero // endpoints. usbDeviceState = USB_STATE_CONFIGURED; usbCallbackInitEndpoints(); break; } default: { // Invalid configuration value, so STALL. return; } } // Get ready to provide a handshake. usbControlAcknowledge(); return; } case USB_REQUEST_GET_CONFIGURATION: // USB Spec 9.4.2 Get Configuration { // Assumption: there is only one configuration and its value is 1. response[0] = (usbDeviceState == USB_STATE_CONFIGURED) ? 1 : 0; usbControlRead(1, response); return; } case USB_REQUEST_GET_INTERFACE: // USB Spec 9.4.4 Get Interface { // Assumption: the "alternate setting number" of each interface // is zero and there are no alternate settings. // Assumption: interface numbers go from 0 to // config->interface_count-1, with no gaps. if (usbDeviceState < USB_STATE_CONFIGURED) { // Invalid request because we have not reached the configured state. return; } if (usbSetupPacket.wIndex >= ((USB_DESCRIPTOR_CONFIGURATION *)&usbConfigurationDescriptor)->bNumInterfaces) { // Invalid index: there is no such interface. return; } // Send a single-byte response of "0". // Assumption: response[0] == 0 usbControlRead(1, response); return; } case USB_REQUEST_GET_STATUS: // USB Spec 9.4.5 Get Status { switch(usbSetupPacket.recipient) { case USB_RECIPIENT_DEVICE: { // See USB Spec Table 9-4. response[0] = vinPowerPresent() ? 1 : 0; // Assumption: response[1] == 0 usbControlRead(2, response); return; } case USB_RECIPIENT_INTERFACE: { if (usbDeviceState < USB_STATE_CONFIGURED && usbSetupPacket.wIndex != 0) { // It is invalid to ask about interfaces other than 0 before the // configured state. return; } if (usbSetupPacket.wIndex >= ((USB_DESCRIPTOR_CONFIGURATION *)&usbConfigurationDescriptor)->bNumInterfaces) { // Invalid index: there is no such interface. return; } // Send a 2-byte response of 0,0 (all of the bits are reserved) // Assumption: response[0] == 0 and response[1] == 0 usbControlRead(2, response); return; } case USB_RECIPIENT_ENDPOINT: { if ((usbSetupPacket.wValue & 15) == 0) { // We don't support the halt feature on Endpoint 0 // (the USB Spec does not require or recommend it). return; } if (usbDeviceState < USB_STATE_CONFIGURED) { // It is invalid to ask about non-zero endpoints before // the configured state. return; } // Assumption: We don't have a USB halt feature, i.e. we // don't stall on non-zero endpoints. // Send a 2-byte response of 0,0. // Assumption: response[0] == 0 and response[1] == 0 usbControlRead(2, response); return; } } return; } // Here are some more standard device requests we would need // to be USB compliant. We didn't use them yet on any of our // PIC devices and it has not caused a problem as far as I // know. We pay lip service to them here just in case they are // needed by some future driver. case USB_REQUEST_SET_FEATURE: case USB_REQUEST_CLEAR_FEATURE: { // Acknowledge the request but don't do anything. usbControlAcknowledge(); return; } case USB_REQUEST_SYNCH_FRAME: { // Send a two-byte response of 0,0. usbControlRead(2, response); return; } } }
static int readDevice (unsigned char request, void *buffer, int length) { return usbControlRead(usbChannel->device, MT_REQUEST_RECIPIENT, MT_REQUEST_TYPE, request, 0, 0, buffer, length, MT_REQUEST_TIMEOUT); }