Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Src/GetDevicesToTest.c
/* GetDevicesToTest.c */ |
/* |
* GetDevicesToTest.c |
* Copyright © 93 Apple Computer Inc. All Rights Reserved. |
* |
* Run the dialog until the user has had enough. |
*/ |
#include "SCSIAsyncSample.h" |
#include "DialogUtilities.h" |
#include "SCSIDefinitions.h" |
void SetupDialog(void); |
void MakeNewInfoRecord(void); |
void RefreshParamBlock(void); |
void RefreshDeviceInfo(void); |
Boolean CheckInfoRecord(void); |
void SaveInfoRecord(void); |
OSErr SetupGetSCSIParamBlock(void); |
OSErr SetupDeviceInquiry(void); |
OSErr SetupReadCapacity(void); |
void StoreDeviceString( |
unsigned char *dst, |
unsigned char *src, |
short srcLength |
); |
unsigned long GetFourBytes( |
unsigned char *src |
); |
/* |
* These are state flags that are valid only for the current |
* dialog. |
*/ |
DialogPtr gDialog; |
InfoPtr gCurrentInfoPtr; |
#define INFO (*gCurrentInfoPtr) |
short gThreadIndex; |
void |
GetDevicesToTest(void) |
{ |
GrafPtr savePort; |
short itemHit; |
Boolean needNewInfoRecord; |
Boolean needToRefreshDeviceInfo; |
Boolean needToRefreshParamBlock; |
Boolean needToUpdateDialogValues; |
GetPort(&savePort); |
gDialog = GetNewDialog(DLOG_Query, NULL, (WindowPtr) -1L); |
SetCheckBox(gDialog, kQueryEnableAsync, FALSE); |
SetCheckBox(gDialog, kQueryEnableDisconnect, FALSE); |
SetDialogValue(gDialog, kQueryTotalRequests, 100); |
/* |
* For my system: prime the device to point to the CD-Rom |
*/ |
SetDialogValue(gDialog, kQueryHostBus, 1); |
SetDialogValue(gDialog, kQueryTargetID, 3); |
/* */ |
ShowWindow(gDialog); |
SetPort(gDialog); |
gThreadIndex = 0; |
needNewInfoRecord = TRUE; |
InitCursor(); |
for (;;) { |
if (needNewInfoRecord) { |
MakeNewInfoRecord(); |
needNewInfoRecord = FALSE; |
needToRefreshParamBlock = TRUE; |
needToUpdateDialogValues = TRUE; |
} |
if (needToRefreshParamBlock) { |
RefreshParamBlock(); |
needToRefreshParamBlock = FALSE; |
needToRefreshDeviceInfo = (INFO.pb != NULL); |
needToUpdateDialogValues = TRUE; |
} |
if (needToRefreshDeviceInfo) { |
RefreshDeviceInfo(); |
needToRefreshDeviceInfo = FALSE; |
needToUpdateDialogValues = TRUE; |
} |
if (needToUpdateDialogValues) { |
SetupDialog(); |
needToUpdateDialogValues = FALSE; |
} |
ModalDialog(NumericFilter, &itemHit); |
switch (itemHit) { |
case kQueryTest: |
if (CheckInfoRecord()) { |
SaveInfoRecord(); |
needNewInfoRecord = TRUE; |
} |
break; |
case kQueryFinished: |
if (gCurrentInfoPtr != NULL) |
DisposePtr((Ptr) gCurrentInfoPtr); |
goto exit; |
case kQueryHostBus: |
INFO.deviceIdent.bus = GetDialogValue(gDialog, kQueryHostBus); |
needToRefreshParamBlock = TRUE; |
break; |
case kQueryTargetID: |
INFO.deviceIdent.targetID = GetDialogValue(gDialog, kQueryTargetID); |
needToRefreshDeviceInfo = TRUE; |
break; |
case kQueryEnableAsync: |
SelectCheckBox(gDialog, kQueryEnableAsync, &INFO.enableAsync); |
break; |
case kQueryEnableDisconnect: |
SelectCheckBox(gDialog, kQueryEnableDisconnect, &INFO.enableDisconnect); |
break; |
case kQueryRandomSeek: |
SelectCheckBox(gDialog, kQueryRandomSeek, &INFO.enableRandomSeek); |
break; |
case kQueryTotalRequests: |
INFO.totalTransfers = GetDialogValue(gDialog, kQueryTotalRequests); |
break; |
case kQueryBlocksPerTransfer: |
INFO.transferSizeBlocks = GetDialogValue(gDialog, kQueryBlocksPerTransfer); |
break; |
case kQueryTimeout: |
INFO.completionTimeout = GetDialogValue(gDialog, kQueryTimeout); |
default: |
break; |
} |
} |
exit: ; |
DisposDialog(gDialog); |
SetPort(savePort); |
} |
/* |
* MakeNewInfoRecord creates a new, empty, InfoRecord and sets state flags |
* so that the first call to SetupDialog fills in the information. |
*/ |
void |
MakeNewInfoRecord(void) |
{ |
Str255 work; |
gCurrentInfoPtr = (InfoPtr) NewPtrClear(sizeof (InfoRecord)); |
if (gCurrentInfoPtr == NULL) |
FatalError(MemError(), "\pCan't make new InfoRecord"); |
++gThreadIndex; |
INFO.threadIndex = gThreadIndex; |
INFO.deviceActive = FALSE; |
INFO.testCompleted = FALSE; |
INFO.completionTimeout = (60L * 15L); /* 15 seconds */ |
/* |
* Copy the current dialog parameters into the new info record. |
*/ |
INFO.deviceIdent.bus = GetDialogValue(gDialog, kQueryHostBus); |
INFO.deviceIdent.targetID = GetDialogValue(gDialog, kQueryTargetID); |
INFO.totalTransfers = GetDialogValue(gDialog, kQueryTotalRequests); |
INFO.transferSizeBlocks = GetDialogValue(gDialog, kQueryBlocksPerTransfer); |
INFO.completionTimeout = GetDialogValue(gDialog, kQueryTimeout); |
INFO.enableAsync = GetDialogButton(gDialog, kQueryEnableAsync) == kCheckedButton; |
INFO.enableDisconnect = GetDialogButton(gDialog, kQueryEnableDisconnect) == kCheckedButton; |
INFO.enableRandomSeek = GetDialogButton(gDialog, kQueryRandomSeek) == kCheckedButton; |
GetDateTime(&INFO.randomSeed); |
INFO.randomSeed ^= TickCount(); |
NumToString(INFO.threadIndex, work); |
pstrcat(work, "\p Thread index"); |
SetDialogText(gDialog, kQueryThreadNumber, work); |
} |
/* |
* SetupDialog is executed each time through the dialog loop to enable and |
* disable editable items and to get information about the active device. |
*/ |
void |
SetupDialog(void) |
{ |
EnableDialogItem(gDialog, kQueryTest, INFO.validDevice); |
EnableDialogItem(gDialog, kQueryTotalRequests, INFO.validDevice); |
EnableDialogItem(gDialog, kQueryBlocksPerTransfer, INFO.validDevice); |
EnableDialogItem(gDialog, kQueryTimeout, INFO.validDevice); |
EnableDialogItem(gDialog, kQueryEnableAsync, INFO.validDevice); |
EnableDialogItem(gDialog, kQueryEnableDisconnect, INFO.validDevice); |
if (INFO.validDevice) { |
SetDialogValue(gDialog, kQueryBlocksPerTransfer, INFO.transferSizeBlocks); |
SetDialogValue(gDialog, kQueryTimeout, INFO.completionTimeout); |
SetDialogText(gDialog, kQueryVendorID, (StringPtr) INFO.vendor); |
SetDialogText(gDialog, kQueryProduct, (StringPtr) INFO.product); |
SetDialogValue(gDialog, kQueryLogicalBlockLength, INFO.logicalBlockLength); |
SetDialogValue(gDialog, kQueryBlocksOnDevice, INFO.totalLogicalBlocks); |
} |
else { |
SetDialogText(gDialog, kQueryBlocksPerTransfer, "\p"); |
SetDialogText(gDialog, kQueryTimeout, "\p"); |
SetDialogText(gDialog, kQueryVendorID, "\p"); |
SetDialogText(gDialog, kQueryProduct, "\p"); |
SetDialogText(gDialog, kQueryLogicalBlockLength, "\p"); |
SetDialogText(gDialog, kQueryBlocksOnDevice, "\p"); |
} |
} |
void |
RefreshDeviceInfo(void) |
{ |
OSErr status; |
if (INFO.pb != NULL) { |
status = SetupDeviceInquiry(); |
if (status == noErr) |
status = SetupReadCapacity(); |
INFO.validDevice = (status == noErr); |
} |
} |
/* |
* Return TRUE if the InfoRecord is valid - this allocates the data buffer. |
*/ |
Boolean |
CheckInfoRecord(void) |
{ |
Str15 work; |
if (INFO.validDevice == FALSE) |
return (FALSE); |
else { |
INFO.totalTransfers = GetDialogValue(gDialog, kQueryTotalRequests); |
INFO.transferSizeBlocks = GetDialogValue(gDialog, kQueryBlocksPerTransfer); |
INFO.completionTimeout = GetDialogValue(gDialog, kQueryTimeout); |
INFO.bufferLength = (INFO.transferSizeBlocks * INFO.logicalBlockLength); |
INFO.bufferPtr = NewPtr(INFO.bufferLength); |
if (INFO.bufferPtr == NULL) { |
NumToString(INFO.bufferLength, work); |
ParamText(work, "\p", "\p", "\p"); |
StopAlert(ALRT_NoMemory, NULL); |
return (FALSE); |
} |
/* To do: read one block to verify that everything is in place */ |
return (TRUE); |
} |
} |
/* |
* SaveInfoRecord links this InfoRecord into the active queue. |
*/ |
void |
SaveInfoRecord(void) |
{ |
Enqueue((QElemPtr) gCurrentInfoPtr, &infoPtrQueue); |
gCurrentInfoPtr = NULL; |
} |
/* |
* Get the SCSI 4.3 Exec I/O parameter block. If this succeeds, |
* INFO.pb points to the parameter block, and INFO.pbSize has |
* its length. On failure, INFO.pb is NULL and INFO.pbSize zero. |
*/ |
void |
RefreshParamBlock(void) |
{ |
OSErr status; |
SCSIBusInquiryPB pb; |
CLEAR(pb); |
pb.scsiPBLength = sizeof pb; |
pb.scsiFunctionCode = SCSIBusInquiry; |
pb.scsiCompletion = NULL; |
pb.scsiFlags = 0; |
pb.scsiDevice = INFO.deviceIdent; |
SCSIAction((SCSI_PB *) &pb); |
status = pb.scsiResult; |
if (status == noErr) { |
if (INFO.pb != NULL && INFO.pbSize != pb.scsiIOpbSize) { |
DisposePtr((Ptr) INFO.pb); |
INFO.pb = NULL; |
INFO.pbSize = 0; |
} |
if (INFO.pb == NULL) { |
INFO.pb = (SCSIExecIOPB *) NewPtr(pb.scsiIOpbSize); |
if (INFO.pb == NULL) |
status = MemError(); |
else { |
INFO.pbSize = pb.scsiIOpbSize; |
} |
} |
} |
if (status != noErr) { |
NonFatalError(status, "\pCan't allocate SCSI Parameter Block"); |
if (INFO.pb != NULL) { |
DisposePtr((Ptr) INFO.pb); |
INFO.pb = NULL; |
INFO.pbSize = 0; |
} |
} |
} |
/* |
* Get the Device Inquiry (vendor, product) data. Return error status. |
*/ |
OSErr |
SetupDeviceInquiry(void) |
{ |
OSErr status; |
SCSI_Inquiry_Data inquiryData; |
const SCSI_6_Byte_Command inquiryCmd = { |
kScsiCmdInquiry, 0, 0, 0, sizeof inquiryData, 0 |
}; |
status = DoSCSISynchronousIO( |
gCurrentInfoPtr, /* -> INFO */ |
(SCSI_CommandPtr) &inquiryCmd, /* Command */ |
scsiDirectionIn, /* Reading from device */ |
(Ptr) &inquiryData, /* -> data buffer */ |
sizeof inquiryData /* data buffer size */ |
); |
if (status == noErr) { |
StoreDeviceString(INFO.vendor, inquiryData.vendor, sizeof inquiryData.vendor); |
StoreDeviceString(INFO.product, inquiryData.product, sizeof inquiryData.product); |
} |
return (status); |
} |
/* |
* Get the drive capacity (blocks, logical block length) for the device. |
* Return error status. |
*/ |
OSErr |
SetupReadCapacity(void) |
{ |
OSErr status; |
SCSI_Capacity_Data capacityData; |
const SCSI_10_Byte_Command capacityCmd = { |
kScsiCmdReadCapacity, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
}; |
status = DoSCSISynchronousIO( |
gCurrentInfoPtr, /* -> INFO */ |
(SCSI_CommandPtr) &capacityCmd, /* Command */ |
scsiDirectionIn, /* Reading from device */ |
(Ptr) &capacityData, /* -> data buffer */ |
sizeof capacityData /* data buffer size */ |
); |
if (status == noErr) { |
INFO.totalLogicalBlocks = GetFourBytes(&capacityData.lbn4); |
INFO.logicalBlockLength = GetFourBytes(&capacityData.len4); |
} |
return (status); |
} |
void |
StoreDeviceString( |
unsigned char *dst, |
unsigned char *src, |
short srcLength |
) |
{ |
short i; |
for (i = srcLength; i > 0 && src[i - 1] == ' '; --i) |
; |
BlockMove(src, &dst[1], i); |
dst[0] = i; |
} |
unsigned long |
GetFourBytes( |
unsigned char *src |
) |
{ |
register unsigned long result; |
result = src[0] & 0xFF; |
result <<= 8; |
result |= (src[1] & 0xFF); |
result <<= 8; |
result |= (src[2] & 0xFF); |
result <<= 8; |
result |= (src[3] & 0xFF); |
return (result); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14