00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00036 #include <string.h>
00037
00038 #include "lpcusb\target\type.h"
00039 #include "lpcusb\target\debug.h"
00040 #include "lpcusb\target\usbapi.h"
00041 #include "msc_bot.h"
00042 #include "msc_scsi.h"
00043
00044
00046 typedef struct {
00047 U32 dwCBWSignature;
00048 U32 dwCBWTag;
00049 U32 dwCBWDataTransferLength;
00050 U8 bmCBWFlags;
00051 U8 bCBWLun;
00052 U8 bCBWCBLength;
00053 U8 CBWCB[16];
00054 } TCBW;
00055
00057 typedef struct {
00058 U32 dwCSWSignature;
00059 U32 dwCSWTag;
00060 U32 dwCSWDataResidue;
00061 U8 bmCSWStatus;
00062 } TCSW;
00063
00065 typedef enum {
00066 eCBW,
00067 eDataOut,
00068 eDataIn,
00069 eCSW,
00070 eStalled
00071 } EBotState;
00072
00073
00074 #define CBW_SIGNATURE 0x43425355
00075 #define CSW_SIGNATURE 0x53425355
00077 #define STATUS_PASSED 0x00
00078 #define STATUS_FAILED 0x01
00079 #define STATUS_PHASE_ERR 0x02
00081 static U32 dwTransferSize;
00082 static U32 dwOffset;
00084 static TCBW CBW;
00085 static TCSW CSW;
00086
00087 static EBotState eState;
00088
00089 static U8 *pbData;
00090
00091
00092
00096 void MSCBotReset(void)
00097 {
00098 DBG("BOT reset in state %d\n", eState);
00099
00100 eState = eCBW;
00101
00102 SCSIReset();
00103 }
00104
00105
00111 static void SendCSW(U8 bStatus)
00112 {
00113 int iResidue;
00114
00115 iResidue = CBW.dwCBWDataTransferLength - dwTransferSize;
00116
00117
00118 CSW.dwCSWSignature = CSW_SIGNATURE;
00119 CSW.dwCSWTag = CBW.dwCBWTag;
00120 CSW.dwCSWDataResidue = MAX(iResidue, 0);
00121 CSW.bmCSWStatus = bStatus;
00122
00123 DBG("CSW: status=%x, residue=%d\n", bStatus, CSW.dwCSWDataResidue);
00124
00125
00126 eState = eCSW;
00127 }
00128
00129
00138 static BOOL CheckCBW(TCBW *pCBW, int iLen)
00139 {
00140
00141 if (iLen != 31) {
00142 DBG("Invalid length (%d)\n", iLen);
00143 return FALSE;
00144 }
00145 if (pCBW->dwCBWSignature != CBW_SIGNATURE) {
00146 DBG("Invalid signature %x\n", pCBW->dwCBWSignature);
00147 return FALSE;
00148 }
00149
00150
00151 if (pCBW->bCBWLun != 0) {
00152 DBG("Invalid LUN %d\n", pCBW->bCBWLun);
00153 return FALSE;
00154 }
00155 if ((pCBW->bCBWCBLength < 1) || (pCBW->bCBWCBLength > 16)) {
00156 DBG("Invalid CB len %d\n", pCBW->bCBWCBLength);
00157 return FALSE;
00158 }
00159 return TRUE;
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 static void BOTStall(void)
00173 {
00174 if ((CBW.bmCBWFlags & 0x80) || (CBW.dwCBWDataTransferLength == 0)) {
00175
00176 USBHwEPStall(MSC_BULK_IN_EP, TRUE);
00177 }
00178 else {
00179
00180 USBHwEPStall(MSC_BULK_OUT_EP, TRUE);
00181 }
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191 static void HandleDataIn(void)
00192 {
00193 int iChunk;
00194
00195
00196 pbData = SCSIHandleData(CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset);
00197 if (pbData == NULL) {
00198 BOTStall();
00199 SendCSW(STATUS_FAILED);
00200 return;
00201 }
00202
00203
00204 if (dwOffset < dwTransferSize) {
00205 iChunk = MIN(64, dwTransferSize - dwOffset);
00206 USBHwEPWrite(MSC_BULK_IN_EP, pbData, iChunk);
00207 dwOffset += iChunk;
00208 }
00209
00210
00211 if (dwOffset == dwTransferSize) {
00212 if (dwOffset != CBW.dwCBWDataTransferLength) {
00213
00214 DBG("stalling DIN");
00215 BOTStall();
00216 }
00217
00218 SendCSW(STATUS_PASSED);
00219 }
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229 static void HandleDataOut(void)
00230 {
00231 int iChunk;
00232
00233 if (dwOffset < dwTransferSize) {
00234
00235 iChunk = USBHwEPRead(MSC_BULK_OUT_EP, pbData, dwTransferSize - dwOffset);
00236
00237 pbData = SCSIHandleData(CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset);
00238 if (pbData == NULL) {
00239 BOTStall();
00240 SendCSW(STATUS_FAILED);
00241 return;
00242 }
00243 dwOffset += iChunk;
00244 }
00245
00246
00247 if (dwOffset == dwTransferSize) {
00248 if (dwOffset != CBW.dwCBWDataTransferLength) {
00249
00250 DBG("stalling DOUT");
00251 BOTStall();
00252 }
00253 SendCSW(STATUS_PASSED);
00254 }
00255 }
00256
00257
00265 void MSCBotBulkOut(U8 bEP, U8 bEPStatus)
00266 {
00267 int iLen, iChunk;
00268 BOOL fHostIn, fDevIn;
00269
00270
00271 if (bEPStatus & EP_STATUS_STALLED) {
00272 return;
00273 }
00274
00275 switch (eState) {
00276
00277 case eCBW:
00278 iLen = USBHwEPRead(bEP, (U8 *)&CBW, sizeof(CBW));
00279
00280
00281 if (!CheckCBW(&CBW, iLen)) {
00282
00283 USBHwEPStall(MSC_BULK_IN_EP, TRUE);
00284 USBHwEPStall(MSC_BULK_OUT_EP, TRUE);
00285 eState = eStalled;
00286 break;
00287 }
00288
00289 DBG("CBW: len=%d, flags=%x, cmd=%x, cmdlen=%d\n",
00290 CBW.dwCBWDataTransferLength, CBW.bmCBWFlags, CBW.CBWCB[0], CBW.bCBWCBLength);
00291
00292 dwOffset = 0;
00293 dwTransferSize = 0;
00294 fHostIn = ((CBW.bmCBWFlags & 0x80) != 0);
00295
00296
00297 pbData = SCSIHandleCmd(CBW.CBWCB, CBW.bCBWCBLength, &iLen, &fDevIn);
00298 if (pbData == NULL) {
00299
00300 BOTStall();
00301 SendCSW(STATUS_FAILED);
00302 break;
00303 }
00304
00305
00306 if ((iLen > 0) &&
00307 ((fHostIn && !fDevIn) ||
00308 (!fHostIn && fDevIn))) {
00309 DBG("Host and device disagree on direction\n");
00310 BOTStall();
00311 SendCSW(STATUS_PHASE_ERR);
00312 break;
00313 }
00314
00315
00316 if (iLen > CBW.dwCBWDataTransferLength) {
00317 DBG("Negative residue\n");
00318 BOTStall();
00319 SendCSW(STATUS_PHASE_ERR);
00320 break;
00321 }
00322
00323 dwTransferSize = iLen;
00324 if ((dwTransferSize == 0) || fDevIn) {
00325
00326 eState = eDataIn;
00327 HandleDataIn();
00328 }
00329 else {
00330
00331 eState = eDataOut;
00332 }
00333 break;
00334
00335 case eDataOut:
00336 HandleDataOut();
00337 break;
00338
00339 case eDataIn:
00340 case eCSW:
00341 iChunk = USBHwEPRead(bEP, NULL, 0);
00342 DBG("Phase error in state %d, %d bytes\n", eState, iChunk);
00343 eState = eCBW;
00344 break;
00345
00346 case eStalled:
00347
00348 USBHwEPStall(MSC_BULK_OUT_EP, TRUE);
00349 break;
00350
00351 default:
00352 DBG("Invalid state %d\n", eState);
00353 ASSERT(FALSE);
00354 break;
00355 }
00356 }
00357
00358
00366 void MSCBotBulkIn(U8 bEP, U8 bEPStatus)
00367 {
00368
00369 if (bEPStatus & EP_STATUS_STALLED) {
00370 return;
00371 }
00372
00373 switch (eState) {
00374
00375 case eCBW:
00376 case eDataOut:
00377
00378 break;
00379
00380 case eDataIn:
00381 HandleDataIn();
00382 break;
00383
00384 case eCSW:
00385
00386 USBHwEPWrite(MSC_BULK_IN_EP, (U8 *)&CSW, 13);
00387 eState = eCBW;
00388 break;
00389
00390 case eStalled:
00391
00392 USBHwEPStall(MSC_BULK_IN_EP, TRUE);
00393 break;
00394
00395 default:
00396 DBG("Invalid state %d\n", eState);
00397 ASSERT(FALSE);
00398 break;
00399 }
00400 }
00401
00402