Question

I am trying to use DeviceIoControl() with SCSI_PASS_THROUGH_DIRECT, in order to fetch TRACK_INFO.

this code "works" but it comes back by setting ScsiStatus to 2.
There seems to be conflicting documentation on the size of the "track" data field. the mmc doc says it's 1 bit long, however, on the web i find references that it is 2 bits long.

however, either way, it fails.

i've racked my brain all day, i got nothin'. anyone understand this?

#define kSCSICmd_READ_TRACK_INFORMATION 0x52

// Read Track Information Format
struct CDTrackInfo
{
    UInt16 dataLength;
    UInt8  trackNumberLSB;
    UInt8  sessionNumberLSB;
    UInt8  reserved;
#ifdef __LITTLE_ENDIAN__
    UInt8  trackMode:4;
    UInt8  copy:1;
    UInt8  damage:1;
    UInt8  reserved3:2;

    UInt8  dataMode:4;
    UInt8  fixedPacket:1;
    UInt8  packet:1;
    UInt8  blank:1;
    UInt8  reservedTrack:1;

    UInt8  nextWritableAddressValid:1;
    UInt8  lastRecordedAddressValid:1;
    UInt8  reserved5:6;
#else /* !__LITTLE_ENDIAN__ */
    UInt8  reserved3:2;
    UInt8  damage:1;
    UInt8  copy:1;
    UInt8  trackMode:4;

    UInt8  reservedTrack:1;
    UInt8  blank:1;
    UInt8  packet:1;
    UInt8  fixedPacket:1;
    UInt8  dataMode:4;

    UInt8  reserved5:6;
    UInt8  lastRecordedAddressValid:1;
    UInt8  nextWritableAddressValid:1;
#endif /* !__LITTLE_ENDIAN__ */
    UInt32 trackStartAddress;
    UInt32 nextWritableAddress;
    UInt32 freeBlocks;
    UInt32 fixedPacketSize;
    UInt32 trackSize;
    UInt32 lastRecordedAddress;
    UInt8  trackNumberMSB;
    UInt8  sessionNumberMSB;
    UInt8  reserved6;
    UInt8  reserved7;
};
typedef struct CDTrackInfo CDTrackInfo;

/*
 from mmc r10a
 6.2.8 Read CD 
 table 140
 page 110
 */
typedef struct {
    UInt8       op_code;

    #if TARGET_RT_BIG_ENDIAN
        UInt8       reserved0       : 7;    //  <-- possibly 6?
        UInt8       track           : 1;    //  <-- possibly 2?
    #else
        UInt8       track           : 1;
        UInt8       reserved0       : 7;
    #endif

    UInt32      lba_or_track_number;
    UInt8       reserved1;
    UInt16      alloc_len;
    UInt8       control;
} SCSICommandDescriptorBlock_ReadTrackInfo;

OSStatus    CRawDiscReader::GetTrackInfo(int trackI, CDTrackInfo *trackInfoP)
{   
    OSStatus            err = noErr;

    if (i_deviceH == NULL) {
        ERR(Open());
    }

    if (!err) {
        SCSI_PASS_THROUGH_DIRECT        pass_thru = { 0 };
        SCSICommandDescriptorBlock_ReadTrackInfo&       cdb(*(SCSICommandDescriptorBlock_ReadTrackInfo *)&pass_thru.Cdb[0]);

        CF_ASSERT(sizeof(cdb) == kSCSICDBSize_10Byte);
        structclr(*trackInfoP);

        cdb.op_code                 = kSCSICmd_READ_TRACK_INFORMATION;
        cdb.track                   = true;
        cdb.lba_or_track_number     = trackI;
        cdb.alloc_len               = sizeof(CDTrackInfo);

        DWORD           numRead = 0;

        pass_thru.Length                    = sizeof(pass_thru);
        pass_thru.CdbLength                 = sizeof(cdb);
        pass_thru.DataIn                    = SCSI_IOCTL_DATA_IN;
        pass_thru.TimeOutValue              = kTimeOutSeconds;
        pass_thru.DataBuffer                = (PVOID)trackInfoP;
        pass_thru.DataTransferLength        = cdb.alloc_len;

        if (!DeviceIoControl(
            i_deviceH, 
            IOCTL_SCSI_PASS_THROUGH_DIRECT,
            (PVOID)&pass_thru,
            (DWORD)sizeof(pass_thru),
            (PVOID)&pass_thru,
            (DWORD)sizeof(pass_thru),
            &numRead, NULL)
        ) {
            err = GetLastError();
            LogErr("reading CD:", err);

        } else if (numRead != pass_thru.Length) {
            err = GetLastError();
            LogErr("reading CD:", err);
            err = noErr;
        }
    }

    if (err && err != ERR_Already_Reported) {
        #if OPT_WINOS
            if (err == ERROR_INVALID_PARAMETER) {
                err = paramErr;
            } else 
        #endif
        {
            err = EIO;
        }
    }

    return err;
}
Was it helpful?

Solution

the answer seems to be "don't use IOCTL_SCSI_PASS_THROUGH_DIRECT".

OSStatus    CRawDiscReader::GetTrackInfo(IDiscRecorder2Ex *discP, int trackI, CDTrackInfo *trackInfoP)
{
    OSStatus                            err = noErr;
    HRESULT                             resultL = 0;
    BYTE                                *dataP = NULL;
    ULONG_IMAPI2_TRACK_INFORMATION      outSize = 0;

    structclr(*trackInfoP);

    resultL = discP->GetTrackInformation(
        trackI, 
        IMAPI_READ_TRACK_ADDRESS_TYPE_TRACK, 
        &dataP, &outSize);

    XTE(TrapError("GetTrackInformation", resultL));

    if (!err) {
        CDTrackInfo     *returnInfoP = (CDTrackInfo *)dataP;

        *trackInfoP = *returnInfoP;
        CoTaskMemFree(dataP);
        dataP = NULL;

        SwapTrackInfo(trackInfoP);
    }

    return err;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top