Exemplo n.º 1
0
/**
 * Media control, for spindle motor and media tray or door.
 * This includes CDROM, TAPE and anything with a media loader.
 *
 * @param lun Logical Unit Number
 * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media
 * @return 0 on success
 */
uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) {
        Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
        Notify(PSTR("-----------------\r\n"), 0x80);
        SetCurLUN(lun);
        uint8_t rcode = MASS_ERR_UNIT_NOT_READY;
        if (bAddress) {
                CommandBlockWrapper cbw;

                cbw.dCBWSignature = MASS_CBW_SIGNATURE;
                cbw.dCBWTag = ++dCBWTag;
                cbw.dCBWDataTransferLength = 0;
                cbw.bmCBWFlags = MASS_CMD_DIR_OUT;
                cbw.bmCBWLUN = lun;
                cbw.bmCBWCBLength = 6;

                for (uint8_t i = 0; i < 16; i++)
                        cbw.CBWCB[i] = 0;

                cbw.CBWCB[0] = SCSI_CMD_START_STOP_UNIT;
                cbw.CBWCB[1] = lun << 5;
                cbw.CBWCB[4] = ctl & 0x03;

                rcode = HandleSCSIError(Transaction(&cbw, 0, NULL, 0));
        }
        return rcode;
}
Exemplo n.º 2
0
/**
 * For driver use only. Used during Driver Init
 *
 * @param lun Logical Unit Number
 * @param bsize
 * @param buf
 * @return
 */
uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) {
        Notify(PSTR("\r\nInquiry\r\n"), 0x80);
        Notify(PSTR("---------\r\n"), 0x80);

        CommandBlockWrapper cbw;
        SetCurLUN(lun);
        cbw.dCBWSignature = MASS_CBW_SIGNATURE;
        cbw.dCBWTag = ++dCBWTag;
        cbw.dCBWDataTransferLength = bsize;
        cbw.bmCBWFlags = MASS_CMD_DIR_IN;
        cbw.bmCBWLUN = lun;
        cbw.bmCBWCBLength = 6;

        for (uint8_t i = 0; i < 16; i++)
                cbw.CBWCB[i] = 0;

        cbw.CBWCB[0] = SCSI_CMD_INQUIRY;
        cbw.CBWCB[1] = lun << 5;
        cbw.CBWCB[4] = bsize;

        uint8_t rc = HandleSCSIError(Transaction(&cbw, bsize, buf, 0));
#if 0
        if (!rc) {
                printf("LUN %i `", lun);
                for (int i = 8; i < 36; i++) printf("%c", buf[i]);
                printf("'\r\nQualifier %1.1X ", (buf[0]&0xE0) >> 5);
                printf("Device type %2.2X ", buf[0]&0x1f);
                printf("RMB %1.1X ", buf[1]&0x80 >> 7);
                printf("SSCS% 1.1X ", buf[5]&0x80 >> 7);
                uint8_t sv = buf[2];
                printf("SCSI version %2.2X\r\nDevice conforms to ", sv);
                switch (sv) {
                        case 0:
                                printf("No specific");
                                break;
                                /*
                                case 1:
                                        printf("");
                                        break;
                                 */
                        case 2:
                                printf("ANSI 2");
                                break;
                        case 3:
                                printf("ANSI INCITS 301-1997 (SPC)");
                                break;
                        case 4:
                                printf("ANSI INCITS 351-2001 (SPC-2)");
                                break;
                        case 5:
                                printf("ANSI INCITS 408-2005 (SPC-4)");
                                break;
                        case 6:
                                printf("T10/1731-D (SPC-4)");
                                break;
                        default:
                                printf("unknown");
                }
                printf(" standards.\r\n");
        }
Exemplo n.º 3
0
/**
 * Media control, for spindle motor and media tray or door.
 * This includes CDROM, TAPE and anything with a media loader.
 *
 * @param lun Logical Unit Number
 * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media
 * @return 0 on success
 */
uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) {
        Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
        Notify(PSTR("-----------------\r\n"), 0x80);

        uint8_t rcode = MASS_ERR_UNIT_NOT_READY;
        if(bAddress) {
                CDB6_t cdb = CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0);
                rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_OUT);
        } else {
                SetCurLUN(lun);
        }
        return rcode;
}
Exemplo n.º 4
0
/**
 * Write data to media
 *
 * @param lun Logical Unit Number
 * @param addr LBA address on media to write
 * @param bsize size of a block (we should probably use the cached size)
 * @param blocks how many blocks to write
 * @param buf memory that contains the data to write
 * @return 0 on success
 */
uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) {
        if (!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
        if (!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED;
        Notify(PSTR("\r\nWrite LUN:\t"), 0x80);
        D_PrintHex<uint8_t > (lun, 0x90);
        //printf("LUN=%i LBA=%8.8X BLOCKS=%i SIZE=%i\r\n", lun, addr, blocks, bsize);
        Notify(PSTR("\r\nLBA:\t\t"), 0x90);
        D_PrintHex<uint32_t > (addr, 0x90);
        Notify(PSTR("\r\nblocks:\t\t"), 0x90);
        D_PrintHex<uint8_t > (blocks, 0x90);
        Notify(PSTR("\r\nblock size:\t"), 0x90);
        D_PrintHex<uint16_t > (bsize, 0x90);
        Notify(PSTR("\r\n---------\r\n"), 0x80);
        //MediaCTL(lun, 0x01);
        CommandBlockWrapper cbw;

again:
        cbw.dCBWSignature = MASS_CBW_SIGNATURE;
        cbw.dCBWTag = ++dCBWTag;
        cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks);
        cbw.bmCBWFlags = MASS_CMD_DIR_OUT;
        cbw.bmCBWLUN = lun;
        cbw.bmCBWCBLength = 10;

        for (uint8_t i = 0; i < 16; i++)
                cbw.CBWCB[i] = 0;

        cbw.CBWCB[0] = SCSI_CMD_WRITE_10;
        cbw.CBWCB[1] = lun << 5;
        cbw.CBWCB[2] = ((addr >> 24) & 0xff);
        cbw.CBWCB[3] = ((addr >> 16) & 0xff);
        cbw.CBWCB[4] = ((addr >> 8) & 0xff);
        cbw.CBWCB[5] = (addr & 0xff);
        cbw.CBWCB[8] = 1;

        SetCurLUN(lun);
        uint8_t er = HandleSCSIError(Transaction(&cbw, bsize, (void*)buf, 0));
        if (er == MASS_ERR_WRITE_STALL) {
                MediaCTL(lun, 1);
                delay(150);
                if (!TestUnitReady(lun)) goto again;
        }
        return er;
}
Exemplo n.º 5
0
/**
 * Lock or Unlock the tray or door on device.
 * Caution: Some devices with buggy firmware will lock up.
 *
 * @param lun Logical Unit Number
 * @param lock 1 to lock, 0 to unlock
 * @return
 */
uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) {
        Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
        Notify(PSTR("---------\r\n"), 0x80);

        CommandBlockWrapper cbw;
        SetCurLUN(lun);
        cbw.dCBWSignature = MASS_CBW_SIGNATURE;
        cbw.dCBWTag = ++dCBWTag;
        cbw.dCBWDataTransferLength = 0;
        cbw.bmCBWFlags = MASS_CMD_DIR_IN;
        cbw.bmCBWLUN = lun;
        cbw.bmCBWCBLength = 6;

        for (uint8_t i = 0; i < 16; i++)
                cbw.CBWCB[i] = 0;

        cbw.CBWCB[0] = SCSI_CMD_PREVENT_REMOVAL;
        cbw.CBWCB[4] = lock;

        return (HandleSCSIError(Transaction(&cbw, 0, NULL, 0)));

}
Exemplo n.º 6
0
/**
 * For driver use only.
 *
 * @param pcbw
 * @param buf_size
 * @param buf
 * @param flags
 * @return
 */
uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf
#if MS_WANT_PARSER
        , uint8_t flags
#endif
        ) {

#if MS_WANT_PARSER
        uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength;
        printf("Transfersize %i\r\n", bytes);
        delay(1000);

        bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK;
#else
        uint16_t bytes = buf_size;
#endif
        bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN;
        uint8_t ret = 0;
        uint8_t usberr;
        CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles.
        SetCurLUN(pcbw->bmCBWLUN);
        ErrorMessage<uint32_t > (PSTR("CBW.dCBWTag"), pcbw->dCBWTag);

        while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) delay(1);

        ret = HandleUsbError(usberr, epDataOutIndex);
        //ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex);
        if(ret) {
                ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret);
        } else {
                if(bytes) {
                        if(!write) {
#if MS_WANT_PARSER
                                if(callback) {
                                        uint8_t rbuf[bytes];
                                        while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) delay(1);
                                        if(usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0);
                                } else {
#endif
                                        while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) delay(1);
#if MS_WANT_PARSER

                                }
#endif
                                ret = HandleUsbError(usberr, epDataInIndex);
                        } else {
                                while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) delay(1);
                                ret = HandleUsbError(usberr, epDataOutIndex);
                        }
                        if(ret) {
                                ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret);
                        }
                }
        }

        {
                bytes = sizeof (CommandStatusWrapper);
                int tries = 2;
                while(tries--) {
                        while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) delay(1);
                        if(!usberr) break;
                        ClearEpHalt(epDataInIndex);
                        if(tries) ResetRecovery();
                }
                if(!ret) {
                        Notify(PSTR("CBW:\t\tOK\r\n"), 0x80);
                        Notify(PSTR("Data Stage:\tOK\r\n"), 0x80);
                } else {
                        // Throw away csw, IT IS NOT OF ANY USE.
                        ResetRecovery();
                        return ret;
                }
                ret = HandleUsbError(usberr, epDataInIndex);
                if(ret) {
                        ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret);
                }
                if(usberr == hrSUCCESS) {
                        if(IsValidCSW(&csw, pcbw)) {
                                //ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag);
                                //ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus);
                                //ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue);
                                Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80);
                                return csw.bCSWStatus;
                        } else {
                                // NOTE! Sometimes this is caused by the reported residue being wrong.
                                // Get a different device. It isn't compliant, and should have never passed Q&A.
                                // I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter.
                                // Other devices that exhibit this behavior exist in the wild too.
                                // Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk
                                Notify(PSTR("Invalid CSW\r\n"), 0x80);
                                ResetRecovery();
                                //return MASS_ERR_SUCCESS;
                                return MASS_ERR_INVALID_CSW;
                        }
                }
        }
        return ret;
}