/** \brief USB Setup Handler * * This function should be called either from the USB interrupt or the main loop when the \c USBIIF.EP0IF * flag has been set. Keep in mind that all bits in \c USBIIF register are cleared when the register is * read. A detailed description of the framework is found in the \ref section_setup_handler_usage * section. * * \note The USB header data is always little-endian, so if a big-endian compiler is used (such as Keil * C51), the 16-bit values in the \ref usbSetupHeader must be flipped before they are used. */ void usbfwSetupHandler(void) { uint8 controlReg; uint8 bytesNow; uint8 oldEndpoint; // Save the old index setting, then select endpoint 0 and fetch the control register oldEndpoint = USBFW_GET_SELECTED_ENDPOINT(); USBFW_SELECT_ENDPOINT(0); controlReg = USBCS0; // The last transfer was ended prematurely by a new SETUP packet if (controlReg & USBCS0_SETUP_END) { USBCS0 = USBCS0_CLR_SETUP_END; usbfwData.ep0Status = EP_CANCEL; if (ProcessFunc) ProcessFunc(); usbfwData.ep0Status = EP_IDLE; } // A STALL handshake was transmitted to the PC if (controlReg & USBCS0_SENT_STALL) { USBCS0 = 0x00; usbfwData.ep0Status = EP_IDLE; } // Receive OUT packets if (usbfwData.ep0Status == EP_RX) { // Read FIFO bytesNow = USBCNT0; usbfwReadFifo(&USBF0, bytesNow, usbSetupData.pBuffer); usbSetupData.bytesLeft -= bytesNow; usbSetupData.pBuffer += bytesNow; // Arm the endpoint USBCS0 = usbSetupData.bytesLeft ? USBCS0_CLR_OUTPKT_RDY : (USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END); // Make a call to the appropriate request handler when done if (usbSetupData.bytesLeft == 0) { if (ProcessFunc) ProcessFunc(); usbfwData.ep0Status = EP_IDLE; } // Return here since nothing more will happen until the next interrupt USBFW_SELECT_ENDPOINT(oldEndpoint); return; // Let the application handle the reception } else if (usbfwData.ep0Status == EP_MANUAL_RX) { ProcessFunc(); } // Receive SETUP header if (usbfwData.ep0Status == EP_IDLE) { if (controlReg & USBCS0_OUTPKT_RDY) { usbfwReadFifo(&USBF0, 8, (uint8 __xdata *) &usbSetupHeader); // Handle control transfers individually ProcessFunc = NULL; switch (usbSetupHeader.requestType & (RT_MASK_TYPE | RT_MASK_DIR)) { // Standard requests with data from the host (OUT) case RT_STD_OUT: switch (usbSetupHeader.request) { case SET_ADDRESS: usbsrSetAddress(); break; case SET_FEATURE: usbsrSetFeature(); break; case CLEAR_FEATURE: usbsrClearFeature(); break; case SET_CONFIGURATION: usbsrSetConfiguration(); break; case SET_INTERFACE: usbsrSetInterface(); break; case SET_DESCRIPTOR: /*usbsrHookSetDescriptor(); break; - unsupported */ default: usbfwData.ep0Status = EP_STALL; break; } break; // Standard requests with data to the host (IN) case RT_STD_IN: switch (usbSetupHeader.request) { case GET_STATUS: usbsrGetStatus(); break; case GET_DESCRIPTOR: usbsrGetDescriptor(); break; case GET_CONFIGURATION: usbsrGetConfiguration(); break; case GET_INTERFACE: usbsrGetInterface(); break; case SYNCH_FRAME: /*usbsrHookSynchFrame(); break; - unsupported */ default: usbfwData.ep0Status = EP_STALL; break; } break; // Vendor requests case RT_VEND_OUT: ProcessFunc = usbvrHookProcessOut; usbvrHookProcessOut(); break; case RT_VEND_IN: ProcessFunc = usbvrHookProcessIn; usbvrHookProcessIn(); break; // Class requests case RT_CLASS_OUT: ProcessFunc = usbcrHookProcessOut; usbcrHookProcessOut(); break; case RT_CLASS_IN: ProcessFunc = usbcrHookProcessIn; usbcrHookProcessIn(); break; // Unrecognized request: Stall the endpoint default: usbfwData.ep0Status = EP_STALL; break; } // Arm/stall the endpoint USBCS0 = (usbfwData.ep0Status == EP_STALL) ? (USBCS0_CLR_OUTPKT_RDY | USBCS0_SEND_STALL) : USBCS0_CLR_OUTPKT_RDY; } } // Transmit IN packets if (usbfwData.ep0Status == EP_TX) { controlReg = USBCS0_INPKT_RDY; // The last frame should contain 0 to (EP0_PACKET_SIZE - 1) bytes if (usbSetupData.bytesLeft < EP0_PACKET_SIZE) { bytesNow = usbSetupData.bytesLeft; controlReg |= USBCS0_DATA_END; // All other packets should have the maximum length } else { bytesNow = EP0_PACKET_SIZE; } // Load the FIFO and move the pointer usbfwWriteFifo(&USBF0, bytesNow, usbSetupData.pBuffer); usbSetupData.pBuffer += bytesNow; usbSetupData.bytesLeft -= bytesNow; // Arm the FIFO (even for a zero-length packet) USBCS0 = controlReg; // Make a call to the appropriate request handler when done if (bytesNow < EP0_PACKET_SIZE) { if (ProcessFunc) ProcessFunc(); usbfwData.ep0Status = EP_IDLE; } // Let the application handle the transmission } else if (usbfwData.ep0Status == EP_MANUAL_TX) { ProcessFunc(); } // Restore the old index setting USBFW_SELECT_ENDPOINT(oldEndpoint); } // usbfwSetupHandler
/** \brief USB Setup Handler * * This function should be called either from the USB interrupt or the main loop when the * \c USB_IIF.EP0IF flag has been set. A detailed description of the framework is found in the * \ref section_setup_handler_usage section. */ void usbfwSetupHandler(void) { uint32_t controlReg; uint32_t oldEndpoint; uint32_t bytesNow; // // Save the old index setting, then select endpoint 0 and fetch the control register // oldEndpoint = USBFW_GET_SELECTED_ENDPOINT(); USBFW_SELECT_ENDPOINT(0); controlReg = HWREG(USB_CS0); // // Update the USB device address after the status stage // if(usbfwData.ep0Status == EP_ADDRESS) { if(!(controlReg & USB_CS0_OUTPKTRDY_M)) { uint8_t address = usbSetupHeader.valueLsb; HWREG(USB_ADDR) = address; if(usbfwData.usbState < DEV_CONFIGURED) { if(address) { usbfwData.usbState = DEV_ADDRESS; } else { usbfwData.usbState = DEV_DEFAULT; } } } usbfwData.ep0Status = EP_IDLE; } // // A STALL handshake was transmitted to the host // if(controlReg & USB_CS0_SENTSTALL_M) { HWREG(USB_CS0) = 0x00; usbfwData.ep0Status = EP_IDLE; } // // The last transfer was ended prematurely by a new SETUP packet // if(controlReg & USB_CS0_SETUPEND_M) { HWREG(USB_CS0) = USB_CS0_CLRSETUPEND_M; usbfwData.ep0Status = EP_CANCEL; if(pProcessFunc) { pProcessFunc(); } usbfwData.ep0Status = EP_IDLE; } // // Receive OUT packets // if(usbfwData.ep0Status == EP_RX) { if(controlReg & USB_CS0_OUTPKTRDY_M) { // // Read FIFO // uint32_t bytesNow = HWREG(USB_CNT0); usbfwReadFifo(USB_F0, bytesNow, usbSetupData.pBuffer); usbSetupData.bytesLeft -= bytesNow; usbSetupData.pBuffer = ((uint8_t*) usbSetupData.pBuffer) + bytesNow; // // Arm the endpoint // if(usbSetupData.bytesLeft) { HWREG(USB_CS0) = USB_CS0_CLROUTPKTRDY_M; } else { HWREG(USB_CS0) = USB_CS0_CLROUTPKTRDY_M | USB_CS0_DATAEND_M; } // // Make a call to the appropriate request handler when done // if(usbSetupData.bytesLeft == 0) { if(pProcessFunc) { pProcessFunc(); } usbfwData.ep0Status = EP_IDLE; } } // // Return here since nothing more will happen until the next interrupt // USBFW_SELECT_ENDPOINT(oldEndpoint); return; // // Let the application handle the reception // } else if(usbfwData.ep0Status == EP_MANUAL_RX) { if(pProcessFunc) { pProcessFunc(); } } // // Receive SETUP header // if(usbfwData.ep0Status == EP_IDLE) { if(controlReg & USB_CS0_OUTPKTRDY_M) { usbfwReadFifo(USB_F0, 8, &usbSetupHeader); // // Handle control transfers individually // pProcessFunc = NULL; switch(usbSetupHeader.requestType & (RT_MASK_TYPE | RT_MASK_DIR)) { // // Standard requests without data or with data from the host (OUT) // case RT_STD_OUT: switch(usbSetupHeader.request) { case USBSR_REQ_SET_ADDRESS: usbsrSetAddress(); break; case USBSR_REQ_SET_FEATURE: usbsrSetFeature(); break; case USBSR_REQ_CLEAR_FEATURE: usbsrClearFeature(); break; case USBSR_REQ_SET_CONFIGURATION: usbsrSetConfiguration(); break; case USBSR_REQ_SET_INTERFACE: usbsrSetInterface(); break; case USBSR_REQ_SET_DESCRIPTOR: pProcessFunc = usbsrHookSetDescriptor; usbsrHookSetDescriptor(); break; default: usbfwData.ep0Status = EP_STALL; break; } break; // // Standard requests with data to the host (IN) // case RT_STD_IN: switch(usbSetupHeader.request) { case USBSR_REQ_GET_STATUS: usbsrGetStatus(); break; case USBSR_REQ_GET_DESCRIPTOR: usbsrGetDescriptor(); break; case USBSR_REQ_GET_CONFIGURATION: usbsrGetConfiguration(); break; case USBSR_REQ_GET_INTERFACE: usbsrGetInterface(); break; case USBSR_REQ_SYNCH_FRAME: pProcessFunc = usbsrHookSynchFrame; usbsrHookSynchFrame(); break; default: usbfwData.ep0Status = EP_STALL; break; } break; // // Vendor requests // case RT_VEND_OUT: pProcessFunc = usbvrHookProcessOut; usbvrHookProcessOut(); break; case RT_VEND_IN: pProcessFunc = usbvrHookProcessIn; usbvrHookProcessIn(); break; // // Class requests // case RT_CLASS_OUT: pProcessFunc = usbcrHookProcessOut; usbcrHookProcessOut(); break; case RT_CLASS_IN: pProcessFunc = usbcrHookProcessIn; usbcrHookProcessIn(); break; // // Unrecognized request: Stall the endpoint // default: usbfwData.ep0Status = EP_STALL; break; } // // Arm/stall the endpoint // if(usbfwData.ep0Status == EP_STALL) { HWREG(USB_CS0) = USB_CS0_CLROUTPKTRDY_M | USB_CS0_SENDSTALL_M; } else if((usbfwData.ep0Status == EP_TX) || (usbfwData.ep0Status == EP_RX)) { HWREG(USB_CS0) = USB_CS0_CLROUTPKTRDY_M; } else { HWREG(USB_CS0) = USB_CS0_CLROUTPKTRDY_M | USB_CS0_DATAEND_M; } } } // // Transmit IN packets // if(usbfwData.ep0Status == EP_TX) { controlReg = USB_CS0_INPKTRDY_M; // // The last frame should contain 0 to (EP0_PACKET_SIZE - 1) bytes // if(usbSetupData.bytesLeft < USB_EP0_PACKET_SIZE) { bytesNow = usbSetupData.bytesLeft; controlReg |= USB_CS0_DATAEND_M; } else { // // All other packets should have the maximum length // bytesNow = USB_EP0_PACKET_SIZE; } // // Load the FIFO and move the pointer // usbfwWriteFifo(USB_F0, bytesNow, usbSetupData.pBuffer); usbSetupData.pBuffer = ((uint8_t*) usbSetupData.pBuffer) + bytesNow; usbSetupData.bytesLeft -= bytesNow; // // Arm the FIFO (even for a zero-length packet) // HWREG(USB_CS0) = controlReg; // // Make a call to the appropriate request handler when done // if(bytesNow < USB_EP0_PACKET_SIZE) { if(pProcessFunc) { pProcessFunc(); } usbfwData.ep0Status = EP_IDLE; } // // Let the application handle the transmission // } else if(usbfwData.ep0Status == EP_MANUAL_TX) { if(pProcessFunc) { pProcessFunc(); } } // // Restore the old index setting // USBFW_SELECT_ENDPOINT(oldEndpoint); }