//! This function manages the CLEAR FEATURE request. //! void usb_clear_feature(void) { U8 wValue; U8 wIndex; switch (bmRequestType) { #if (USB_REMOTE_WAKEUP_FEATURE == true) case USB_SETUP_SET_STAND_DEVICE: wValue = Usb_read_endpoint_data(EP_CONTROL, 8); if (wValue != FEATURE_DEVICE_REMOTE_WAKEUP) break; // Invalid request device_status &= ~USB_DEV_STATUS_REMOTEWAKEUP; remote_wakeup_feature = false; Usb_ack_setup_received_free(); Usb_ack_control_in_ready_send(); return; #endif case USB_SETUP_SET_STAND_INTERFACE: break; case USB_SETUP_SET_STAND_ENDPOINT: wValue = Usb_read_endpoint_data(EP_CONTROL, 8); if (wValue != FEATURE_ENDPOINT_HALT) break; Usb_read_endpoint_data(EP_CONTROL, 8); //!< dummy read (MSB of wValue) wIndex = Usb_read_endpoint_data(EP_CONTROL, 8); wIndex = Get_desc_ep_nbr(wIndex); if (!Is_usb_endpoint_enabled(wIndex)) break; if (wIndex != EP_CONTROL) { Usb_disable_stall_handshake(wIndex); Usb_reset_endpoint(wIndex); Usb_reset_data_toggle(wIndex); } Usb_ack_setup_received_free(); Usb_ack_control_in_ready_send(); return; default: break; } Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); }
//! This function manages the CLEAR FEATURE request. //! void usb_clear_feature(void) { U8 wValue; U8 wIndex; if (bmRequestType == DEVICE_TYPE || bmRequestType == INTERFACE_TYPE) { //!< keep that order (set StallRq/clear RxSetup) or a //!< OUT request following the SETUP may be acknowledged Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); } else if (bmRequestType == ENDPOINT_TYPE) { wValue = Usb_read_endpoint_data(EP_CONTROL, 8); if (wValue == FEATURE_ENDPOINT_HALT) { Usb_read_endpoint_data(EP_CONTROL, 8); //!< dummy read (MSB of wValue) wIndex = Usb_read_endpoint_data(EP_CONTROL, 8); wIndex = Get_desc_ep_nbr(wIndex); if (Is_usb_endpoint_enabled(wIndex)) { if (wIndex != EP_CONTROL) { Usb_disable_stall_handshake(wIndex); Usb_reset_endpoint(wIndex); Usb_reset_data_toggle(wIndex); } endpoint_status[wIndex] = 0; // Halt feature flag Usb_ack_setup_received_free(); Usb_ack_control_in_ready_send(); } else { Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); } } else { Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); } } }
//! This function manages the GET STATUS request. The device, interface or //! endpoint status is returned. //! void usb_get_status(void) { U8 wIndex; switch (bmRequestType) { case REQUEST_DEVICE_STATUS: Usb_ack_setup_received_free(); Usb_reset_endpoint_fifo_access(EP_CONTROL); Usb_write_endpoint_data(EP_CONTROL, 8, device_status); break; case REQUEST_INTERFACE_STATUS: Usb_ack_setup_received_free(); Usb_reset_endpoint_fifo_access(EP_CONTROL); Usb_write_endpoint_data(EP_CONTROL, 8, INTERFACE_STATUS); break; case REQUEST_ENDPOINT_STATUS: Usb_read_endpoint_data(EP_CONTROL, 16); //!< dummy read (wValue) wIndex = Usb_read_endpoint_data(EP_CONTROL, 8); wIndex = Get_desc_ep_nbr(wIndex); Usb_ack_setup_received_free(); Usb_reset_endpoint_fifo_access(EP_CONTROL); Usb_write_endpoint_data(EP_CONTROL, 8, Is_usb_endpoint_stall_requested(wIndex) ); break; default: Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); return; } Usb_write_endpoint_data(EP_CONTROL, 8, 0x00); Usb_ack_control_in_ready_send(); while (!Is_usb_control_out_received()); Usb_ack_control_out_received_free(); }
//! This function manages the SET FEATURE request. The USB test modes are //! supported by this function. //! void usb_set_feature(void) { U16 wValue = usb_format_usb_to_mcu_data(16, Usb_read_endpoint_data(EP_CONTROL, 16)); U16 wIndex = usb_format_usb_to_mcu_data(16, Usb_read_endpoint_data(EP_CONTROL, 16)); U16 wLength = usb_format_usb_to_mcu_data(16, Usb_read_endpoint_data(EP_CONTROL, 16)); if (wLength) goto unsupported_request; if (bmRequestType==USB_SETUP_SET_STAND_DEVICE) { #if (USB_REMOTE_WAKEUP_FEATURE == true) if (FEATURE_DEVICE_REMOTE_WAKEUP == wValue) { device_status |= USB_DEV_STATUS_REMOTEWAKEUP; remote_wakeup_feature = true; Usb_ack_setup_received_free(); Usb_ack_control_in_ready_send(); return; } #endif goto unsupported_request; } switch (wValue) { case FEATURE_ENDPOINT_HALT: wIndex = Get_desc_ep_nbr(wIndex); // clear direction flag if (bmRequestType != ENDPOINT_TYPE || wIndex == EP_CONTROL || !Is_usb_endpoint_enabled(wIndex)) goto unsupported_request; Usb_enable_stall_handshake(wIndex); Usb_ack_setup_received_free(); Usb_ack_control_in_ready_send(); break; #if (USB_HIGH_SPEED_SUPPORT==true) case FEATURE_TEST_MODE: if (bmRequestType != DEVICE_TYPE || wIndex & 0x00FF) goto unsupported_request; switch (wIndex >> 8) { case TEST_J: Usb_ack_setup_received_free(); Usb_ack_control_in_ready_send(); while (!Is_usb_control_in_ready()); Wr_bitfield(AVR32_USBB_udcon, AVR32_USBB_UDCON_SPDCONF_MASK, 2); Set_bits(AVR32_USBB_udcon, AVR32_USBB_UDCON_TSTJ_MASK); break; case TEST_K: Usb_ack_setup_received_free(); Usb_ack_control_in_ready_send(); while (!Is_usb_control_in_ready()); Wr_bitfield(AVR32_USBB_udcon, AVR32_USBB_UDCON_SPDCONF_MASK, 2); Set_bits(AVR32_USBB_udcon, AVR32_USBB_UDCON_TSTK_MASK); break; case TEST_SE0_NAK: Usb_ack_setup_received_free(); Usb_ack_control_in_ready_send(); while (!Is_usb_control_in_ready()); Wr_bitfield(AVR32_USBB_udcon, AVR32_USBB_UDCON_SPDCONF_MASK, 2); break; case TEST_PACKET: { static const U8 test_packet[] = { // 00000000 * 9 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 01010101 * 8 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 01110111 * 8 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, // 0, {111111S * 15}, 111111 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // S, 111111S, {0111111S * 7} 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, // 00111111, {S0111111 * 9}, S0 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E }; Usb_ack_setup_received_free(); Usb_ack_control_in_ready_send(); while (!Is_usb_control_in_ready()); Wr_bitfield(AVR32_USBB_udcon, AVR32_USBB_UDCON_SPDCONF_MASK, 2); Usb_disable_endpoint(EP_CONTROL); Usb_unallocate_memory(EP_CONTROL); (void)Usb_configure_endpoint(EP_CONTROL, TYPE_BULK, DIRECTION_IN, 64, SINGLE_BANK); Usb_reset_endpoint(EP_CONTROL); Set_bits(AVR32_USBB_udcon, AVR32_USBB_UDCON_TSTPCKT_MASK); usb_write_ep_txpacket(EP_CONTROL, &test_packet, sizeof(test_packet), NULL); Usb_send_in(EP_CONTROL); } break; case TEST_FORCE_ENABLE: // Only for downstream facing hub ports default: goto unsupported_request; } break; #endif case FEATURE_DEVICE_REMOTE_WAKEUP: default: goto unsupported_request; } return; unsupported_request: Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); }
//! This function checks if the device class is supported. //! The function looks in all interfaces declared in the received descriptors if //! one of them matches an entry of the CLASS/SUB_CLASS/PROTOCOL table. //! If HOST_AUTO_CFG_ENDPOINT is enabled, a pipe is configured for each endpoint //! of supported interfaces. //! //! @return bool: Status //! bool host_check_class(void) { uint8_t *descriptor, *conf_end; uint8_t device_class, device_subclass, device_protocol; uint8_t c; #if HOST_AUTO_CFG_ENDPOINT == ENABLE uint8_t nb_endpoint_to_configure = 0; uint8_t ep_index = 0; uint8_t physical_pipe = P_1; // P_1 because physical pipe 0 is reserved for control uint16_t ep_size; // By default, the host is configured when returning Host_set_configured(); #endif // First, assume no interface is supported nb_interface_supported = 0; // Check if configuration descriptor if (data_stage[OFFSET_FIELD_DESCRIPTOR_TYPE] != CONFIGURATION_DESCRIPTOR) return false; bmattributes = data_stage[OFFSET_FIELD_BMATTRIBUTES]; maxpower = data_stage[OFFSET_FIELD_MAXPOWER]; conf_end = data_stage + min(usb_format_usb_to_mcu_data(16, *(uint16_t *)(data_stage + OFFSET_FIELD_TOTAL_LENGTH)), SIZEOF_DATA_STAGE - OFFSET_FIELD_PROTOCOL); // Look in all interfaces declared in the configuration for (descriptor = data_stage + data_stage[OFFSET_DESCRIPTOR_LENGTH]; descriptor < conf_end; descriptor += descriptor[OFFSET_DESCRIPTOR_LENGTH]) { // Find next interface descriptor switch (descriptor[OFFSET_FIELD_DESCRIPTOR_TYPE]) { case INTERFACE_DESCRIPTOR: // Check the number of supported interfaces does not exceed the maximum if (nb_interface_supported >= MAX_INTERFACE_SUPPORTED) return true; #if HOST_AUTO_CFG_ENDPOINT == ENABLE // If there are still endpoints to configure although a new interface descriptor has been found if (nb_endpoint_to_configure) { // Mark the host as not configured Host_clear_configured(); // Reset the number of endpoints to configure nb_endpoint_to_configure = 0; } #endif // Found an interface descriptor // Get characteristics of this interface device_class = descriptor[OFFSET_FIELD_CLASS]; device_subclass = descriptor[OFFSET_FIELD_SUB_CLASS]; device_protocol = descriptor[OFFSET_FIELD_PROTOCOL]; // Look in registered class table for match for (c = 0; c < REG_CLASS_CNT; c += 3) { if (registered_class[c] == device_class && // Class is correct registered_class[c + 1] == device_subclass && // Subclass is correct registered_class[c + 2] == device_protocol) // Protocol is correct { // Store this interface as supported interface // Memorize its interface nb interface_supported[nb_interface_supported].interface_nb = descriptor[OFFSET_FIELD_INTERFACE_NB]; // its alternate setting interface_supported[nb_interface_supported].altset_nb = descriptor[OFFSET_FIELD_ALT]; // its USB class interface_supported[nb_interface_supported].uclass = device_class; // its USB subclass interface_supported[nb_interface_supported].subclass = device_subclass; // its USB protocol interface_supported[nb_interface_supported].protocol = device_protocol; // the number of endpoints associated with this interface #if HOST_AUTO_CFG_ENDPOINT == ENABLE ep_index = 0; nb_endpoint_to_configure = #endif interface_supported[nb_interface_supported].nb_ep = min(descriptor[OFFSET_FIELD_NB_OF_EP], MAX_EP_PER_INTERFACE); // Update the number of supported interfaces nb_interface_supported++; // Class/subclass/protocol is registered, so look for next interface descriptor break; } } break; #if HOST_AUTO_CFG_ENDPOINT == ENABLE case ENDPOINT_DESCRIPTOR: // If there are still endpoints to configure while there are free pipes if (physical_pipe < MAX_PEP_NB && nb_endpoint_to_configure) { nb_endpoint_to_configure--; // Reconfigure the new physical pipe to get rid of any previous configuration #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE cpu_irq_disable(); #endif Host_disable_pipe(physical_pipe); #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE (void)Is_host_pipe_enabled(physical_pipe); cpu_irq_enable(); #endif Host_unallocate_memory(physical_pipe); Host_enable_pipe(physical_pipe); // Fix HW, set freq at 0 in case of no interrupt endpoint if( TYPE_INTERRUPT != descriptor[OFFSET_FIELD_EP_TYPE] ) descriptor[OFFSET_FIELD_EP_INTERVAL] = 0; ep_size = descriptor[OFFSET_FIELD_EP_SIZE] | descriptor[OFFSET_FIELD_EP_SIZE + 1] << 8; #if BOARD != EVK1104 if (ep_size <= 64) { #endif // Build the pipe configuration according to the endpoint descriptor fields received (void)Host_configure_pipe( physical_pipe, // Pipe nb in USB interface descriptor[OFFSET_FIELD_EP_INTERVAL], // Interrupt period (for interrupt pipe) Get_desc_ep_nbr(descriptor[OFFSET_FIELD_EP_ADDR]), // Pipe endpoint number descriptor[OFFSET_FIELD_EP_TYPE], // Pipe type (isochronous/bulk/interrupt) Get_pipe_token(descriptor[OFFSET_FIELD_EP_ADDR]), // Pipe token (IN/OUT) ep_size, // Pipe size (descriptor[OFFSET_FIELD_EP_TYPE] == TYPE_BULK) ? SINGLE_BANK : DOUBLE_BANK // Number of banks to allocate for pipe ); // Update endpoint pipe table in supported interface structure interface_supported[nb_interface_supported - 1].ep_pipe[ep_index++] = physical_pipe++; } #if BOARD != EVK1104 else { // Build the pipe configuration according to the endpoint descriptor fields received (void)Host_configure_pipe( MAX_PEP_NB - 1, // Pipe nb in USB interface descriptor[OFFSET_FIELD_EP_INTERVAL], // Interrupt period (for interrupt pipe) Get_desc_ep_nbr(descriptor[OFFSET_FIELD_EP_ADDR]), // Pipe endpoint number descriptor[OFFSET_FIELD_EP_TYPE], // Pipe type (isochronous/bulk/interrupt) Get_pipe_token(descriptor[OFFSET_FIELD_EP_ADDR]), // Pipe token (IN/OUT) ep_size, // Pipe size (descriptor[OFFSET_FIELD_EP_TYPE] == TYPE_BULK) ? SINGLE_BANK : DOUBLE_BANK // Number of banks to allocate for pipe ); // Update endpoint pipe table in supported interface structure interface_supported[nb_interface_supported - 1].ep_pipe[ep_index++] = MAX_PEP_NB - 1; } } #endif break; #endif } // Call user callback to look more deeply into the configuration descriptor Host_user_check_class_action(descriptor); } #if HOST_AUTO_CFG_ENDPOINT == ENABLE // If there are still endpoints to configure although all descriptors have been parsed if (nb_endpoint_to_configure) { // Mark the host as not configured Host_clear_configured(); } #endif return (nb_interface_supported > 0); }