Christian Lerche
/
EA_DoorPlayer
EA BaseBoard, playing wav, PC see\'s SD-card through USB port.
msc_bot.cpp@0:fef366d2ed20, 2011-11-22 (annotated)
- Committer:
- Lerche
- Date:
- Tue Nov 22 05:45:58 2011 +0000
- Revision:
- 0:fef366d2ed20
Thanks to those who provided EA_WavPlayer and USB_MSC
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Lerche | 0:fef366d2ed20 | 1 | /* |
Lerche | 0:fef366d2ed20 | 2 | LPCUSB, an USB device driver for LPC microcontrollers |
Lerche | 0:fef366d2ed20 | 3 | Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) |
Lerche | 0:fef366d2ed20 | 4 | |
Lerche | 0:fef366d2ed20 | 5 | Redistribution and use in source and binary forms, with or without |
Lerche | 0:fef366d2ed20 | 6 | modification, are permitted provided that the following conditions are met: |
Lerche | 0:fef366d2ed20 | 7 | |
Lerche | 0:fef366d2ed20 | 8 | 1. Redistributions of source code must retain the above copyright |
Lerche | 0:fef366d2ed20 | 9 | notice, this list of conditions and the following disclaimer. |
Lerche | 0:fef366d2ed20 | 10 | 2. Redistributions in binary form must reproduce the above copyright |
Lerche | 0:fef366d2ed20 | 11 | notice, this list of conditions and the following disclaimer in the |
Lerche | 0:fef366d2ed20 | 12 | documentation and/or other materials provided with the distribution. |
Lerche | 0:fef366d2ed20 | 13 | 3. The name of the author may not be used to endorse or promote products |
Lerche | 0:fef366d2ed20 | 14 | derived from this software without specific prior written permission. |
Lerche | 0:fef366d2ed20 | 15 | |
Lerche | 0:fef366d2ed20 | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
Lerche | 0:fef366d2ed20 | 17 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
Lerche | 0:fef366d2ed20 | 18 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
Lerche | 0:fef366d2ed20 | 19 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
Lerche | 0:fef366d2ed20 | 20 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
Lerche | 0:fef366d2ed20 | 21 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
Lerche | 0:fef366d2ed20 | 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
Lerche | 0:fef366d2ed20 | 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
Lerche | 0:fef366d2ed20 | 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
Lerche | 0:fef366d2ed20 | 25 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Lerche | 0:fef366d2ed20 | 26 | */ |
Lerche | 0:fef366d2ed20 | 27 | |
Lerche | 0:fef366d2ed20 | 28 | /** @file |
Lerche | 0:fef366d2ed20 | 29 | |
Lerche | 0:fef366d2ed20 | 30 | Bulk-only-transfer layer for mass storage. |
Lerche | 0:fef366d2ed20 | 31 | |
Lerche | 0:fef366d2ed20 | 32 | This layers sits between the generic USB layers and the SCSI layer |
Lerche | 0:fef366d2ed20 | 33 | and performs data transfer according to the BOT protocol. |
Lerche | 0:fef366d2ed20 | 34 | */ |
Lerche | 0:fef366d2ed20 | 35 | |
Lerche | 0:fef366d2ed20 | 36 | //#define DEBUG |
Lerche | 0:fef366d2ed20 | 37 | #include "dbg.h" |
Lerche | 0:fef366d2ed20 | 38 | #include "mbed.h" |
Lerche | 0:fef366d2ed20 | 39 | #include <string.h> |
Lerche | 0:fef366d2ed20 | 40 | |
Lerche | 0:fef366d2ed20 | 41 | #include "msc_bot.h" |
Lerche | 0:fef366d2ed20 | 42 | #include "msc_scsi.h" |
Lerche | 0:fef366d2ed20 | 43 | #include "USBMSC.h" |
Lerche | 0:fef366d2ed20 | 44 | |
Lerche | 0:fef366d2ed20 | 45 | extern USBMSC usbdev; |
Lerche | 0:fef366d2ed20 | 46 | |
Lerche | 0:fef366d2ed20 | 47 | /** Command block wrapper structure */ |
Lerche | 0:fef366d2ed20 | 48 | struct TCBW { |
Lerche | 0:fef366d2ed20 | 49 | uint32_t dwCBWSignature; |
Lerche | 0:fef366d2ed20 | 50 | uint32_t dwCBWTag; |
Lerche | 0:fef366d2ed20 | 51 | uint32_t dwCBWDataTransferLength; |
Lerche | 0:fef366d2ed20 | 52 | uint8_t bmCBWFlags; |
Lerche | 0:fef366d2ed20 | 53 | uint8_t bCBWLun; |
Lerche | 0:fef366d2ed20 | 54 | uint8_t bCBWCBLength; |
Lerche | 0:fef366d2ed20 | 55 | uint8_t CBWCB[16]; |
Lerche | 0:fef366d2ed20 | 56 | uint8_t dummy[MAX_PACKET_SIZE_EPBULK - 31]; |
Lerche | 0:fef366d2ed20 | 57 | } __attribute__((packed)); |
Lerche | 0:fef366d2ed20 | 58 | |
Lerche | 0:fef366d2ed20 | 59 | /** Command status wrapper structure */ |
Lerche | 0:fef366d2ed20 | 60 | struct TCSW { |
Lerche | 0:fef366d2ed20 | 61 | uint32_t dwCSWSignature; |
Lerche | 0:fef366d2ed20 | 62 | uint32_t dwCSWTag; |
Lerche | 0:fef366d2ed20 | 63 | uint32_t dwCSWDataResidue; |
Lerche | 0:fef366d2ed20 | 64 | uint8_t bmCSWStatus; |
Lerche | 0:fef366d2ed20 | 65 | uint8_t dummy[MAX_PACKET_SIZE_EPBULK - 13]; |
Lerche | 0:fef366d2ed20 | 66 | } __attribute__((packed)); |
Lerche | 0:fef366d2ed20 | 67 | |
Lerche | 0:fef366d2ed20 | 68 | /** States of BOT state machine */ |
Lerche | 0:fef366d2ed20 | 69 | typedef enum { |
Lerche | 0:fef366d2ed20 | 70 | eCBW, |
Lerche | 0:fef366d2ed20 | 71 | eDataOut, |
Lerche | 0:fef366d2ed20 | 72 | eDataIn, |
Lerche | 0:fef366d2ed20 | 73 | eCSW, |
Lerche | 0:fef366d2ed20 | 74 | eStalled |
Lerche | 0:fef366d2ed20 | 75 | } EBotState; |
Lerche | 0:fef366d2ed20 | 76 | |
Lerche | 0:fef366d2ed20 | 77 | |
Lerche | 0:fef366d2ed20 | 78 | #define CBW_SIGNATURE 0x43425355 /**< magic word in CBW */ |
Lerche | 0:fef366d2ed20 | 79 | #define CSW_SIGNATURE 0x53425355 /**< magic word in CSW */ |
Lerche | 0:fef366d2ed20 | 80 | |
Lerche | 0:fef366d2ed20 | 81 | #define STATUS_PASSED 0x00 /**< successful transfer */ |
Lerche | 0:fef366d2ed20 | 82 | #define STATUS_FAILED 0x01 /**< failed transfer */ |
Lerche | 0:fef366d2ed20 | 83 | #define STATUS_PHASE_ERR 0x02 /**< conflict between host and device */ |
Lerche | 0:fef366d2ed20 | 84 | |
Lerche | 0:fef366d2ed20 | 85 | static uint32_t dwTransferSize; /**< total size of data transfer */ |
Lerche | 0:fef366d2ed20 | 86 | static uint32_t dwOffset; /**< offset in current data transfer */ |
Lerche | 0:fef366d2ed20 | 87 | |
Lerche | 0:fef366d2ed20 | 88 | static TCBW CBW; |
Lerche | 0:fef366d2ed20 | 89 | static TCSW CSW; |
Lerche | 0:fef366d2ed20 | 90 | |
Lerche | 0:fef366d2ed20 | 91 | static EBotState eState; |
Lerche | 0:fef366d2ed20 | 92 | |
Lerche | 0:fef366d2ed20 | 93 | static uint8_t *pbData; |
Lerche | 0:fef366d2ed20 | 94 | |
Lerche | 0:fef366d2ed20 | 95 | |
Lerche | 0:fef366d2ed20 | 96 | |
Lerche | 0:fef366d2ed20 | 97 | /** |
Lerche | 0:fef366d2ed20 | 98 | Resets the BOT state machine |
Lerche | 0:fef366d2ed20 | 99 | */ |
Lerche | 0:fef366d2ed20 | 100 | void MSCBotReset(void) |
Lerche | 0:fef366d2ed20 | 101 | { |
Lerche | 0:fef366d2ed20 | 102 | DBG("BOT reset in state %d\n", eState); |
Lerche | 0:fef366d2ed20 | 103 | // reset BOT state |
Lerche | 0:fef366d2ed20 | 104 | eState = eCBW; |
Lerche | 0:fef366d2ed20 | 105 | // reset SCSI |
Lerche | 0:fef366d2ed20 | 106 | SCSIReset(); |
Lerche | 0:fef366d2ed20 | 107 | } |
Lerche | 0:fef366d2ed20 | 108 | |
Lerche | 0:fef366d2ed20 | 109 | |
Lerche | 0:fef366d2ed20 | 110 | /** |
Lerche | 0:fef366d2ed20 | 111 | Prepares a CSW, to be sent on next bulk-IN interrupt |
Lerche | 0:fef366d2ed20 | 112 | |
Lerche | 0:fef366d2ed20 | 113 | @param [in] bStatus CSW status |
Lerche | 0:fef366d2ed20 | 114 | */ |
Lerche | 0:fef366d2ed20 | 115 | static void SendCSW(uint8_t bStatus) |
Lerche | 0:fef366d2ed20 | 116 | { |
Lerche | 0:fef366d2ed20 | 117 | int iResidue; |
Lerche | 0:fef366d2ed20 | 118 | |
Lerche | 0:fef366d2ed20 | 119 | iResidue = CBW.dwCBWDataTransferLength - dwTransferSize; |
Lerche | 0:fef366d2ed20 | 120 | |
Lerche | 0:fef366d2ed20 | 121 | // construct CSW |
Lerche | 0:fef366d2ed20 | 122 | CSW.dwCSWSignature = CSW_SIGNATURE; |
Lerche | 0:fef366d2ed20 | 123 | CSW.dwCSWTag = CBW.dwCBWTag; |
Lerche | 0:fef366d2ed20 | 124 | CSW.dwCSWDataResidue = MAX(iResidue, 0); |
Lerche | 0:fef366d2ed20 | 125 | CSW.bmCSWStatus = bStatus; |
Lerche | 0:fef366d2ed20 | 126 | |
Lerche | 0:fef366d2ed20 | 127 | DBG("CSW: status=%x, residue=%d\n", bStatus, CSW.dwCSWDataResidue); |
Lerche | 0:fef366d2ed20 | 128 | |
Lerche | 0:fef366d2ed20 | 129 | // next state |
Lerche | 0:fef366d2ed20 | 130 | eState = eCSW; |
Lerche | 0:fef366d2ed20 | 131 | } |
Lerche | 0:fef366d2ed20 | 132 | |
Lerche | 0:fef366d2ed20 | 133 | |
Lerche | 0:fef366d2ed20 | 134 | /** |
Lerche | 0:fef366d2ed20 | 135 | Checks if CBW is valid and meaningful |
Lerche | 0:fef366d2ed20 | 136 | |
Lerche | 0:fef366d2ed20 | 137 | @param [in] pCBW Command block wrapper |
Lerche | 0:fef366d2ed20 | 138 | @param [in] iLen Length of CBW |
Lerche | 0:fef366d2ed20 | 139 | |
Lerche | 0:fef366d2ed20 | 140 | @return true if valid and meaningful |
Lerche | 0:fef366d2ed20 | 141 | */ |
Lerche | 0:fef366d2ed20 | 142 | static bool CheckCBW(TCBW *pCBW, int iLen) |
Lerche | 0:fef366d2ed20 | 143 | { |
Lerche | 0:fef366d2ed20 | 144 | // CBW valid? |
Lerche | 0:fef366d2ed20 | 145 | if (iLen != 31) { |
Lerche | 0:fef366d2ed20 | 146 | DBG("Invalid length (%d)\n", iLen); |
Lerche | 0:fef366d2ed20 | 147 | return false; |
Lerche | 0:fef366d2ed20 | 148 | } |
Lerche | 0:fef366d2ed20 | 149 | if (pCBW->dwCBWSignature != CBW_SIGNATURE) { |
Lerche | 0:fef366d2ed20 | 150 | DBG("Invalid signature %x\n", pCBW->dwCBWSignature); |
Lerche | 0:fef366d2ed20 | 151 | return false; |
Lerche | 0:fef366d2ed20 | 152 | } |
Lerche | 0:fef366d2ed20 | 153 | |
Lerche | 0:fef366d2ed20 | 154 | // CBW meaningful? |
Lerche | 0:fef366d2ed20 | 155 | if (pCBW->bCBWLun != 0) { |
Lerche | 0:fef366d2ed20 | 156 | DBG("Invalid LUN %d\n", pCBW->bCBWLun); |
Lerche | 0:fef366d2ed20 | 157 | return false; |
Lerche | 0:fef366d2ed20 | 158 | } |
Lerche | 0:fef366d2ed20 | 159 | if ((pCBW->bCBWCBLength < 1) || (pCBW->bCBWCBLength > 16)) { |
Lerche | 0:fef366d2ed20 | 160 | DBG("Invalid CB len %d\n", pCBW->bCBWCBLength); |
Lerche | 0:fef366d2ed20 | 161 | return false; |
Lerche | 0:fef366d2ed20 | 162 | } |
Lerche | 0:fef366d2ed20 | 163 | return true; |
Lerche | 0:fef366d2ed20 | 164 | } |
Lerche | 0:fef366d2ed20 | 165 | |
Lerche | 0:fef366d2ed20 | 166 | |
Lerche | 0:fef366d2ed20 | 167 | /************************************************************************* |
Lerche | 0:fef366d2ed20 | 168 | BOTStall |
Lerche | 0:fef366d2ed20 | 169 | ======== |
Lerche | 0:fef366d2ed20 | 170 | Local function to stall ongoing transfer |
Lerche | 0:fef366d2ed20 | 171 | |
Lerche | 0:fef366d2ed20 | 172 | Which endpoint to stall is determined by looking at the transfer |
Lerche | 0:fef366d2ed20 | 173 | direction intended by the host. |
Lerche | 0:fef366d2ed20 | 174 | |
Lerche | 0:fef366d2ed20 | 175 | **************************************************************************/ |
Lerche | 0:fef366d2ed20 | 176 | static void BOTStall(void) |
Lerche | 0:fef366d2ed20 | 177 | { |
Lerche | 0:fef366d2ed20 | 178 | if ((CBW.bmCBWFlags & 0x80) || (CBW.dwCBWDataTransferLength == 0)) { |
Lerche | 0:fef366d2ed20 | 179 | // stall data-in or CSW |
Lerche | 0:fef366d2ed20 | 180 | usbdev.stallEndpoint(EPBULK_IN); |
Lerche | 0:fef366d2ed20 | 181 | } |
Lerche | 0:fef366d2ed20 | 182 | else { |
Lerche | 0:fef366d2ed20 | 183 | // stall data-out |
Lerche | 0:fef366d2ed20 | 184 | usbdev.stallEndpoint(EPBULK_OUT); |
Lerche | 0:fef366d2ed20 | 185 | } |
Lerche | 0:fef366d2ed20 | 186 | } |
Lerche | 0:fef366d2ed20 | 187 | |
Lerche | 0:fef366d2ed20 | 188 | |
Lerche | 0:fef366d2ed20 | 189 | /************************************************************************* |
Lerche | 0:fef366d2ed20 | 190 | HandleDataIn |
Lerche | 0:fef366d2ed20 | 191 | ============ |
Lerche | 0:fef366d2ed20 | 192 | Handles data from device-to-host |
Lerche | 0:fef366d2ed20 | 193 | |
Lerche | 0:fef366d2ed20 | 194 | **************************************************************************/ |
Lerche | 0:fef366d2ed20 | 195 | static void HandleDataIn(int io) |
Lerche | 0:fef366d2ed20 | 196 | { |
Lerche | 0:fef366d2ed20 | 197 | int iChunk; |
Lerche | 0:fef366d2ed20 | 198 | // process data for host in SCSI layer |
Lerche | 0:fef366d2ed20 | 199 | pbData = SCSIHandleData(CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset); |
Lerche | 0:fef366d2ed20 | 200 | if (pbData == NULL) { |
Lerche | 0:fef366d2ed20 | 201 | BOTStall(); |
Lerche | 0:fef366d2ed20 | 202 | SendCSW(STATUS_FAILED); |
Lerche | 0:fef366d2ed20 | 203 | return; |
Lerche | 0:fef366d2ed20 | 204 | } |
Lerche | 0:fef366d2ed20 | 205 | |
Lerche | 0:fef366d2ed20 | 206 | // send data to host? |
Lerche | 0:fef366d2ed20 | 207 | if (dwOffset < dwTransferSize) { |
Lerche | 0:fef366d2ed20 | 208 | iChunk = MIN(64, dwTransferSize - dwOffset); |
Lerche | 0:fef366d2ed20 | 209 | //USBHwEPWrite(MSC_BULK_IN_EP, pbData, iChunk); |
Lerche | 0:fef366d2ed20 | 210 | usbdev.writeNB(EPBULK_IN, pbData, iChunk, MAX_PACKET_SIZE_EPBULK); |
Lerche | 0:fef366d2ed20 | 211 | dwOffset += iChunk; |
Lerche | 0:fef366d2ed20 | 212 | } |
Lerche | 0:fef366d2ed20 | 213 | |
Lerche | 0:fef366d2ed20 | 214 | // are we done now? |
Lerche | 0:fef366d2ed20 | 215 | if (dwOffset == dwTransferSize) { |
Lerche | 0:fef366d2ed20 | 216 | if (dwOffset != CBW.dwCBWDataTransferLength) { |
Lerche | 0:fef366d2ed20 | 217 | // stall pipe |
Lerche | 0:fef366d2ed20 | 218 | DBG("stalling DIN"); |
Lerche | 0:fef366d2ed20 | 219 | BOTStall(); |
Lerche | 0:fef366d2ed20 | 220 | } |
Lerche | 0:fef366d2ed20 | 221 | // done |
Lerche | 0:fef366d2ed20 | 222 | SendCSW(STATUS_PASSED); |
Lerche | 0:fef366d2ed20 | 223 | } |
Lerche | 0:fef366d2ed20 | 224 | } |
Lerche | 0:fef366d2ed20 | 225 | |
Lerche | 0:fef366d2ed20 | 226 | |
Lerche | 0:fef366d2ed20 | 227 | /************************************************************************* |
Lerche | 0:fef366d2ed20 | 228 | HandleDataOut |
Lerche | 0:fef366d2ed20 | 229 | ============= |
Lerche | 0:fef366d2ed20 | 230 | Handles data from host-to-device |
Lerche | 0:fef366d2ed20 | 231 | |
Lerche | 0:fef366d2ed20 | 232 | **************************************************************************/ |
Lerche | 0:fef366d2ed20 | 233 | static void HandleDataOut(void) |
Lerche | 0:fef366d2ed20 | 234 | { |
Lerche | 0:fef366d2ed20 | 235 | int iChunk; |
Lerche | 0:fef366d2ed20 | 236 | |
Lerche | 0:fef366d2ed20 | 237 | if (dwOffset < dwTransferSize) { |
Lerche | 0:fef366d2ed20 | 238 | // get data from host |
Lerche | 0:fef366d2ed20 | 239 | // iChunk = USBHwEPRead(MSC_BULK_OUT_EP, pbData, dwTransferSize - dwOffset); |
Lerche | 0:fef366d2ed20 | 240 | usbdev.read(EPBULK_OUT, pbData, (uint16_t*)&iChunk, MAX_PACKET_SIZE_EPBULK); |
Lerche | 0:fef366d2ed20 | 241 | // process data in SCSI layer |
Lerche | 0:fef366d2ed20 | 242 | pbData = SCSIHandleData(CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset); |
Lerche | 0:fef366d2ed20 | 243 | if (pbData == NULL) { |
Lerche | 0:fef366d2ed20 | 244 | BOTStall(); |
Lerche | 0:fef366d2ed20 | 245 | SendCSW(STATUS_FAILED); |
Lerche | 0:fef366d2ed20 | 246 | return; |
Lerche | 0:fef366d2ed20 | 247 | } |
Lerche | 0:fef366d2ed20 | 248 | dwOffset += iChunk; |
Lerche | 0:fef366d2ed20 | 249 | } |
Lerche | 0:fef366d2ed20 | 250 | |
Lerche | 0:fef366d2ed20 | 251 | // are we done now? |
Lerche | 0:fef366d2ed20 | 252 | if (dwOffset == dwTransferSize) { |
Lerche | 0:fef366d2ed20 | 253 | if (dwOffset != CBW.dwCBWDataTransferLength) { |
Lerche | 0:fef366d2ed20 | 254 | // stall pipe |
Lerche | 0:fef366d2ed20 | 255 | DBG("stalling DOUT"); |
Lerche | 0:fef366d2ed20 | 256 | BOTStall(); |
Lerche | 0:fef366d2ed20 | 257 | } |
Lerche | 0:fef366d2ed20 | 258 | SendCSW(STATUS_PASSED); |
Lerche | 0:fef366d2ed20 | 259 | } |
Lerche | 0:fef366d2ed20 | 260 | } |
Lerche | 0:fef366d2ed20 | 261 | |
Lerche | 0:fef366d2ed20 | 262 | |
Lerche | 0:fef366d2ed20 | 263 | /** |
Lerche | 0:fef366d2ed20 | 264 | Handles the BOT bulk OUT endpoint |
Lerche | 0:fef366d2ed20 | 265 | |
Lerche | 0:fef366d2ed20 | 266 | @param [in] bEP Endpoint number |
Lerche | 0:fef366d2ed20 | 267 | @param [in] bEPStatus Endpoint status (indicates NAK, STALL, etc) |
Lerche | 0:fef366d2ed20 | 268 | |
Lerche | 0:fef366d2ed20 | 269 | */ |
Lerche | 0:fef366d2ed20 | 270 | void MSCBotBulkOut() |
Lerche | 0:fef366d2ed20 | 271 | { |
Lerche | 0:fef366d2ed20 | 272 | int iLen, iChunk; |
Lerche | 0:fef366d2ed20 | 273 | bool fHostIn, fDevIn; |
Lerche | 0:fef366d2ed20 | 274 | |
Lerche | 0:fef366d2ed20 | 275 | switch (eState) { |
Lerche | 0:fef366d2ed20 | 276 | |
Lerche | 0:fef366d2ed20 | 277 | case eCBW: |
Lerche | 0:fef366d2ed20 | 278 | //iLen = USBHwEPRead(bEP, (U8 *)&CBW, sizeof(CBW)); |
Lerche | 0:fef366d2ed20 | 279 | usbdev.read(EPBULK_OUT, (uint8_t *)&CBW, (uint16_t*)&iLen, MAX_PACKET_SIZE_EPBULK); |
Lerche | 0:fef366d2ed20 | 280 | |
Lerche | 0:fef366d2ed20 | 281 | // check if we got a good CBW |
Lerche | 0:fef366d2ed20 | 282 | if (!CheckCBW(&CBW, iLen)) { |
Lerche | 0:fef366d2ed20 | 283 | // see 6.6.1 |
Lerche | 0:fef366d2ed20 | 284 | usbdev.stallEndpoint(EPBULK_IN); |
Lerche | 0:fef366d2ed20 | 285 | usbdev.stallEndpoint(EPBULK_OUT); |
Lerche | 0:fef366d2ed20 | 286 | eState = eStalled; |
Lerche | 0:fef366d2ed20 | 287 | break; |
Lerche | 0:fef366d2ed20 | 288 | } |
Lerche | 0:fef366d2ed20 | 289 | |
Lerche | 0:fef366d2ed20 | 290 | DBG("CBW: len=%d, flags=%x, cmd=%x, cmdlen=%d\n", |
Lerche | 0:fef366d2ed20 | 291 | CBW.dwCBWDataTransferLength, CBW.bmCBWFlags, CBW.CBWCB[0], CBW.bCBWCBLength); |
Lerche | 0:fef366d2ed20 | 292 | |
Lerche | 0:fef366d2ed20 | 293 | dwOffset = 0; |
Lerche | 0:fef366d2ed20 | 294 | dwTransferSize = 0; |
Lerche | 0:fef366d2ed20 | 295 | fHostIn = ((CBW.bmCBWFlags & 0x80) != 0); |
Lerche | 0:fef366d2ed20 | 296 | |
Lerche | 0:fef366d2ed20 | 297 | // verify request |
Lerche | 0:fef366d2ed20 | 298 | pbData = SCSIHandleCmd(CBW.CBWCB, CBW.bCBWCBLength, &iLen, &fDevIn); |
Lerche | 0:fef366d2ed20 | 299 | if (pbData == NULL) { |
Lerche | 0:fef366d2ed20 | 300 | // unknown command |
Lerche | 0:fef366d2ed20 | 301 | BOTStall(); |
Lerche | 0:fef366d2ed20 | 302 | SendCSW(STATUS_FAILED); |
Lerche | 0:fef366d2ed20 | 303 | break; |
Lerche | 0:fef366d2ed20 | 304 | } |
Lerche | 0:fef366d2ed20 | 305 | |
Lerche | 0:fef366d2ed20 | 306 | // rule: if device and host disagree on direction, send CSW with status 2 |
Lerche | 0:fef366d2ed20 | 307 | if ((iLen > 0) && |
Lerche | 0:fef366d2ed20 | 308 | ((fHostIn && !fDevIn) || |
Lerche | 0:fef366d2ed20 | 309 | (!fHostIn && fDevIn))) { |
Lerche | 0:fef366d2ed20 | 310 | DBG("Host and device disagree on direction\n"); |
Lerche | 0:fef366d2ed20 | 311 | BOTStall(); |
Lerche | 0:fef366d2ed20 | 312 | SendCSW(STATUS_PHASE_ERR); |
Lerche | 0:fef366d2ed20 | 313 | break; |
Lerche | 0:fef366d2ed20 | 314 | } |
Lerche | 0:fef366d2ed20 | 315 | |
Lerche | 0:fef366d2ed20 | 316 | // rule: if D > H, send CSW with status 2 |
Lerche | 0:fef366d2ed20 | 317 | if (iLen > CBW.dwCBWDataTransferLength) { |
Lerche | 0:fef366d2ed20 | 318 | DBG("Negative residue\n"); |
Lerche | 0:fef366d2ed20 | 319 | BOTStall(); |
Lerche | 0:fef366d2ed20 | 320 | SendCSW(STATUS_PHASE_ERR); |
Lerche | 0:fef366d2ed20 | 321 | break; |
Lerche | 0:fef366d2ed20 | 322 | } |
Lerche | 0:fef366d2ed20 | 323 | |
Lerche | 0:fef366d2ed20 | 324 | dwTransferSize = iLen; |
Lerche | 0:fef366d2ed20 | 325 | if ((dwTransferSize == 0) || fDevIn) { |
Lerche | 0:fef366d2ed20 | 326 | // data from device-to-host |
Lerche | 0:fef366d2ed20 | 327 | eState = eDataIn; |
Lerche | 0:fef366d2ed20 | 328 | HandleDataIn(0); |
Lerche | 0:fef366d2ed20 | 329 | } |
Lerche | 0:fef366d2ed20 | 330 | else { |
Lerche | 0:fef366d2ed20 | 331 | // data from host-to-device |
Lerche | 0:fef366d2ed20 | 332 | eState = eDataOut; |
Lerche | 0:fef366d2ed20 | 333 | } |
Lerche | 0:fef366d2ed20 | 334 | break; |
Lerche | 0:fef366d2ed20 | 335 | |
Lerche | 0:fef366d2ed20 | 336 | case eDataOut: |
Lerche | 0:fef366d2ed20 | 337 | HandleDataOut(); |
Lerche | 0:fef366d2ed20 | 338 | break; |
Lerche | 0:fef366d2ed20 | 339 | |
Lerche | 0:fef366d2ed20 | 340 | case eDataIn: |
Lerche | 0:fef366d2ed20 | 341 | case eCSW: |
Lerche | 0:fef366d2ed20 | 342 | // iChunk = USBHwEPRead(bEP, NULL, 0); |
Lerche | 0:fef366d2ed20 | 343 | uint8_t dummy[64]; |
Lerche | 0:fef366d2ed20 | 344 | int idummy; |
Lerche | 0:fef366d2ed20 | 345 | usbdev.read(EPBULK_OUT, dummy, (uint16_t*)&idummy, MAX_PACKET_SIZE_EPBULK); |
Lerche | 0:fef366d2ed20 | 346 | DBG("Phase error in state %d, %d bytes\n", eState, iChunk); |
Lerche | 0:fef366d2ed20 | 347 | eState = eCBW; |
Lerche | 0:fef366d2ed20 | 348 | break; |
Lerche | 0:fef366d2ed20 | 349 | |
Lerche | 0:fef366d2ed20 | 350 | case eStalled: |
Lerche | 0:fef366d2ed20 | 351 | // keep stalling |
Lerche | 0:fef366d2ed20 | 352 | usbdev.stallEndpoint(EPBULK_OUT); |
Lerche | 0:fef366d2ed20 | 353 | break; |
Lerche | 0:fef366d2ed20 | 354 | |
Lerche | 0:fef366d2ed20 | 355 | default: |
Lerche | 0:fef366d2ed20 | 356 | DBG("Invalid state %d\n", eState); |
Lerche | 0:fef366d2ed20 | 357 | break; |
Lerche | 0:fef366d2ed20 | 358 | } |
Lerche | 0:fef366d2ed20 | 359 | } |
Lerche | 0:fef366d2ed20 | 360 | |
Lerche | 0:fef366d2ed20 | 361 | |
Lerche | 0:fef366d2ed20 | 362 | /** |
Lerche | 0:fef366d2ed20 | 363 | Handles the BOT bulk IN endpoint |
Lerche | 0:fef366d2ed20 | 364 | |
Lerche | 0:fef366d2ed20 | 365 | @param [in] bEP Endpoint number |
Lerche | 0:fef366d2ed20 | 366 | @param [in] bEPStatus Endpoint status (indicates NAK, STALL, etc) |
Lerche | 0:fef366d2ed20 | 367 | |
Lerche | 0:fef366d2ed20 | 368 | */ |
Lerche | 0:fef366d2ed20 | 369 | void MSCBotBulkIn() |
Lerche | 0:fef366d2ed20 | 370 | { |
Lerche | 0:fef366d2ed20 | 371 | DBG("MSCBotBulkIn: %d\r\n", eState); |
Lerche | 0:fef366d2ed20 | 372 | switch (eState) { |
Lerche | 0:fef366d2ed20 | 373 | |
Lerche | 0:fef366d2ed20 | 374 | case eCBW: |
Lerche | 0:fef366d2ed20 | 375 | case eDataOut: |
Lerche | 0:fef366d2ed20 | 376 | // ignore possibly old ACKs |
Lerche | 0:fef366d2ed20 | 377 | break; |
Lerche | 0:fef366d2ed20 | 378 | |
Lerche | 0:fef366d2ed20 | 379 | case eDataIn: |
Lerche | 0:fef366d2ed20 | 380 | HandleDataIn(1); |
Lerche | 0:fef366d2ed20 | 381 | break; |
Lerche | 0:fef366d2ed20 | 382 | |
Lerche | 0:fef366d2ed20 | 383 | case eCSW: |
Lerche | 0:fef366d2ed20 | 384 | // wait for an IN token, then send the CSW |
Lerche | 0:fef366d2ed20 | 385 | //USBHwEPWrite(MSC_BULK_IN_EP, (uint8_t *)&CSW, 13); |
Lerche | 0:fef366d2ed20 | 386 | usbdev.writeNB(EPBULK_IN, (uint8_t *)&CSW, 13, MAX_PACKET_SIZE_EPBULK); |
Lerche | 0:fef366d2ed20 | 387 | eState = eCBW; |
Lerche | 0:fef366d2ed20 | 388 | break; |
Lerche | 0:fef366d2ed20 | 389 | |
Lerche | 0:fef366d2ed20 | 390 | case eStalled: |
Lerche | 0:fef366d2ed20 | 391 | // keep stalling |
Lerche | 0:fef366d2ed20 | 392 | usbdev.stallEndpoint(EPBULK_IN); |
Lerche | 0:fef366d2ed20 | 393 | break; |
Lerche | 0:fef366d2ed20 | 394 | |
Lerche | 0:fef366d2ed20 | 395 | default: |
Lerche | 0:fef366d2ed20 | 396 | DBG("Invalid state %d\n", eState); |
Lerche | 0:fef366d2ed20 | 397 | break; |
Lerche | 0:fef366d2ed20 | 398 | } |
Lerche | 0:fef366d2ed20 | 399 | } |
Lerche | 0:fef366d2ed20 | 400 |