2 // OS specific CDROM interface (Win32)
7 // OS dependent CDROM stuffola
20 DWORD remain = 0, sector = 0;
21 BYTE cdBuf[2532 * 10];
23 // Private function prototypes
26 HINSTANCE WNASPI32_handle = NULL; //Handle to ASPI for Win32 (WNASPI.DLL)
27 //WNASPI.DLL functions
28 DWORD (*ASPI_GetASPI32SupportInfo)(VOID);
29 DWORD (*ASPI_SendASPI32Command)(LPSRB);
30 //BOOL (*ASPI_GetASPI32Buffer)(PASPI32BUFF);
31 //BOOL (*ASPI_FreeASPI32Buffer)(PASPI32BUFF);
32 //BOOL (*ASPI_TranslateASPI32Address)(PDWORD, PDWORD);
34 byte DataBuf[2352]; //Buffer for holding data to/from drive
35 //************************************************************
39 // Load the WNASPI32.DLL and import the required functions, then initialise
45 SRB_GetSetTimeouts srbTimeouts;
47 WNASPI32_handle = LoadLibrary("WNASPI32"); //WNASPI32.DLL
51 WriteLog("CDINTF: Could not load WNASPI32.DLL\n");
56 ** Get the ASPI entry points. Note that only two functions are mandatory:
57 ** GetASPI32SupportInfo and SendASPI32Command. The code will run if the
58 ** others are not present.
60 ASPI_GetASPI32SupportInfo = (DWORD (*)(void))GetProcAddress(WNASPI32_handle, "GetASPI32SupportInfo");
61 ASPI_SendASPI32Command = (DWORD (*)(LPSRB))GetProcAddress(WNASPI32_handle, "SendASPI32Command");
62 //ASPI_GetASPI32Buffer = (BOOL (*)(PASPI32BUFF))GetProcAddress(WNASPI32_handle, "GetASPI32Buffer");
63 //ASPI_FreeASPI32Buffer = (BOOL (*)(PASPI32BUFF))GetProcAddress(WNASPI32_handle, "FreeASPI32Buffer");
64 //ASPI_TranslateASPI32Address = (BOOL (*)(PDWORD, PDWORD))GetProcAddress(WNASPI32_handle, "TranslateASPI32Address");
66 //Check if the 2 functions were imported.
67 if(!ASPI_GetASPI32SupportInfo || !ASPI_SendASPI32Command)
69 WriteLog("Could not import GetASPI32SupportInfo & SendASPI32Command functions from WNASPI32.DLL\n");
73 //Initialise Win ASPI 32 by calling ASPI_GetASPI32SupportInfo().
74 dwSupportInfo = ASPI_GetASPI32SupportInfo();
75 if (HIBYTE(LOWORD(dwSupportInfo)) != SS_COMP && HIBYTE(LOWORD(dwSupportInfo)) != SS_NO_ADAPTERS)
77 WriteLog("Could not initialise using GetASPI32SupportInfo function or no adapters\n");
82 ** Set timeouts for ALL devices to 15 seconds. Nothing we deal with should
83 ** take that long to do ANYTHING. We are just doing inquiries to most
84 ** devices, and then simple reads to CDs, disks, etc. so 10 seconds (even
85 ** if they have to spin up) should be plenty.
87 memset(&srbTimeouts, 0, sizeof(SRB_GetSetTimeouts));
88 srbTimeouts.SRB_Cmd = SC_GETSET_TIMEOUTS;
89 srbTimeouts.SRB_HaId = 0xFF;
90 srbTimeouts.SRB_Flags = SRB_DIR_OUT;
91 srbTimeouts.SRB_Target = 0xFF;
92 srbTimeouts.SRB_Lun = 0xFF;
93 srbTimeouts.SRB_Timeout = 15 * 2;
94 ASPI_SendASPI32Command(&srbTimeouts);
100 Sends a SRB (SCSI Request Block) to Win ASPI32 driver for processing and
101 waits for completion.
103 The SRB contains the CDB (Command Descriptor Block) which has the
104 raw SCSI command/info you want to send to the drive. So effectively
105 this is actually sending the SCSI command to the drive.
107 Note that this uses a Windows event to wait for the drive to reply back
108 which is efficient. If an event is not available (which should never
109 happen really) a loop is used to poll for reply back.
111 Both methods will wait infinitely - so the drive must reply back otherwise
112 this software will appear to hang. There seems to be no mechanism for
113 cancelling the SRB process - the Win ASPI 32 'SC_ABORT_SRB' command doesn't
116 BOOL SendASPICMD_and_wait(BYTE HA_ID, BYTE Target_ID, BYTE SRB_flags, DWORD Buffer_len,
117 PBYTE Buffer, BYTE CDB_len, PBYTE CDB)
120 HANDLE hevent_SRB; //A handle for a new Windows event
121 SRB_ExecSCSICmd SRB; //The SRB variable with CDB included
124 //Clear & setup the SRB for this command..
125 memset(&SRB, 0, sizeof(SRB_ExecSCSICmd)); //Set it to zeroes
126 memcpy(SRB.CDBByte, CDB, CDB_len); //Copy CDB into SRB
128 SRB.SRB_Cmd = SC_EXEC_SCSI_CMD;
129 SRB.SRB_HaId = HA_ID;
130 SRB.SRB_Target = Target_ID;
131 //SRB.SRB_Lun = 0; //It's already zero
132 SRB.SRB_Flags = SRB_flags;
133 SRB.SRB_BufLen = Buffer_len;
134 SRB.SRB_BufPointer = Buffer;
135 SRB.SRB_SenseLen = SENSE_LEN;
136 SRB.SRB_CDBLen = CDB_len;
141 ** Create an event (if possible) and issue the command. After sending
142 ** the command, wait for completion.
144 hevent_SRB = CreateEvent(NULL, TRUE, FALSE, NULL);
147 //Windows event method for waiting - efficient.
149 SRB.SRB_Flags |= SRB_EVENT_NOTIFY;
150 SRB.SRB_PostProc = (LPVOID)hevent_SRB;
152 //Send the SRB for processing.
153 dwASPIStatus = ASPI_SendASPI32Command((LPSRB)&SRB);
154 if (dwASPIStatus == SS_PENDING)
156 //Wait for reply back.
157 WaitForSingleObject(hevent_SRB, INFINITE);
159 CloseHandle(hevent_SRB);
163 //Polling method for waiting - not very efficient.
165 //Send the SRB for processing.
166 ASPI_SendASPI32Command((LPSRB)&SRB);
167 //Wait for reply back.
168 while(SRB.SRB_Status == SS_PENDING);
172 ** Check for errors. We'll retry on unit attention condition. Anything
173 ** else will generate an error msg.
175 if (SRB.SRB_Status != SS_COMP)
177 if (b_retry && (SRB.SRB_TargStat != STATUS_CHKCOND
178 || (SRB.SenseArea[2] & 0x0F) != KEY_UNITATT))
182 WriteLog("SCSI command failed.\n");
187 while (b_retry == FALSE);
193 Lists all available CDROM type drives. This includes:
200 It can only list the SCSI IDs not drive letters. Win ASPI 32 does
201 not provide a mechanism for this. You will have to use windows API
217 DWORD dwMaxTransferBytes;
218 SRB_HAInquiry srbHAInquiry;
219 SRB_GDEVBlock srbGDEVBlock;
220 DWORD n_CDROM_drives=0; //No of CDROM type drives found.
222 //Use support info for host adapter count and loop over all of them.
223 dwASPIStatus = ASPI_GetASPI32SupportInfo();
224 if(HIBYTE(LOWORD(dwASPIStatus)) == SS_COMP)
226 MaxHaId = LOBYTE(LOWORD(dwASPIStatus));
227 for(HaId = 0; HaId < MaxHaId; HaId++)
230 ** Do a host adapter inquiry to get max target count. If the
231 ** target count isn't 8 or 16 then go with a default of 8.
233 memset(&srbHAInquiry, 0, sizeof(SRB_HAInquiry));
234 srbHAInquiry.SRB_Cmd = SC_HA_INQUIRY;
235 srbHAInquiry.SRB_HaId = HaId;
237 ASPI_SendASPI32Command((LPSRB)&srbHAInquiry);
238 if(srbHAInquiry.SRB_Status != SS_COMP)
243 MaxTarget = srbHAInquiry.HA_Unique[3];
244 if(MaxTarget != 8 && MaxTarget != 16)
250 ** Loop over all the targets on this host adapter.
252 for(Target = 0; Target < MaxTarget; Target++ )
255 ** Issue get device type call to see if there is a device we're
256 ** interested in at this address. We're interested in CDROMs.
258 memset(&srbGDEVBlock, 0, sizeof(SRB_GDEVBlock));
259 srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;
260 srbGDEVBlock.SRB_HaId = HaId;
261 srbGDEVBlock.SRB_Target = Target;
263 ASPI_SendASPI32Command((LPSRB)&srbGDEVBlock);
264 if(srbGDEVBlock.SRB_Status != SS_COMP ||
265 (srbGDEVBlock.SRB_DeviceType != DTYPE_CDROM))
271 ** Determine the max transfer count of this target. It will
272 ** be the min of the host adapters min count and the size
273 ** of our global transfer buffer.
275 dwMaxTransferBytes = (DWORD)&srbHAInquiry.HA_Unique[4];
280 memset(InquiryCDB, 0, 6);
281 InquiryCDB[0] = SCSI_INQUIRY;
282 InquiryCDB[4] = 36; //Size in bytes of inquiry buffer.
284 //Send SCSI device inquiry command and wait for completion.
285 bSRB_exec = SendASPICMD_and_wait
297 ** Make sure the inquiry worked. If it failed, or if the
298 ** inquiry data returns a different device type than we got
299 ** before (guards against certain device drivers and against
300 ** vendor unique devices).
302 if(!bSRB_exec || (InquiryBuf[0] != DTYPE_CDROM))
306 ** Add this target to the screen.
308 WriteLog("Host adapter ID: %ld\n", HaId);
309 WriteLog("Target ID : %ld\n", Target);
310 WriteLog("LUN ID : 0\n");
311 WriteLog("Max buffer size: %ld bytes\n", dwMaxTransferBytes);
313 memcpy(szVendor, InquiryBuf + 8, 8);
314 szVendor[8] = '\0'; //Terminate the string
316 memcpy(szProduct, InquiryBuf + 16, 16);
317 szProduct[16] = '\0'; //Terminate the string
319 memcpy(szRev, InquiryBuf + 32, 4);
320 szRev[4] = '\0'; //Terminate the string
322 WriteLog("Vendor : %s\n", szVendor);
323 WriteLog("Product : %s\n", szProduct);
324 WriteLog("Revision : %s\n\n", szRev);
330 if (n_CDROM_drives == 0)
331 WriteLog("No CDROM type drives found.\n");
336 // 1. Sets up the CDB for MMC readcd (CDB12) command.
337 // 2. Send the request to the drive.
338 // 3. If success displays the sector data as hex on the screen.
340 BOOL ReadCD(BYTE HA_ID, BYTE Target_ID, long int MMC_LBA_sector)
343 long int MMC_LBA_sector2;
345 //CDB with values for ReadCD CDB12 command. The values were taken from MMC1 draft paper.
346 read_CDB12[0] = 0xBE; //Code for ReadCD CDB12 command
349 read_CDB12[5] = byte(MMC_LBA_sector); //Least sig byte of LBA sector no. to read from CD
350 MMC_LBA_sector2 = MMC_LBA_sector >> 8;
351 read_CDB12[4] = byte(MMC_LBA_sector2); //2nd byte of:
352 MMC_LBA_sector2 = MMC_LBA_sector2 >> 8;
353 read_CDB12[3] = byte(MMC_LBA_sector2); //3rd byte of:
354 MMC_LBA_sector2 = MMC_LBA_sector2 >> 8;
355 read_CDB12[2] = byte(MMC_LBA_sector2); //Most significant byte
357 read_CDB12[6] = 0; //No. of sectors to read from CD byte 2 (MSB)
358 read_CDB12[7] = 0; //No. of sectors to read from CD byte 1
359 read_CDB12[8] = 1; //No. of sectors to read from CD byte 0 (LSB)
360 read_CDB12[9] = 0xF8; //Raw read, 2352 bytes per sector
361 read_CDB12[10] = 0; //Sub-channel selection bits.
364 return SendASPICMD_and_wait(HA_ID, Target_ID, SRB_DIR_IN, 2352, DataBuf, 12, read_CDB12);
368 // Initialize the SDL sound system
374 WriteLog("Sound: Failed to init ASPI layer!\n");
380 // Close down the SDL sound subsystem
384 //Unload ASPI if it has been loaded.
386 FreeLibrary(WNASPI32_handle);
390 // Sound card callback handler
392 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
396 memcpy(buffer, DataBuf + 2352 - remain, remain);
404 ReadCD(0, 1, sector++);
405 memcpy(buffer, DataBuf, (length >= 2352 ? 2352 : length));