/************************************************************************* BOTStall ======== Local function to stall ongoing transfer Which endpoint to stall is determined by looking at the transfer direction intended by the host. **************************************************************************/ static void BOTStall(void) { if ((CBW.bmCBWFlags & 0x80) || (CBW.dwCBWDataTransferLength == 0)) { // stall data-in or CSW USBHwEPStall(MSC_BULK_IN_EP, TRUE); } else { // stall data-out USBHwEPStall(MSC_BULK_OUT_EP, TRUE); } }
/** Handles the BOT bulk IN endpoint @param [in] bEP Endpoint number @param [in] bEPStatus Endpoint status (indicates NAK, STALL, etc) */ void MSCBotBulkIn(U8 bEP, U8 bEPStatus) { // ignore events on stalled EP if (bEPStatus & EP_STATUS_STALLED) { return; } switch (eState) { case eCBW: case eDataOut: // ignore possibly old ACKs break; case eDataIn: HandleDataIn(); break; case eCSW: // wait for an IN token, then send the CSW USBHwEPWrite(MSC_BULK_IN_EP, (U8 *)&CSW, 13); eState = eCBW; break; case eStalled: // keep stalling USBHwEPStall(MSC_BULK_IN_EP, TRUE); break; default: DBG("Invalid state %d\n", eState); ASSERT(FALSE); break; } }
/** Local function to handle a standard endpoint request @param [in] pSetup The setup packet @param [in,out] *piLen Pointer to data length @param [in] ppbData Data buffer. @return TRUE if the request was handled successfully */ static int HandleStdEndPointReq(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData) { unsigned char *pbData = *ppbData; switch (pSetup->bRequest) { case REQ_GET_STATUS: // bit 0 = endpointed halted or not pbData[0] = (USBHwEPGetStatus(pSetup->wIndex) & EP_STATUS_STALLED) ? 1 : 0; pbData[1] = 0; *piLen = 2; break; case REQ_CLEAR_FEATURE: if (pSetup->wValue == FEA_ENDPOINT_HALT) { // clear HALT by unstalling USBHwEPStall(pSetup->wIndex, FALSE); break; } // only ENDPOINT_HALT defined for endpoints return FALSE; case REQ_SET_FEATURE: if (pSetup->wValue == FEA_ENDPOINT_HALT) { // set HALT by stalling USBHwEPStall(pSetup->wIndex, TRUE); break; } // only ENDPOINT_HALT defined for endpoints return FALSE; case REQ_SYNCH_FRAME: DBG("EP req %d not implemented\n", pSetup->bRequest); return FALSE; default: DBG("Illegal EP req %d\n", pSetup->bRequest); return FALSE; } return TRUE; }
/************************************************************************* StallControlPipe ================ Local function to stall the control endpoint **************************************************************************/ static void StallControlPipe(U8 bEPStat) { U8 *pb; int i; DBG("STALL on ["); // dump setup packet pb = (U8 *)&Setup; for (i = 0; i < 8; i++) { DBG(" %02x", *pb++); } DBG("] stat=%x\n", bEPStat); USBHwEPStall(0x80, TRUE); }
/** Local function to stall the control endpoint @param [in] bEPStat Endpoint status */ static void StallControlPipe(U8 bEPStat __attribute__ ((unused))) { U8 *pb __attribute__((unused)); int i; USBHwEPStall(0x80, TRUE); // dump setup packet DBG("STALL on ["); pb = (U8 *)&Setup; for (i = 0; i < 8; i++) { DBG(" %02x", *pb++); } DBG("] stat=%x\n", bEPStat); }
/** Local function to stall the control endpoint @param [in] bEPStat Endpoint status */ static void StallControlPipe(uint8_t bEPStat) { uint8_t *pb; int i; USBHwEPStall(0x80, true); // dump setup packet DBG(UART0,"STALL on ["); pb = (uint8_t *)&Setup; for (i = 0; i < 8; i++) { DBG(UART0," %02x", *pb++); } DBG(UART0,"] stat=%x\n", bEPStat); }
/** Local function to stall the control endpoint @param [in] bEPStat Endpoint status */ static void StallControlPipe(unsigned char bEPStat) { unsigned char *pb; int i; USBHwEPStall(0x80, TRUE); // dump setup packet DBG("STALL on ["); pb = (unsigned char *)&Setup; for (i = 0; i < 8; i++) { DBG(" %02x", *pb++); } DBG("] stat=%x\n", bEPStat); }
/** Local function to stall the control endpoint @param [in] bEPStat Endpoint status */ static void StallControlPipe(unsigned char bEPStat) { unsigned char *pb; int i; // Just for removing the unused variable warning (void) bEPStat; USBHwEPStall(0x80, TRUE); // dump setup packet DBG("STALL on ["); pb = (unsigned char *)&Setup; for (i = 0; i < 8; i++) { DBG(" %02x", *pb++); } DBG("] stat=%x\n", bEPStat); }
/** Handles the BOT bulk OUT endpoint @param [in] bEP Endpoint number @param [in] bEPStatus Endpoint status (indicates NAK, STALL, etc) */ void MSCBotBulkOut(U8 bEP, U8 bEPStatus) { int iLen, iChunk; BOOL fHostIn, fDevIn; // ignore events on stalled EP if (bEPStatus & EP_STATUS_STALLED) { return; } switch (eState) { case eCBW: iLen = USBHwEPRead(bEP, (U8 *)&CBW, sizeof(CBW)); // check if we got a good CBW if (!CheckCBW(&CBW, iLen)) { // see 6.6.1 USBHwEPStall(MSC_BULK_IN_EP, TRUE); USBHwEPStall(MSC_BULK_OUT_EP, TRUE); eState = eStalled; break; } DBG("CBW: len=%d, flags=%x, cmd=%x, cmdlen=%d\n", CBW.dwCBWDataTransferLength, CBW.bmCBWFlags, CBW.CBWCB[0], CBW.bCBWCBLength); dwOffset = 0; dwTransferSize = 0; fHostIn = ((CBW.bmCBWFlags & 0x80) != 0); // verify request pbData = SCSIHandleCmd(CBW.CBWCB, CBW.bCBWCBLength, &iLen, &fDevIn); if (pbData == NULL) { // unknown command BOTStall(); SendCSW(STATUS_FAILED); break; } // rule: if device and host disagree on direction, send CSW with status 2 if ((iLen > 0) && ((fHostIn && !fDevIn) || (!fHostIn && fDevIn))) { DBG("Host and device disagree on direction\n"); BOTStall(); SendCSW(STATUS_PHASE_ERR); break; } // rule: if D > H, send CSW with status 2 if (iLen > CBW.dwCBWDataTransferLength) { DBG("Negative residue\n"); BOTStall(); SendCSW(STATUS_PHASE_ERR); break; } dwTransferSize = iLen; if ((dwTransferSize == 0) || fDevIn) { // data from device-to-host eState = eDataIn; HandleDataIn(); } else { // data from host-to-device eState = eDataOut; } break; case eDataOut: HandleDataOut(); break; case eDataIn: case eCSW: iChunk = USBHwEPRead(bEP, NULL, 0); DBG("Phase error in state %d, %d bytes\n", eState, iChunk); eState = eCBW; break; case eStalled: // keep stalling USBHwEPStall(MSC_BULK_OUT_EP, TRUE); break; default: DBG("Invalid state %d\n", eState); ASSERT(FALSE); break; } }