/*! * @brief Handle set current configuration request. * * This function is used to handle set current configuration request. * * @param handle The device handle. It equals the value returned from USB_DeviceInit. * @param setup The pointer of the setup packet. * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. * @param length It is an out parameter, the data length. * * @retval kStatus_USB_Success The requst is handled successfully. * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, * or, the request is unsupported. */ static usb_status_t USB_DeviceCh9SetConfiguration(usb_device_common_class_struct_t *classHandle, usb_setup_struct_t *setup, uint8_t **buffer, uint32_t *length) { uint8_t state; USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state)) { return kStatus_USB_InvalidRequest; } /* The device state is changed to kUSB_DeviceStateConfigured */ state = kUSB_DeviceStateConfigured; USB_DeviceSetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); if (!setup->wValue) { /* If the new configuration is zero, the device state is changed to kUSB_DeviceStateAddress */ state = kUSB_DeviceStateAddress; USB_DeviceSetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); } /* Notify the class layer the configuration is changed */ USB_DeviceClassEvent(classHandle->handle, kUSB_DeviceClassEventSetConfiguration, &setup->wValue); /* Notify the application the configuration is changed */ return USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventSetConfiguration, &setup->wValue); }
/*! * @brief Handle the common class callback. * * This function handles the common class callback. * * @param handle The device handle, got from the USB_DeviceInit. * @param event The event codes. Please refer to the enumeration usb_device_event_t. * @param param The param type is determined by the event code. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceClassCallback(usb_device_handle handle, uint32_t event, void *param) { usb_device_common_class_struct_t *classHandle; usb_status_t error = kStatus_USB_Error; /* Get the common class handle according to the device handle. */ error = USB_DeviceClassGetHandleByDeviceHandle(handle, &classHandle); if (kStatus_USB_Success != error) { return error; } if (kUSB_DeviceEventBusReset == event) { /* Initialize the control pipes */ USB_DeviceControlPipeInit(handle, classHandle); /* Notify the classes the USB bus reset signal detected. */ USB_DeviceClassEvent(handle, kUSB_DeviceClassEventDeviceReset, classHandle); } /* Call the application device callback function. */ error = classHandle->configList->deviceCallback(handle, event, param); return error; }
/*! * @brief Handle set the alternate setting of a interface request. * * This function is used to handle set the alternate setting of a interface request. * * @param handle The device handle. It equals the value returned from USB_DeviceInit. * @param setup The pointer of the setup packet. * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. * @param length It is an out parameter, the data length. * * @retval kStatus_USB_Success The requst is handled successfully. * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, * or, the request is unsupported. */ static usb_status_t USB_DeviceCh9SetInterface(usb_device_common_class_struct_t *classHandle, usb_setup_struct_t *setup, uint8_t **buffer, uint32_t *length) { uint8_t state; USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); if (state != kUSB_DeviceStateConfigured) { return kStatus_USB_InvalidRequest; } classHandle->standardTranscationBuffer = ((setup->wIndex & 0xFFU) << 8U) | (setup->wValue & 0xFFU); /* Notify the class driver the alternate setting of the interface is changed. */ /* The Bit[15~8] is used to save the interface index, and the alternate setting is saved in Bit[7~0]. */ USB_DeviceClassEvent(classHandle->handle, kUSB_DeviceClassEventSetInterface, &classHandle->standardTranscationBuffer); /* Notify the application the alternate setting of the interface is changed. */ /* The Bit[15~8] is used to save the interface index, and the alternate setting will is saved in Bit[7~0]. */ return USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventSetInterface, &classHandle->standardTranscationBuffer); }
/*! * @brief Control endpoint callback function. * * This callback function is used to notify uplayer the tranfser result of a transfer. * This callback pointer is passed when a sepcified endpoint initialied by calling API USB_DeviceInitEndpoint. * * @param handle The device handle. It equals the value returned from USB_DeviceInit. * @param message The result of a transfer, includes transfer buffer, transfer length and whether is in setup * phase for control pipe. * @param callbackParam The paramter for this callback. It is same with * usb_device_endpoint_callback_struct_t::callbackParam. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceControlCallback(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, void *callbackParam) { usb_setup_struct_t *deviceSetup; usb_device_common_class_struct_t *classHandle; uint8_t *buffer = (uint8_t *)NULL; uint32_t length = 0U; usb_status_t error = kStatus_USB_InvalidRequest; uint8_t state; if ((0xFFFFFFFFU == message->length) || (NULL == callbackParam)) { return error; } classHandle = (usb_device_common_class_struct_t *)callbackParam; deviceSetup = (usb_setup_struct_t *)&classHandle->setupBuffer[0]; USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); if (message->isSetup) { if ((USB_SETUP_PACKET_SIZE != message->length) || (NULL == message->buffer)) { /* If a invalid setup is received, the control pipes should be de-init and init again. * Due to the IP can not meet this require, it is revesed for feature. */ /* USB_DeviceDeinitEndpoint(handle, USB_CONTROL_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); USB_DeviceDeinitEndpoint(handle, USB_CONTROL_ENDPOINT | (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); USB_DeviceControlPipeInit(handle, callbackParam); */ return error; } /* Receive a setup request */ usb_setup_struct_t *setup = (usb_setup_struct_t *)(message->buffer); /* Copy the setup packet to the application buffer */ deviceSetup->wValue = USB_SHORT_FROM_LITTLE_ENDIAN(setup->wValue); deviceSetup->wIndex = USB_SHORT_FROM_LITTLE_ENDIAN(setup->wIndex); deviceSetup->wLength = USB_SHORT_FROM_LITTLE_ENDIAN(setup->wLength); deviceSetup->bRequest = setup->bRequest; deviceSetup->bmRequestType = setup->bmRequestType; if ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_MASK) == USB_REQUEST_TYPE_TYPE_STANDARD) { /* Handle the standard request */ if (s_UsbDeviceStandardRequest[deviceSetup->bRequest] != (usb_standard_request_callback_t)NULL) { error = s_UsbDeviceStandardRequest[deviceSetup->bRequest](classHandle, deviceSetup, &buffer, &length); } } else { if ((deviceSetup->wLength) && ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT)) { /* Class or vendor request with the OUT data phase. */ if ((deviceSetup->wLength) && ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_CLASS) == USB_REQUEST_TYPE_TYPE_CLASS)) { /* Get data buffer to receive the data from the host. */ usb_device_control_request_struct_t controlRequest; controlRequest.buffer = (uint8_t *)NULL; controlRequest.isSetup = 1U; controlRequest.setup = deviceSetup; controlRequest.length = deviceSetup->wLength; error = USB_DeviceClassEvent(handle, kUSB_DeviceClassEventClassRequest, &controlRequest); length = controlRequest.length; buffer = controlRequest.buffer; } else if ((deviceSetup->wLength) && ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_VENDOR) == USB_REQUEST_TYPE_TYPE_VENDOR)) { /* Get data buffer to receive the data from the host. */ usb_device_control_request_struct_t controlRequest; controlRequest.buffer = (uint8_t *)NULL; controlRequest.isSetup = 1U; controlRequest.setup = deviceSetup; controlRequest.length = deviceSetup->wLength; error = USB_DeviceClassCallback(handle, kUSB_DeviceEventVendorRequest, &controlRequest); length = controlRequest.length; buffer = controlRequest.buffer; } else { } if (kStatus_USB_Success == error) { /* Prime an OUT transfer */ error = USB_DeviceRecvRequest(handle, USB_CONTROL_ENDPOINT, buffer, deviceSetup->wLength); return error; } } else { /* Class or vendor request with the IN data phase. */ if (((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_CLASS) == USB_REQUEST_TYPE_TYPE_CLASS)) { /* Get data buffer to response the host. */ usb_device_control_request_struct_t controlRequest; controlRequest.buffer = (uint8_t *)NULL; controlRequest.isSetup = 1U; controlRequest.setup = deviceSetup; controlRequest.length = deviceSetup->wLength; error = USB_DeviceClassEvent(handle, kUSB_DeviceClassEventClassRequest, &controlRequest); length = controlRequest.length; buffer = controlRequest.buffer; } else if (((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_VENDOR) == USB_REQUEST_TYPE_TYPE_VENDOR)) { /* Get data buffer to response the host. */ usb_device_control_request_struct_t controlRequest; controlRequest.buffer = (uint8_t *)NULL; controlRequest.isSetup = 1U; controlRequest.setup = deviceSetup; controlRequest.length = deviceSetup->wLength; error = USB_DeviceClassCallback(handle, kUSB_DeviceEventVendorRequest, &controlRequest); length = controlRequest.length; buffer = controlRequest.buffer; } else { } } } /* Send the reponse to the host. */ error = USB_DeviceControlCallbackFeedback(handle, deviceSetup, error, kUSB_DeviceControlPipeSetupStage, &buffer, &length); } else if (kUSB_DeviceStateAddressing == state) { /* Set the device address to controller. */ error = s_UsbDeviceStandardRequest[deviceSetup->bRequest](classHandle, deviceSetup, &buffer, &length); } #if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) && \ (defined(USB_DEVICE_CONFIG_EHCI_TEST_MODE) && (USB_DEVICE_CONFIG_EHCI_TEST_MODE > 0U)) else if (kUSB_DeviceStateTestMode == state) { uint8_t portTestControl = (uint8_t)(deviceSetup->wIndex >> 8); /* Set the controller.into test mode. */ error = USB_DeviceSetStatus(handle, kUSB_DeviceStatusTestMode, &portTestControl); }
/*! * @brief Handle set or clear device feature request. * * This function is used to handle set or clear device feature request. * * @param handle The device handle. It equals the value returned from USB_DeviceInit. * @param setup The pointer of the setup packet. * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. * @param length It is an out parameter, the data length. * * @retval kStatus_USB_Success The requst is handled successfully. * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, * or, the request is unsupported. */ static usb_status_t USB_DeviceCh9SetClearFeature(usb_device_common_class_struct_t *classHandle, usb_setup_struct_t *setup, uint8_t **buffer, uint32_t *length) { usb_status_t error = kStatus_USB_InvalidRequest; uint8_t state; uint8_t isSet = 0U; USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state)) { return error; } /* Identify the request is set or clear the feature. */ if (USB_REQUEST_STANDARD_SET_FEATURE == setup->bRequest) { isSet = 1U; } if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_DEVICE) { /* Set or Clear the device featrue. */ if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP == setup->wValue) { /* Set or Clear the device remote wakeup featrue. */ error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventSetRemoteWakeup, &isSet); } #if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) && \ (defined(USB_DEVICE_CONFIG_EHCI_TEST_MODE) && (USB_DEVICE_CONFIG_EHCI_TEST_MODE > 0U)) else if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_TEST_MODE == setup->wValue) { state = kUSB_DeviceStateTestMode; error = USB_DeviceSetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); } #endif else { } } else if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) { /* Set or Clear the endpoint featrue. */ if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT == setup->wValue) { if (USB_CONTROL_ENDPOINT == (setup->wIndex & USB_ENDPOINT_NUMBER_MASK)) { /* Set or Clear the control endpoint status(halt or not). */ if (isSet) { USB_DeviceStallEndpoint(classHandle->handle, (uint8_t)setup->wIndex); } else { USB_DeviceUnstallEndpoint(classHandle->handle, (uint8_t)setup->wIndex); } } /* Set or Clear the endpoint status featrue. */ if (isSet) { error = USB_DeviceClassEvent(classHandle->handle, kUSB_DeviceClassEventSetEndpointHalt, &setup->wIndex); } else { error = USB_DeviceClassEvent(classHandle->handle, kUSB_DeviceClassEventClearEndpointHalt, &setup->wIndex); } } else { } } else { } return error; }