#include "usb.h" void USB::suspend() {} void USB::resume() {} void USB::reset() {} bool USB::setup(const int &configuration){return false;} /** * This routine can clear Halt Endpoint features on EPs. * @see 9.4.1 * */ bool USB::StandardRequest::clear_feature(const SetupBuffer &buf){ // Send procedural stall if device isn't configured if((usb.dev_state != DEV_CONFIGURED) // or request is made to host(remote wakeup not supported) || (buf.bmRequestType == SetupBuffer::OUT_DEVICE) // or request is made to interface || (buf.bmRequestType == SetupBuffer::OUT_INTERFACE) // or msbs of value or index set to non-zero value || (buf.wValue & 0xFF00u) || (buf.wIndex & 0xFF00u) // or data length set to non-zero. || (buf.wLength != 0)){ return false; } // Verify that packet was directed at an endpoint if((buf.bmRequestType != SetupBuffer::OUT_ENDPOINT) // the feature selected was HALT_ENDPOINT || (buf.wValue != ENDPOINT_HALT)){ return false; } if(usb.set_ep_state((Uint8)buf.wIndex, EP_IDLE) != EP_IDLE){ return false; } return true; } /** * This routine returns current configuration value * @see 9.4.2 * */ bool USB::StandardRequest::get_configuration(const SetupBuffer &buf){ // This request must be directed to the device if ((buf.bmRequestType != SetupBuffer::IN_DEVICE) // with value word set to zero || buf.wValue // and index set to zero || buf.wIndex // and setup length set to one || buf.wLength != 1){ // Otherwise send a stall to host return false; } if(usb.dev_state == DEV_CONFIGURED){ // If the device is configured, then return value 0x01 // since this software only supports one configuration usb.ep0_tx(one_packet, 1); }else if(usb.dev_state == DEV_ADDRESS){ // If the device is in address state, it is not // configured, so return 0x00 usb.ep0_tx(zero_packet, 1); } // Put endpoint into transmit mode return true; } /** * This routine sets the data pointer and size to correct * descriptor and sets the endpoint status to transmit * @see 9.4.3 */ bool USB::StandardRequest::get_descriptor(const SetupBuffer &buf){ /* * Determine which type of descriptor was requested, * and set data ptr and size accordingly * @see USB spec. 9.4.3 Get Descriptor */ unsigned char *descriptor(NULL); int descriptor_size(0); if(!usb.descriptor(buf.wValue, buf.wIndex, &descriptor, &descriptor_size)){ return false; } // activate only when the requested descriptor is valid if(buf.wLength > 0){ // Send only requested amount of data if(buf.wLength < descriptor_size){ descriptor_size = buf.wLength; } // Put endpoint in transmit mode usb.ep0_tx(descriptor, descriptor_size); } return true; } /** * This routine returns 0x00, since only one interface * is supported by this firmware * @see 9.4.4 */ bool USB::StandardRequest::get_interface(const SetupBuffer &buf){ // If device is not configured if((usb.dev_state != DEV_CONFIGURED) // or recipient is not an interface || (buf.bmRequestType != SetupBuffer::IN_INTERFACE) // or non-zero value or index fields || buf.wValue || (buf.wIndex >= usb.interfaces()) // or data length not equal to one || buf.wLength != 1){ // Then return stall due to invalid request return false; } // Otherwise, return 0x00 to host usb.ep0_tx(zero_packet, 1); // Set Serviced Setup packet, put endpoint in transmit // mode and reset Data sent counter return true; } /** * This routine returns a two byte status packet to the host * @see 9.4.5 */ bool USB::StandardRequest::get_status(const SetupBuffer &buf){ // If non-zero return length or data length not // equal to 2 then send a stall indicating invalid request if((buf.wValue > 0) || (buf.wLength != 2)){ return false; } bool request_completed(false); // Determine if recipient was device, interface, or EP switch(buf.bmRequestType){ case SetupBuffer::IN_DEVICE: if(buf.wIndex == 0){ // send 0x00, indicating bus power and no remote wake-up supported // b0 => seif powered, b1 => remote wakeup, b2..15 => reserved usb.ep0_tx(zero_packet, sizeof(zero_packet)); request_completed = true; } // else Send stall if request is invalid break; case SetupBuffer::IN_INTERFACE: if((usb.dev_state == DEV_CONFIGURED) && (buf.wIndex <= usb.interfaces())){ // Only valid if device is configured and non-zero index // Status packet always returns 0x00 usb.ep0_tx(zero_packet, sizeof(zero_packet)); request_completed = true; } // Otherwise send stall to host break; case SetupBuffer::IN_ENDPOINT: if(((usb.dev_state == DEV_CONFIGURED) && (buf.wIndex & 0xFF00u == 0)) || ((usb.dev_state == DEV_ADDRESS) && (buf.wIndex == 0))){ // Make sure device is configured and index msb = 0x00 // Handle case if request is directed to some EPs ep_state_t state(usb.get_ep_state((Uint8)buf.wIndex)); if(state == EP_VOID){break;} request_completed = true; if(state == EP_HALT){ // If endpoint is halted, return 0x01,0x00 usb.ep0_tx(one_packet, sizeof(one_packet)); }else{ // Otherwise return 0x00,0x00 to indicate endpoint active usb.ep0_tx(zero_packet, sizeof(zero_packet)); } } // else Send stall if unexpected data encountered break; } return request_completed; } /** * Set new function address * @see 9.4.6 */ bool USB::StandardRequest::set_address(const SetupBuffer &buf){ // Request must be directed to device // with index and length set to zero. if((buf.bmRequestType != SetupBuffer::OUT_DEVICE) || (buf.wIndex != 0) || (buf.wLength != 0) || (buf.wValue & 0xFF80u)){ // Send stall if setup data invalid return false; } if(usb.set_address((Uint8)buf.wValue) != 0){ // Indicate that device state is now address usb.dev_state = DEV_ADDRESS; }else{ // If new address was 0x00, return device to default state usb.dev_state = DEV_DEFAULT; } // Indicate setup packet has been serviced return true; } /** * This routine allows host to change current device configuration value * @see 9.4.7 */ bool USB::StandardRequest::set_configuration(const SetupBuffer &buf){ // Device must be addressed before configured if((usb.dev_state == DEV_DEFAULT) // and request recipient must be the device || (buf.bmRequestType != SetupBuffer::OUT_DEVICE) // the index and length words must be zero || buf.wIndex || buf.wLength || (buf.wValue & 0xFF00u)){ // Send stall if setup data is invalid return false; } // Any positive configuration request, // This software only supports config = 0,1? bool res(usb.setup(buf.wValue & 0xFF)); if(res){ // positive: results in configuration being set to 1 // zero: unconfigures device by setting state to address, usb.dev_state = buf.wValue ? DEV_CONFIGURED : DEV_ADDRESS; } return res; } /** * This routine will set the EP Halt feature for EPs. * @see 9.4.9 */ bool USB::StandardRequest::set_feature(const SetupBuffer &buf){ if((buf.wValue & 0xFF00u) || (buf.wIndex & 0xFF00u) || (buf.wLength != 0)){ return false; } switch(usb.dev_state){ case DEV_DEFAULT: if((buf.wValue != TEST_MODE) || (buf.bmRequestType == SetupBuffer::OUT_DEVICE)){return false;} // TODO: TEST_MODE‚ΜŽΐ‘• break; case DEV_ADDRESS: if((buf.bmRequestType == SetupBuffer::OUT_INTERFACE) && ((buf.bmRequestType == SetupBuffer::OUT_ENDPOINT) && buf.wIndex)){ return false; } // TODO: Žΐ‘• break; case DEV_CONFIGURED: // TODO: Žΐ‘• // Make sure endpoint exists and that halt // endpoint feature is selected if((buf.bmRequestType == SetupBuffer::OUT_ENDPOINT) && (buf.wValue == ENDPOINT_HALT) && (usb.set_ep_state((Uint8)buf.wIndex, EP_HALT) == EP_HALT)){ // Send procedural stall return true; } break; } return false; } /** * This function sets interface if it's supported * @see 9.4.10 */ bool USB::StandardRequest::set_interface(const SetupBuffer &buf){ // Make sure request is directed at interface etc if((buf.bmRequestType != SetupBuffer::OUT_INTERFACE) || buf.wLength || (buf.wIndex >= usb.interfaces())){ // Othewise send a stall to host return false; } // TODO: Žΐ‘• return false; } USB::StandardRequest::StandardRequest(USB &target) : usb(target) {} USB::StandardRequest::~StandardRequest(){} bool USB::StandardRequest::handle(const SetupBuffer &buf){ switch(buf.bRequest){ case CLEAR_FEATURE: return clear_feature(buf); case GET_CONFIGURATION: return get_configuration(buf); case GET_DESCRIPTOR: return get_descriptor(buf); case GET_INTERFACE: return get_interface(buf); case GET_STATUS: return get_status(buf); case SET_ADDRESS: return set_address(buf); case SET_CONFIGURATION: return set_configuration(buf); case SET_DESCRIPTOR: break; case SET_FEATURE: return set_feature(buf); case SET_INTERFACE: return set_interface(buf); case SYNCH_FRAME: break; } return false; } USB::USB() : dev_state(DEV_DEFAULT), standard_request_handler(*this) {} USB::~USB() {} const unsigned char USB::StandardRequest::one_packet[] = {0x01, 0x00}; const unsigned char USB::StandardRequest::zero_packet[] = {0x00, 0x00};