//! //! @brief USB Command Block Wrapper (CBW) management //! //! This function decodes the CBW command and stores the SCSI command. //! static void usb_mass_storage_cbw(void) { bool cbw_error; Usb_reset_endpoint_fifo_access(EP_MS_OUT); //! Check if dCBWSignature is correct cbw_error = (Usb_read_endpoint_data(EP_MS_OUT, 32) != *(U32 *)&"USBC"); //! Store CBW Tag to be repeated in CSW dCBWTag = Usb_read_endpoint_data(EP_MS_OUT, 32); g_scsi_data_remaining = Usb_read_endpoint_data(EP_MS_OUT, 32); g_scsi_data_remaining = usb_format_usb_to_mcu_data(32, g_scsi_data_remaining); //! if (bmCBWFlags.bit7 == 1) {direction = IN;} if (Usb_read_endpoint_data(EP_MS_OUT, 8)) { ms_endpoint = EP_MS_IN; if (cbw_error) { Usb_ack_out_received_free(EP_MS_OUT); Usb_enable_stall_handshake(EP_MS_IN); return; } } else { ms_endpoint = EP_MS_OUT; if (cbw_error) { Usb_enable_stall_handshake(EP_MS_OUT); Usb_ack_out_received_free(EP_MS_OUT); return; } } usb_LUN = Usb_read_endpoint_data(EP_MS_OUT, 8); if (!ms_multiple_drive) { usb_LUN = get_cur_lun(); } //! Dummy CBWCBLength read Usb_read_endpoint_data(EP_MS_OUT, 8); //! Store scsi_command usb_read_ep_rxpacket(EP_MS_OUT, g_scsi_command, sizeof(g_scsi_command), NULL); Usb_ack_out_received_free(EP_MS_OUT); // Take the USB Mutex(i.e. we're allowed to perform a ms cmd). /* if( ( pdFALSE == ( xGiveUsbMutex = x_supervisor_SemaphoreTake( xUSBMutex, 0 ) ) ) || ( !scsi_decode_command() && g_scsi_data_remaining ) ) */ if( ( pdFALSE == (xGiveUsbMutex = x_supervisor_SemaphoreTake( xUSBMutex, 0 ) ) ) || ( !scsi_decode_command() && g_scsi_data_remaining ) ) { Usb_enable_stall_handshake(ms_endpoint); } }
// ! // ! @brief USB Command Block Wrapper (CBW) management // ! // ! This function decodes the CBW command and stores the SCSI command. // ! static void usb_mass_storage_cbw (void) { Bool cbw_error; Usb_reset_endpoint_fifo_access (EP_MS_OUT); // ! Check if dCBWSignature is correct cbw_error = (Usb_read_endpoint_data (EP_MS_OUT, 32) != *(U32 *) & "USBC"); // ! Store CBW Tag to be repeated in CSW dCBWTag = Usb_read_endpoint_data (EP_MS_OUT, 32); g_scsi_data_remaining = Usb_read_endpoint_data (EP_MS_OUT, 32); g_scsi_data_remaining = usb_format_usb_to_mcu_data (32, g_scsi_data_remaining); /* Show the remaining bytes { U8 Text_u8[20]; CI_StringOut (" - "); itoa ((S32)g_scsi_data_remaining,Text_u8); CI_StringOut (Text_u8); CI_StringOut (" - "); } */ // ! if (bmCBWFlags.bit7 == 1) {direction = IN;} if (Usb_read_endpoint_data (EP_MS_OUT, 8)) { ms_endpoint = EP_MS_IN; if (cbw_error) { Usb_ack_out_received_free (EP_MS_OUT); Usb_enable_stall_handshake (EP_MS_IN); return; } } else { ms_endpoint = EP_MS_OUT; if (cbw_error) { Usb_enable_stall_handshake (EP_MS_OUT); Usb_ack_out_received_free (EP_MS_OUT); return; } } usb_LUN = Usb_read_endpoint_data (EP_MS_OUT, 8); if (!ms_multiple_drive) { usb_LUN = get_cur_lun (); } // ! Dummy CBWCBLength read Usb_read_endpoint_data (EP_MS_OUT, 8); // ! Store scsi_command usb_read_ep_rxpacket (EP_MS_OUT, g_scsi_command, sizeof (g_scsi_command), NULL); Usb_ack_out_received_free (EP_MS_OUT); if (!scsi_decode_command ()) { Usb_enable_stall_handshake (ms_endpoint); } }
//! usb_set_feature. //! //! This function manages the SET FEATURE request. The USB test modes are //! supported by this function. //! //! @warning Code:xx bytes (function code length) //! //! @param none //! //! @return none //! void usb_set_feature(void) { U8 wValue; U8 wIndex; U8 dummy; if (bmRequestType == INTERFACE_TYPE) { //!< keep that order (set StallRq/clear RxSetup) or a //!< OUT request following the SETUP may be acknowledged Usb_enable_stall_handshake(); Usb_ack_receive_setup(); return; } else if (bmRequestType == ENDPOINT_TYPE) { wValue = Usb_read_byte(); dummy = Usb_read_byte(); //!< dummy read if (wValue == FEATURE_ENDPOINT_HALT) { wIndex = (Usb_read_byte() & MSK_EP_DIR); if (wIndex == EP_CONTROL) { Usb_enable_stall_handshake(); Usb_ack_receive_setup(); return; } Usb_select_endpoint(wIndex); if(Is_usb_endpoint_enabled()) { Usb_enable_stall_handshake(); Usb_select_endpoint(EP_CONTROL); endpoint_status[wIndex] = 0x01; Usb_ack_receive_setup(); Usb_send_control_in(); } else { Usb_select_endpoint(EP_CONTROL); Usb_enable_stall_handshake(); Usb_ack_receive_setup(); return; } } else { Usb_enable_stall_handshake(); Usb_ack_receive_setup(); return; } } }
//! usb_set_configuration. //! //! This function manages the SET CONFIGURATION request. If the selected //! configuration is valid, this function call the usb_user_endpoint_init() //! function that will configure the endpoints following the configuration //! number. //! //! @warning Code:xx bytes (function code length) //! //! @param none //! //! @return none //! void usb_set_configuration( void ) { U8 configuration_number; configuration_number = Usb_read_byte(); if (configuration_number <= NB_CONFIGURATION) { Usb_ack_receive_setup(); usb_configuration_nb = configuration_number; } else { //!< keep that order (set StallRq/clear RxSetup) or a //!< OUT request following the SETUP may be acknowledged Usb_enable_stall_handshake(); Usb_ack_receive_setup(); return; } Usb_send_control_in(); //!< send a ZLP for STATUS phase usb_user_endpoint_init(usb_configuration_nb); //!< endpoint configuration Usb_set_configuration_action(); }
//! usb_get_status. //! //! This function manages the GET STATUS request. The device, interface or //! endpoint status is returned. //! //! @warning Code:xx bytes (function code length) //! //! @param none //! //! @return none //! void usb_get_status(void) { U8 wIndex; U8 dummy; dummy = Usb_read_byte(); //!< dummy read dummy = Usb_read_byte(); //!< dummy read wIndex = Usb_read_byte(); switch(bmRequestType) { case REQUEST_DEVICE_STATUS: Usb_ack_receive_setup(); Usb_write_byte(DEVICE_STATUS); break; case REQUEST_INTERFACE_STATUS: Usb_ack_receive_setup(); Usb_write_byte(INTERFACE_STATUS); break; case REQUEST_ENDPOINT_STATUS: Usb_ack_receive_setup(); wIndex = wIndex & MSK_EP_DIR; Usb_write_byte(endpoint_status[wIndex]); break; default: Usb_enable_stall_handshake(); Usb_ack_receive_setup(); return; } Usb_write_byte(0x00); Usb_send_control_in(); while( !Is_usb_receive_out() ); Usb_ack_receive_out(); }
//! 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 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(); }
//! usb_set_feature. //! //! This function manages the SET FEATURE request. The USB test modes are //! supported by this function. //! //! @warning Code:xx bytes (function code length) //! void usb_set_feature(void) { U8 wValue; U8 wIndex; U8 dummy; if (bmRequestType == INTERFACE_TYPE) { return; } else if (bmRequestType == ENDPOINT_TYPE) { wValue = Usb_read_byte(); dummy = Usb_read_byte(); //!< dummy read if (wValue == FEATURE_ENDPOINT_HALT) { wIndex = (Usb_read_byte() & MSK_EP_DIR); if (wIndex == EP_CONTROL) { return; } Usb_select_endpoint(wIndex); if(Is_usb_endpoint_enabled()) { Usb_enable_stall_handshake(); Usb_select_endpoint(EP_CONTROL); endpoint_status[wIndex] = 0x01; Usb_ack_receive_setup(); Usb_send_control_in(); } else { Usb_select_endpoint(EP_CONTROL); return; } } else { return; } } }
//! 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 CONFIGURATION request. If the selected //! configuration is valid, this function call the usb_user_endpoint_init() //! function that will configure the endpoints following the configuration //! number. //! void usb_set_configuration(void) { U8 configuration_number = Usb_read_endpoint_data(EP_CONTROL, 8); U8 u8_i; if (configuration_number <= NB_CONFIGURATION) { Usb_ack_setup_received_free(); usb_configuration_nb = configuration_number; for( u8_i=0; u8_i<NB_INTERFACE; u8_i++) usb_interface_status[u8_i]=0; usb_user_endpoint_init(usb_configuration_nb); //!< endpoint configuration Usb_set_configuration_action(); Usb_ack_control_in_ready_send(); //!< send a ZLP for STATUS phase } else { //!< 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(); } }
//! This function manages the GET DESCRIPTOR request. The device descriptor, //! the configuration descriptor and the device qualifier are supported. All //! other descriptors must be supported by the usb_user_get_descriptor //! function. //! Only 1 configuration is supported. //! void usb_get_descriptor(void) { bool zlp; U16 wLength; U8 descriptor_type; U8 string_type; Union32 temp; #if (USB_HIGH_SPEED_SUPPORT==true) bool b_first_data = true; #endif zlp = false; /* no zero length packet */ string_type = Usb_read_endpoint_data(EP_CONTROL, 8); /* read LSB of wValue */ descriptor_type = Usb_read_endpoint_data(EP_CONTROL, 8); /* read MSB of wValue */ switch (descriptor_type) { case DEVICE_DESCRIPTOR: data_to_transfer = Usb_get_dev_desc_length(); //!< sizeof(usb_dev_desc); pbuffer = Usb_get_dev_desc_pointer(); break; #if (USB_HIGH_SPEED_SUPPORT==false) case CONFIGURATION_DESCRIPTOR: data_to_transfer = Usb_get_conf_desc_length(); //!< sizeof(usb_conf_desc); pbuffer = Usb_get_conf_desc_pointer(); break; #else case CONFIGURATION_DESCRIPTOR: if( Is_usb_full_speed_mode() ) { data_to_transfer = Usb_get_conf_desc_fs_length(); //!< sizeof(usb_conf_desc_fs); pbuffer = Usb_get_conf_desc_fs_pointer(); }else{ data_to_transfer = Usb_get_conf_desc_hs_length(); //!< sizeof(usb_conf_desc_hs); pbuffer = Usb_get_conf_desc_hs_pointer(); } break; case OTHER_SPEED_CONFIGURATION_DESCRIPTOR: if( !Is_usb_full_speed_mode() ) { data_to_transfer = Usb_get_conf_desc_fs_length(); //!< sizeof(usb_conf_desc_fs); pbuffer = Usb_get_conf_desc_fs_pointer(); }else{ data_to_transfer = Usb_get_conf_desc_hs_length(); //!< sizeof(usb_conf_desc_hs); pbuffer = Usb_get_conf_desc_hs_pointer(); } break; case DEVICE_QUALIFIER_DESCRIPTOR: data_to_transfer = Usb_get_qualifier_desc_length(); //!< sizeof(usb_qualifier_desc); pbuffer = Usb_get_qualifier_desc_pointer(); break; #endif default: if (!usb_user_get_descriptor(descriptor_type, string_type)) { Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); return; } break; } temp.u32 = Usb_read_endpoint_data(EP_CONTROL, 32); //!< read wIndex and wLength with a 32-bit access //!< since this access is aligned with a 32-bit //!< boundary from the beginning of the endpoint wLength = usb_format_usb_to_mcu_data(16, temp.u16[1]); //!< ignore wIndex, keep and format wLength Usb_ack_setup_received_free(); //!< clear the setup received flag if (wLength > data_to_transfer) { zlp = !(data_to_transfer % EP_CONTROL_LENGTH); //!< zero length packet condition } else { // No need to test ZLP sending since we send the exact number of bytes as // expected by the host. data_to_transfer = wLength; //!< send only requested number of data bytes } Usb_ack_nak_out(EP_CONTROL); while (data_to_transfer && !Is_usb_nak_out(EP_CONTROL)) { while (!Is_usb_control_in_ready() && !Is_usb_nak_out(EP_CONTROL)); if (Is_usb_nak_out(EP_CONTROL)) break; // don't clear the flag now, it will be cleared after Usb_reset_endpoint_fifo_access(EP_CONTROL); #if (USB_HIGH_SPEED_SUPPORT==true) // To support other descriptors like OTHER_SPEED_CONFIGURATION_DESCRIPTOR if( b_first_data ) { b_first_data = false; if( 0!= data_to_transfer ) { usb_write_ep_txpacket(EP_CONTROL, pbuffer, 1, &pbuffer); data_to_transfer--; } if( 0!= data_to_transfer ) { usb_write_ep_txpacket(EP_CONTROL, &descriptor_type, 1, NULL); pbuffer = ((const U8*)pbuffer)+1; data_to_transfer--; } } #endif if( 0!= data_to_transfer ) { data_to_transfer = usb_write_ep_txpacket(EP_CONTROL, pbuffer, data_to_transfer, &pbuffer); } if (Is_usb_nak_out(EP_CONTROL)) break; Usb_ack_control_in_ready_send(); //!< Send data until necessary } if (zlp && !Is_usb_nak_out(EP_CONTROL)) { while (!Is_usb_control_in_ready()); Usb_ack_control_in_ready_send(); } while (!Is_usb_nak_out(EP_CONTROL)); Usb_ack_nak_out(EP_CONTROL); while (!Is_usb_control_out_received()); Usb_ack_control_out_received_free(); }
//! This function reads the SETUP request sent to the default control endpoint //! and calls the appropriate function. When exiting of the usb_read_request //! function, the device is ready to manage the next request. //! //! If the received request is not supported or a non-standard USB request, the function //! will call the custom decoding function in usb_specific_request module. //! //! @note List of supported requests: //! GET_DESCRIPTOR //! GET_CONFIGURATION //! SET_ADDRESS //! SET_CONFIGURATION //! CLEAR_FEATURE //! SET_FEATURE //! GET_STATUS //! void usb_process_request(void) { U8 bRequest; Usb_reset_endpoint_fifo_access(EP_CONTROL); bmRequestType = Usb_read_endpoint_data(EP_CONTROL, 8); bRequest = Usb_read_endpoint_data(EP_CONTROL, 8); switch (bRequest) { case GET_DESCRIPTOR: if (bmRequestType == 0x80) usb_get_descriptor(); else goto unsupported_request; break; case GET_CONFIGURATION: if (bmRequestType == 0x80) usb_get_configuration(); else goto unsupported_request; break; case SET_ADDRESS: if (bmRequestType == 0x00) usb_set_address(); else goto unsupported_request; break; case SET_CONFIGURATION: if (bmRequestType == 0x00) usb_set_configuration(); else goto unsupported_request; break; case CLEAR_FEATURE: if (bmRequestType <= 0x02) usb_clear_feature(); else goto unsupported_request; break; case SET_FEATURE: if (bmRequestType <= 0x02) usb_set_feature(); else goto unsupported_request; break; case GET_STATUS: if (0x7F < bmRequestType && bmRequestType <= 0x82) usb_get_status(); else goto unsupported_request; break; case GET_INTERFACE: if (bmRequestType == 0x81) { if(!usb_get_interface()) { Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); } } else goto unsupported_request; break; case SET_INTERFACE: if (bmRequestType == 0x01) usb_set_interface(); else goto unsupported_request; break; case SET_DESCRIPTOR: case SYNCH_FRAME: default: //!< unsupported request => call to user read request unsupported_request: if (!usb_user_read_request(bmRequestType, bRequest)) { Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); } break; } }
//! usb_halt_endpoint. //! //! This function sends a STALL handshake for the next Host request. A STALL //! handshake will be send for each next request untill a SETUP or a Clear Halt //! Feature occurs for this endpoint. //! //! @param ep_num number of the addressed endpoint //! //! @return none //! void usb_halt_endpoint (U8 ep_num) { Usb_select_endpoint(ep_num); Usb_enable_stall_handshake(); }
void usb_get_string_descriptor(U8 string_type) { U16 requested_length; U8 dummy; PGM_P user_str; user_str = usb_user_get_string(string_type); if(!user_str) { usb_get_string_descriptor_sram(string_type); return; } dummy = Usb_read_byte(); //!< don't care of wIndex field dummy = Usb_read_byte(); requested_length = Usb_read_byte(); //!< read wLength requested_length |= Usb_read_byte()<<8; const U8 actual_descriptor_size = 2+strlen_P(user_str)*2; if (requested_length > actual_descriptor_size) { zlp = ((actual_descriptor_size % EP_CONTROL_LENGTH) == 0); requested_length = actual_descriptor_size; } Usb_ack_receive_setup() ; //!< clear the receive setup flag if(usb_endpoint_wait_for_read_control_enabled()!=0) { Usb_enable_stall_handshake(); return; } U8 nb_byte = 0; // Output the length if(requested_length) { Usb_write_byte(actual_descriptor_size); requested_length--; nb_byte++; } // Output the type if(requested_length) { Usb_write_byte(STRING_DESCRIPTOR); requested_length--; nb_byte++; } if(!requested_length) { Usb_send_control_in(); } while((requested_length != 0) && (!Is_usb_receive_out())) { if(usb_endpoint_wait_for_read_control_enabled()!=0) { Usb_enable_stall_handshake(); break; } while(requested_length != 0) //!< Send data until necessary { if(nb_byte==EP_CONTROL_LENGTH) { //!< Check endpoint 0 size nb_byte=0; break; } Usb_write_byte(pgm_read_byte_near((unsigned int)user_str++)); requested_length--; nb_byte++; if(requested_length) { Usb_write_byte(0); requested_length--; nb_byte++; } } Usb_send_control_in(); } //bail: if(Is_usb_receive_out()) { //! abort from Host Usb_ack_receive_out(); return; } if(zlp == TRUE) { if(usb_endpoint_wait_for_read_control_enabled()!=0) { Usb_enable_stall_handshake(); return; } Usb_send_control_in(); } usb_endpoint_wait_for_receive_out(); Usb_ack_receive_out(); }
//! This function manages the GET DESCRIPTOR request. The device descriptor, //! the configuration descriptor and the device qualifier are supported. All //! other descriptors must be supported by the usb_user_get_descriptor //! function. //! Only 1 configuration is supported. //! void usb_get_descriptor(void) { Bool zlp; U16 wLength; U8 descriptor_type; U8 string_type; Union32 temp; zlp = FALSE; /* no zero length packet */ string_type = Usb_read_endpoint_data(EP_CONTROL, 8); /* read LSB of wValue */ descriptor_type = Usb_read_endpoint_data(EP_CONTROL, 8); /* read MSB of wValue */ switch (descriptor_type) { case DEVICE_DESCRIPTOR: data_to_transfer = Usb_get_dev_desc_length(); //!< sizeof(usb_dev_desc); pbuffer = Usb_get_dev_desc_pointer(); break; case CONFIGURATION_DESCRIPTOR: data_to_transfer = Usb_get_conf_desc_length(); //!< sizeof(usb_conf_desc); pbuffer = Usb_get_conf_desc_pointer(); break; default: if (!usb_user_get_descriptor(descriptor_type, string_type)) { Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); return; } break; } temp.u32 = Usb_read_endpoint_data(EP_CONTROL, 32); //!< read wIndex and wLength with a 32-bit access //!< since this access is aligned with a 32-bit //!< boundary from the beginning of the endpoint wLength = usb_format_usb_to_mcu_data(16, temp.u16[1]); //!< ignore wIndex, keep and format wLength Usb_ack_setup_received_free(); //!< clear the setup received flag if (wLength > data_to_transfer) { zlp = !(data_to_transfer % EP_CONTROL_LENGTH); //!< zero length packet condition } else { // No need to test ZLP sending since we send the exact number of bytes as // expected by the host. data_to_transfer = (U8)wLength; //!< send only requested number of data bytes } Usb_ack_nak_out(EP_CONTROL); while (data_to_transfer && !Is_usb_nak_out(EP_CONTROL)) { while (!Is_usb_control_in_ready() && !Is_usb_nak_out(EP_CONTROL)); if (Is_usb_nak_out(EP_CONTROL)) break; // don't clear the flag now, it will be cleared after Usb_reset_endpoint_fifo_access(EP_CONTROL); data_to_transfer = usb_write_ep_txpacket(EP_CONTROL, pbuffer, data_to_transfer, &pbuffer); if (Is_usb_nak_out(EP_CONTROL)) break; else Usb_ack_control_in_ready_send(); //!< Send data until necessary } if (zlp && !Is_usb_nak_out(EP_CONTROL)) { while (!Is_usb_control_in_ready()); Usb_ack_control_in_ready_send(); } while (!Is_usb_nak_out(EP_CONTROL)); Usb_ack_nak_out(EP_CONTROL); while (!Is_usb_control_out_received()); Usb_ack_control_out_received_free(); }
//! This function manages the SET INTERFACE request. //! void usb_set_interface(void) { U8 u8_i; // wValue = Alternate Setting // wIndex = Interface 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)); Usb_ack_setup_received_free(); // Get descriptor #if (USB_HIGH_SPEED_SUPPORT==true) if( Is_usb_full_speed_mode() ) { data_to_transfer = Usb_get_conf_desc_fs_length(); //!< sizeof(usb_conf_desc_fs); pbuffer = Usb_get_conf_desc_fs_pointer(); }else{ data_to_transfer = Usb_get_conf_desc_hs_length(); //!< sizeof(usb_conf_desc_hs); pbuffer = Usb_get_conf_desc_hs_pointer(); } #else data_to_transfer = Usb_get_conf_desc_length(); //!< sizeof(usb_conf_desc); pbuffer = Usb_get_conf_desc_pointer(); #endif //** Scan descriptor //* Find configuration selected if( usb_configuration_nb == 0 ) { // No configuration selected then no interface enable Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); return; } u8_i = usb_configuration_nb; while( u8_i != 0 ) { if( CONFIGURATION_DESCRIPTOR != ((S_usb_configuration_descriptor*)pbuffer)->bDescriptorType ) { data_to_transfer -= ((S_usb_configuration_descriptor*)pbuffer)->bLength; pbuffer = (U8*)pbuffer + ((S_usb_configuration_descriptor*)pbuffer)->bLength; continue; } u8_i--; if( u8_i != 0 ) { data_to_transfer -= ((S_usb_configuration_descriptor*)pbuffer)->wTotalLength; pbuffer = (U8*)pbuffer + ((S_usb_configuration_descriptor*)pbuffer)->wTotalLength; } } // Find interface selected if( wIndex >= ((S_usb_configuration_descriptor*)pbuffer)->bNumInterfaces ) { // Interface number unknown Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); return; } while( 1 ) { if( data_to_transfer <= ((S_usb_interface_descriptor*)pbuffer)->bLength ) { // Interface unknown Usb_enable_stall_handshake(EP_CONTROL); Usb_ack_setup_received_free(); return; } data_to_transfer -= ((S_usb_interface_descriptor*)pbuffer)->bLength; pbuffer = (U8*)pbuffer + ((S_usb_interface_descriptor*)pbuffer)->bLength; if( INTERFACE_DESCRIPTOR != ((S_usb_interface_descriptor*)pbuffer)->bDescriptorType ) continue; if( wIndex != ((S_usb_interface_descriptor*)pbuffer)->bInterfaceNumber ) continue; if( wValue != ((S_usb_interface_descriptor*)pbuffer)->bAlternateSetting ) continue; usb_interface_status[wIndex] = wValue; break; } //* Find endpoints of interface and reset it while( 1 ) { if( data_to_transfer <= ((S_usb_endpoint_descriptor*)pbuffer)->bLength ) break; // End of interface data_to_transfer -= ((S_usb_endpoint_descriptor*)pbuffer)->bLength; pbuffer = (U8*)pbuffer + ((S_usb_endpoint_descriptor*)pbuffer)->bLength; if( INTERFACE_DESCRIPTOR == ((S_usb_endpoint_descriptor*)pbuffer)->bDescriptorType ) break; // End of interface if( ENDPOINT_DESCRIPTOR == ((S_usb_endpoint_descriptor*)pbuffer)->bDescriptorType ) { // Reset endpoint u8_i = ((S_usb_endpoint_descriptor*)pbuffer)->bEndpointAddress & (~MSK_EP_DIR); Usb_disable_stall_handshake(u8_i); Usb_reset_endpoint(u8_i); Usb_reset_data_toggle(u8_i); } } // send a ZLP for STATUS phase Usb_ack_control_in_ready_send(); while (!Is_usb_control_in_ready()); }
//! usb_get_descriptor. //! //! This function manages the GET DESCRIPTOR request. The device descriptor, //! the configuration descriptor and the device qualifier are supported. All //! other descriptors must be supported by the usb_user_get_descriptor //! function. //! Only 1 configuration is supported. //! //! @warning Code:xx bytes (function code length) //! //! @param none //! //! @return none //! void usb_get_descriptor(void) { U16 wLength ; U8 descriptor_type ; U8 string_type ; U8 dummy; U8 nb_byte; zlp = FALSE; /* no zero length packet */ string_type = Usb_read_byte(); /* read LSB of wValue */ descriptor_type = Usb_read_byte(); /* read MSB of wValue */ switch (descriptor_type) { case DEVICE_DESCRIPTOR: data_to_transfer = Usb_get_dev_desc_length(); //!< sizeof (usb_user_device_descriptor); pbuffer = Usb_get_dev_desc_pointer(); break; case CONFIGURATION_DESCRIPTOR: data_to_transfer = Usb_get_conf_desc_length(); //!< sizeof (usb_user_configuration_descriptor); pbuffer = Usb_get_conf_desc_pointer(); break; default: if( usb_user_get_descriptor(descriptor_type, string_type)==FALSE ) { Usb_enable_stall_handshake(); Usb_ack_receive_setup(); return; } break; } dummy = Usb_read_byte(); //!< don't care of wIndex field dummy = Usb_read_byte(); LSB(wLength) = Usb_read_byte(); //!< read wLength MSB(wLength) = Usb_read_byte(); Usb_ack_receive_setup() ; //!< clear the receive setup flag if (wLength > data_to_transfer) { if ((data_to_transfer % EP_CONTROL_LENGTH) == 0) { zlp = TRUE; } else { zlp = FALSE; } //!< no need of zero length packet } else { data_to_transfer = (U8)wLength; //!< send only requested number of data } while((data_to_transfer != 0) && (!Is_usb_receive_out())) { while(!Is_usb_read_control_enabled()); nb_byte=0; while(data_to_transfer != 0) //!< Send data until necessary { if(nb_byte++==EP_CONTROL_LENGTH) //!< Check endpoint 0 size { break; } #ifndef AVRGCC Usb_write_byte(*pbuffer++); #else // AVRGCC does not support point to PGM space #warning with avrgcc assumes devices descriptors are stored in the lower 64Kbytes of on-chip flash memory Usb_write_byte(pgm_read_byte_near((unsigned int)pbuffer++)); #endif data_to_transfer --; } Usb_send_control_in(); } if(Is_usb_receive_out()) { Usb_ack_receive_out(); return; } //!< abort from Host if(zlp == TRUE) { while(!Is_usb_read_control_enabled()); Usb_send_control_in(); } while(!Is_usb_receive_out()); Usb_ack_receive_out(); }
//! usb_get_descriptor. //! //! This function manages the GET DESCRIPTOR request. The device descriptor, //! the configuration descriptor and the device qualifier are supported. All //! other descriptors must be supported by the usb_user_get_descriptor //! function. //! Only 1 configuration is supported. //! //! @warning Code:xx bytes (function code length) //! void usb_get_descriptor(void) { U8 LSBwLength, MSBwLength; U8 descriptor_type ; U8 string_type ; U8 dummy; U8 byteswereread; zlp = FALSE; /* no zero length packet */ string_type = Usb_read_byte(); /* read LSB of wValue */ descriptor_type = Usb_read_byte(); /* read MSB of wValue */ byteswereread = 0; switch (descriptor_type) { case DEVICE_DESCRIPTOR: data_to_transfer = Usb_get_dev_desc_length(); //!< sizeof (usb_user_device_descriptor); pbuffer = Usb_get_dev_desc_pointer(); break; case CONFIGURATION_DESCRIPTOR: data_to_transfer = Usb_get_conf_desc_length(string_type); //!< sizeof (usb_user_configuration_descriptor); pbuffer = Usb_get_conf_desc_pointer(string_type); break; #if 1 case STRING_DESCRIPTOR: if(string_type!=LANG_ID) { usb_get_string_descriptor(string_type); return; } #endif default: dummy = Usb_read_byte(); dummy = Usb_read_byte(); LSBwLength = Usb_read_byte(); MSBwLength = Usb_read_byte(); byteswereread=1; if( usb_user_get_descriptor(descriptor_type, string_type)==FALSE ) { Usb_enable_stall_handshake(); //TODO:is this necessary, Win7 flaky without? Usb_ack_receive_setup(); return; } break; } if (byteswereread==0) { dummy = Usb_read_byte(); //!< don't care of wIndex field dummy = Usb_read_byte(); LSBwLength = Usb_read_byte(); //!< read wLength MSBwLength = Usb_read_byte(); } Usb_ack_receive_setup() ; //!< clear the receive setup flag if ((LSBwLength > data_to_transfer) || (MSBwLength)) { if ((data_to_transfer % EP_CONTROL_LENGTH) == 0) { zlp = TRUE; } else { zlp = FALSE; } //!< no need of zero length packet LSBwLength = data_to_transfer; MSBwLength = 0x00; } else { data_to_transfer = LSBwLength; //!< send only requested number of data } while((data_to_transfer != 0) && (!Is_usb_receive_out())) { U8 nb_byte = 0; if(usb_endpoint_wait_for_read_control_enabled()!=0) { Usb_enable_stall_handshake(); break; } //! Send data until necessary while(data_to_transfer != 0) { // if(Is_usb_write_enabled()) //!< Check endpoint 0 size if(nb_byte++==EP_CONTROL_LENGTH) //!< Check endpoint 0 size break; Usb_write_byte(pgm_read_byte_near((unsigned int)pbuffer++)); data_to_transfer --; } Usb_send_control_in(); } if(Is_usb_receive_out()) { //! abort from Host Usb_ack_receive_out(); return; } if(zlp == TRUE) { if(usb_endpoint_wait_for_read_control_enabled()!=0) { Usb_enable_stall_handshake(); return; } Usb_send_control_in(); } usb_endpoint_wait_for_receive_out(); Usb_ack_receive_out(); }
//! 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(); }
//! usb_process_request. //! //! @brief This function reads the SETUP request sent to the default control endpoint //! and calls the appropriate function. When exiting of the usb_read_request //! function, the device is ready to manage the next request. //! //! @param none //! //! @return none //! @note list of supported requests: //! GET_DESCRIPTOR //! GET_CONFIGURATION //! SET_ADDRESS //! SET_CONFIGURATION //! CLEAR_FEATURE //! SET_FEATURE //! GET_STATUS //! void usb_process_request(void) { U8 bmRequest; bmRequestType = Usb_read_byte(); bmRequest = Usb_read_byte(); switch (bmRequest) { case GET_DESCRIPTOR: if (0x80 == bmRequestType) { usb_get_descriptor(); } else { usb_user_read_request(bmRequestType, bmRequest); } break; case GET_CONFIGURATION: if (0x80 == bmRequestType) { usb_get_configuration(); } else { usb_user_read_request(bmRequestType, bmRequest); } break; case SET_ADDRESS: if (0x00 == bmRequestType) { usb_set_address(); } else { usb_user_read_request(bmRequestType, bmRequest); } break; case SET_CONFIGURATION: if (0x00 == bmRequestType) { usb_set_configuration(); } else { usb_user_read_request(bmRequestType, bmRequest); } break; case CLEAR_FEATURE: if (0x02 >= bmRequestType) { usb_clear_feature(); } else { usb_user_read_request(bmRequestType, bmRequest); } break; case SET_FEATURE: if (0x02 >= bmRequestType) { usb_set_feature(); } else { usb_user_read_request(bmRequestType, bmRequest); } break; case GET_STATUS: if ((0x7F < bmRequestType) & (0x82 >= bmRequestType)) { usb_get_status(); } else { usb_user_read_request(bmRequestType, bmRequest); } break; case GET_INTERFACE: if (bmRequestType == 0x81) { usb_get_interface(); } else { usb_user_read_request(bmRequestType, bmRequest); } break; case SET_INTERFACE: if (bmRequestType == 0x01) {usb_set_interface();} break; case SET_DESCRIPTOR: case SYNCH_FRAME: default: //!< un-supported request => call to user read request if(usb_user_read_request(bmRequestType, bmRequest) == FALSE) { Usb_enable_stall_handshake(); Usb_ack_receive_setup(); return; } break; } }
//! usb_process_request. //! //! @brief This function reads the SETUP request sent to the default control endpoint //! and calls the appropriate function. When exiting of the usb_read_request //! function, the device is ready to manage the next request. //! //! @note list of supported requests: //! GET_DESCRIPTOR //! GET_CONFIGURATION //! SET_ADDRESS //! SET_CONFIGURATION //! CLEAR_FEATURE //! SET_FEATURE //! GET_STATUS //! void usb_process_request(void) { U8 bmRequest; bmRequestType = Usb_read_byte(); bmRequest = Usb_read_byte(); switch (bmRequest) { case GET_DESCRIPTOR: if (0x80 == bmRequestType) { usb_get_descriptor(); } else goto user_read; break; case GET_CONFIGURATION: if (0x80 == bmRequestType) { usb_get_configuration(); } else goto user_read; break; case SET_ADDRESS: if (0x00 == bmRequestType) { usb_set_address(); } else goto user_read; break; case SET_CONFIGURATION: if (0x00 == bmRequestType) { usb_set_configuration(); } else goto user_read; break; case CLEAR_FEATURE: if (0x02 >= bmRequestType) { usb_clear_feature(); } else goto user_read; break; case SET_FEATURE: if (0x02 >= bmRequestType) { usb_set_feature(); } else goto user_read; break; case GET_STATUS: if ((0x7F < bmRequestType) & (0x82 >= bmRequestType)) { usb_get_status(); } else goto user_read; break; case GET_INTERFACE: if (bmRequestType == 0x81) { usb_get_interface(); } else goto user_read; break; case SET_INTERFACE: if (bmRequestType == 0x01) {usb_set_interface();} break; case SET_DESCRIPTOR: case SYNCH_FRAME: default: //!< un-supported request => call to user read request user_read: usb_user_read_request(bmRequestType, bmRequest); break; } Usb_select_endpoint(EP_CONTROL); // If the receive setup flag hasn't been cleared // by this point then we can assume that we didn't // support this request and should stall. if(Is_usb_receive_setup()) Usb_enable_stall_handshake(); // Clear some flags. Usb_ack_receive_setup(); Usb_ack_receive_out(); Usb_ack_in_ready(); }
//! usb_get_interface. //! //! TThis function manages the GET_INTERFACE request. //! //! @warning Code:xx bytes (function code length) //! //! @param none //! //! @return none //! void usb_get_interface (void) { Usb_enable_stall_handshake(); Usb_ack_receive_setup(); }
//! @brief This function reads the SETUP request sent to the default control endpoint //! and calls the appropriate function. When exiting of the usb_read_request //! function, the device is ready to manage the next request. //! void usb_process_request(void) { U8 bmRequestType; U8 bmRequest; Usb_ack_control_out(); bmRequestType = Usb_read_byte(); bmRequest = Usb_read_byte(); switch (bmRequest) { case SETUP_GET_DESCRIPTOR: if (USB_SETUP_GET_STAND_DEVICE == bmRequestType) { if( usb_get_descriptor() ) return; } break; case SETUP_GET_CONFIGURATION: if (USB_SETUP_GET_STAND_DEVICE == bmRequestType) { usb_get_configuration(); return; } break; case SETUP_SET_ADDRESS: if (USB_SETUP_SET_STAND_DEVICE == bmRequestType) { usb_set_address(); return; } break; case SETUP_SET_CONFIGURATION: if (USB_SETUP_SET_STAND_DEVICE == bmRequestType) { if( usb_set_configuration() ) return; } break; case SETUP_CLEAR_FEATURE: if (usb_clear_feature(bmRequestType)) return; break; case SETUP_SET_FEATURE: if (usb_set_feature(bmRequestType)) return; break; case SETUP_GET_STATUS: if (usb_get_status(bmRequestType)) return; break; case SETUP_GET_INTERFACE: if (USB_SETUP_GET_STAND_INTERFACE == bmRequestType) { if( usb_get_interface() ) return; } break; case SETUP_SET_INTERFACE: if (bmRequestType == USB_SETUP_SET_STAND_INTERFACE) { if( usb_set_interface() ) return; } break; default: break; } // un-supported like standard request => call to user read request if( !usb_user_read_request(bmRequestType, bmRequest) ) { // Request unknow in the specific request list from interface // keep that order (set StallRq/clear RxSetup) or a // OUT request following the SETUP may be acknowledged Usb_enable_stall_handshake(); Usb_ack_receive_setup(); endpoint_status[(EP_CONTROL & MSK_EP_DIR)] = 0x01; } }