Reputation: 154
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;
}
Upvotes: 0
Views: 233
Reputation: 154
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;
}
Upvotes: 0