Almost identical to USBHostShell; reads all endpoint descriptors

Dependents:   myBlueUSB mbed_TANK_Kinect myBlueUSB_ros myBlueUSB_localfix

MassStorage.h

Committer:
networker
Date:
2011-07-01
Revision:
3:58c785c2b381

File content as of revision 3:58c785c2b381:

#ifndef MASSSTORAGE_H
#define MASSSTORAGE_H

#include "Utils.h"
#include "USBHost.h"


#define ERR_BAD_CSW_SIGNATURE -200

#define CBW_SIGNATURE  0x43425355
#define CSW_SIGNATURE  0x53425355

#define BULK_ENDPOINT_IN    0x81
#define BULK_ENDPOINT_OUT   0x02

//  Command Block
typedef struct {
    u32 Signature;
    u32 Tag;
    u32 TransferLength;
    u8 Flags;
    u8 LUN;
    u8 CBLength;
    u8 CB[16];   // only 6 really
} CBW;

//  Status block
typedef struct {
    u32 Signature;
    u32 Tag;
    u32 DataResidue;
    u8 Status;
} CSW;

class USBSCSI {
protected:
    int _device;
    unsigned char epin, epout;
public:
    USBSCSI() : _device(0) {}

    void SetDevice(int device, unsigned char in, unsigned char out)
    {
        _device = device;
        epin = in;
        epout = out;
    }
protected:    
    int DoSCSI(const u8* cmd, int cmdLen, int flags, u8* data, u32 transferLen) {
        CBW cbw;
        cbw.Signature = CBW_SIGNATURE;
        cbw.Tag = 0;
        cbw.TransferLength = transferLen;
        cbw.Flags = flags;
        cbw.LUN = 0;
        cbw.CBLength = cmdLen;
        memset(cbw.CB,0,sizeof(cbw.CB));
        memcpy(cbw.CB,cmd,cmdLen);

        int r;
        //r = USBBulkTransfer(device,0x01,(u8*)&cbw,31);   // Send the command
        r = USBBulkTransfer(_device,epout,(u8*)&cbw,31);   // Send the command
        if (r < 0) {
            printf("first transfer returns %d\n", r);
            return r;
        }
        if (data) {
            //r = USBBulkTransfer(device,flags | 1,data,transferLen);
            r = USBBulkTransfer(_device,flags ? epin : epout,data,transferLen);
            if (r < 0) {
                printf("second transfer returns %d (flags=%02xH)\n", r, flags);
                return r;
            }
        }

        CSW csw;
        csw.Signature = 0;
        //r = USBBulkTransfer(device,0x81,(u8*)&csw,13);
        r = USBBulkTransfer(_device,epin,(u8*)&csw,13);
        if (r < 0) {
            printf("third transfer returns %d\n", r);
            return r;
        }
        if (csw.Signature != CSW_SIGNATURE)
            return ERR_BAD_CSW_SIGNATURE;

        // ModeSense?
        if (csw.Status == 1 && cmd[0] != 3)
            return SCSIRequestSense();

        return csw.Status;
    }

    int SCSITestUnitReady() {
        u8 cmd[6];
        memset(cmd,0,6);
        return DoSCSI(cmd,6,DEVICE_TO_HOST,0,0);
    }

    int SCSIRequestSense() {
        u8 cmd[6] = {0x03,0,0,0,18,0};
        u8 result[18];
        int r = DoSCSI(cmd,6,DEVICE_TO_HOST,result,18);
        return r;
    }

    int SCSIInquiry() {
        u8 cmd[6] = {0x12,0,0,0,36,0};
        u8 result[36+2];
        result[36] = '\n';
        result[37] = 0;
        int r = DoSCSI(cmd,6,DEVICE_TO_HOST,result,36);
        if (r == 0)
            printf((const char*)result + 8);
        return r;
    }

    int SCSIReadCapacity(u32* blockCount, u32* blockSize) {
        u8 cmd[10] = {0x25,0,0,0,8,0,0,0,0,0};
        u8 result[8];
        *blockSize = 0;
        *blockCount = 0;
        int r = DoSCSI(cmd,10,DEVICE_TO_HOST,result,8);
        if (r == 0) {
            *blockCount = BE32(result);
            *blockSize = BE32(result+4);
        }
        return r;
    }

    int SCSITransfer(u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize, int direction) {
        //  USB hardware will only do 4k per transfer
        while (blockCount*blockSize > 4096) {
            int count = 4096/blockSize;
            int r = SCSITransfer(blockAddr,count,dst,blockSize,direction);
            dst += count*blockSize;
            blockAddr += count;
            blockCount -= count;
        }

        u8 cmd[10];
        memset(cmd,0,10);
        cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A;
        BE32(blockAddr,cmd+2);
        BE16(blockCount,cmd+7);
        return DoSCSI(cmd,10,direction,dst,blockSize*blockCount);
    }
};
#endif