1 /*
2  *  Copyright (C) 2002-2010  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 /* $Id: cdrom_aspi_win32.cpp,v 1.21 2009-05-27 09:15:41 qbix79 Exp $ */
20 
21 #if defined (WIN32)
22 
23 #include <ctype.h>
24 
25 #include "dosbox.h"
26 #include "cdrom.h"
27 #include "support.h"
28 
29 //Are actually system includes but leave for now
30 #include "wnaspi32.h"
31 
32 #if defined (_MSC_VER)
33 #include <ntddcdrm.h>			// Ioctl stuff
34 #include <ntddscsi.h>
35 #include <winioctl.h>			// Ioctl stuff
36 #elif (defined __MINGW64_VERSION_MAJOR)
37 #include <winioctl.h>			// Ioctl stuff
38 #include <ntddcdrm.h>			// Ioctl stuff
39 #include <ntddscsi.h>
40 #else
41 #include "ddk/ntddcdrm.h"		// Ioctl stuff
42 #include "ddk/ntddscsi.h"
43 #endif
44 
45 #include "scsidefs.h"
46 
47 // always use a buffer of the maximum struct size (like the union of all 'SRB_*' struct types)
48 // Thanx SaPu
49 typedef union {
50 	SRB_HAInquiry       hainquiry;
51 	SRB_GDEVBlock       gdevblock;
52 	SRB_ExecSCSICmd     execscsicmd;
53 	SRB_Abort           abort;
54 	SRB_BusDeviceReset  busdevicereset;
55 	SRB_GetDiskInfo     getdiskinfo;
56 	SRB_RescanPort      rescanport;
57 	SRB_GetSetTimeouts  getsettimeouts;
58 } ASPI_SRB;
59 
60 // *****************************************************************
61 // Windows ASPI functions (should work for all WIN with ASPI layer)
62 // *****************************************************************
63 
CDROM_Interface_Aspi(void)64 CDROM_Interface_Aspi::CDROM_Interface_Aspi(void)
65 {
66 	hASPI					= NULL;
67 	hEvent					= NULL;
68 	pGetASPI32SupportInfo	= NULL;
69 	pSendASPI32Command		= NULL;
70 	memset(&oldLeadOut,0,sizeof(oldLeadOut));
71 };
72 
~CDROM_Interface_Aspi(void)73 CDROM_Interface_Aspi::~CDROM_Interface_Aspi(void)
74 {
75 	// Stop Audio
76 	StopAudio();
77 
78 	pGetASPI32SupportInfo	= NULL;	// clear funcs
79 	pSendASPI32Command		= NULL;
80 
81 	if (hASPI) {					// free aspi
82 		FreeLibrary(hASPI);
83 		hASPI=NULL;
84 	}
85 };
86 
GetRegistryValue(HKEY & hKey,char * valueName,char * buffer,ULONG bufferSize)87 bool GetRegistryValue(HKEY& hKey,char* valueName, char* buffer, ULONG bufferSize)
88 // hKey has to be open
89 {
90 	// Read subkey
91 	ULONG valType;
92 	ULONG result;
93 	result = RegQueryValueEx(hKey,valueName,NULL,&valType,(unsigned char*)&buffer[0],&bufferSize);
94 	return (result == ERROR_SUCCESS);
95 };
96 
GetHostAdapter(char * hardwareID)97 BYTE CDROM_Interface_Aspi::GetHostAdapter(char* hardwareID)
98 {
99 	ASPI_SRB sh;
100 	ASPI_SRB sd;
101 	DWORD d		= pGetASPI32SupportInfo();
102 	int cnt		= LOBYTE(LOWORD(d));
103 	int i,j,k,max;
104 
105 	for(i=0; i<cnt; i++) {
106 		memset(&sh, 0, sizeof(sh));
107 		sh.hainquiry.SRB_Cmd  = SC_HA_INQUIRY;
108 		sh.hainquiry.SRB_HaId = i;
109 		pSendASPI32Command((LPSRB)&sh);
110 		if (sh.hainquiry.SRB_Status!=SS_COMP) continue;
111 
112 		// Indicates the maximum number of targets the adapter supports
113 		// If the value is not 8 or 16, then it should be assumed max target is 8
114 		max = (int)sh.hainquiry.HA_Unique[3];
115 		if ((max!=8) && (max!=16)) max = 8;
116 
117 		for(j=0; j<max; j++) {
118 			for(k=0; k<8; k++) {
119 				memset(&sd, 0, sizeof(sd));
120 				sd.gdevblock.SRB_Cmd    = SC_GET_DEV_TYPE;
121 				sd.gdevblock.SRB_HaId   = i;
122 				sd.gdevblock.SRB_Target = j;
123 				sd.gdevblock.SRB_Lun    = k;
124 				pSendASPI32Command((LPSRB)&sd);
125 				if (sd.gdevblock.SRB_Status == SS_COMP) {
126 					if (sd.gdevblock.SRB_DeviceType == DTYPE_CDROM) {
127 						if ((target==j) && (lun==k)) {
128 							LOG(LOG_MISC,LOG_NORMAL)("SCSI: Getting Hardware vendor.");
129 							// "Hardware ID = vendor" match ?
130 							char vendor[64];
131 							if (GetVendor(i,target,lun,vendor)) {
132 								LOG(LOG_MISC,LOG_NORMAL)("SCSI: Vendor : %s",vendor);
133 								if (strstr(strupr(hardwareID),strupr(vendor))) {
134 									LOG(LOG_MISC,LOG_NORMAL)("SCSI: Host Adapter found: %d",i);
135 									return i;
136 								}
137 							};
138 						}
139 					}
140 				}
141 			}
142 		}
143 	}
144 	LOG(LOG_MISC,LOG_ERROR)("SCSI: Host Adapter not found: %d",i);
145 	return 0;
146 };
147 
ScanRegistryFindKey(HKEY & hKeyBase)148 bool CDROM_Interface_Aspi::ScanRegistryFindKey(HKEY& hKeyBase)
149 // hKey has to be open
150 {
151 	FILETIME	time;
152 	ULONG		result,newKeyResult;
153 	char		subKey[256];
154 	char		buffer[256];
155 	ULONG		subKeySize = 256;
156 	HKEY		hNewKey;
157 
158 	ULONG index = 0;
159 	do {
160 		result = RegEnumKeyEx (hKeyBase,index,&subKey[0],&subKeySize,NULL,NULL,0,&time);
161 		if (result==ERROR_SUCCESS) {
162 			// Open Key...
163 			newKeyResult = RegOpenKeyEx (hKeyBase,subKey,0,KEY_READ,&hNewKey);
164 			if (newKeyResult==ERROR_SUCCESS) {
165 				static const char drive_letter_assignment[] = "CurrentDriveLetterAssignment";
166 				if (GetRegistryValue(hNewKey,(char*)&drive_letter_assignment,buffer,256)) {
167 					LOG(LOG_MISC,LOG_NORMAL)("SCSI: Drive Letter found: %s",buffer);
168 					// aha, something suspicious...
169 					if (buffer[0]==letter) {
170 						char hardwareID[256];
171 						// found it... lets see if we can get the scsi values
172 						static const char SCSI_LUN[] = "SCSILUN";
173 						bool v1 = GetRegistryValue(hNewKey,(char*)SCSI_LUN,buffer,256);
174 						LOG(LOG_MISC,LOG_NORMAL)("SCSI: SCSILUN found: %s",buffer);
175 						lun		= buffer[0]-'0';
176 						static const char SCSI_TargetID[] = "SCSITargetID";
177 						bool v2 = GetRegistryValue(hNewKey,(char*)SCSI_TargetID,buffer,256);
178 						LOG(LOG_MISC,LOG_NORMAL)("SCSI: SCSITargetID found: %s",buffer);
179 						target  = buffer[0]-'0';
180 						static const char Hardware_ID[] = "HardwareID";
181 						bool v3 = GetRegistryValue(hNewKey,(char*)Hardware_ID,hardwareID,256);
182 						RegCloseKey(hNewKey);
183 						if (v1 && v2 && v3) {
184 							haId = GetHostAdapter(hardwareID);
185 							return true;
186 						};
187 					}
188 				};
189 			};
190 			RegCloseKey(hNewKey);
191 		};
192 		index++;
193 	} while ((result==ERROR_SUCCESS) || (result==ERROR_MORE_DATA));
194 	return false;
195 };
196 
GetVendor(BYTE HA_num,BYTE SCSI_Id,BYTE SCSI_Lun,char * szBuffer)197 bool CDROM_Interface_Aspi::GetVendor(BYTE HA_num, BYTE SCSI_Id, BYTE SCSI_Lun, char* szBuffer)
198 {
199 	ASPI_SRB srbExec;
200 	//	SRB_ExecSCSICmd srbExec;
201 	memset ( &srbExec, 0, sizeof ( SRB_ExecSCSICmd ) );
202 
203 	hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
204 
205 	srbExec.execscsicmd.SRB_Cmd			= SC_EXEC_SCSI_CMD ;
206 	srbExec.execscsicmd.SRB_HaId		= HA_num;
207 	srbExec.execscsicmd.SRB_Flags		= SRB_DIR_IN | SRB_EVENT_NOTIFY;
208 	srbExec.execscsicmd.SRB_Target		= SCSI_Id;
209 	srbExec.execscsicmd.SRB_Lun			= SCSI_Lun;
210 	srbExec.execscsicmd.SRB_BufLen		= 36;
211 	srbExec.execscsicmd.SRB_BufPointer	= (unsigned char*)szBuffer;
212 	srbExec.execscsicmd.SRB_SenseLen	= SENSE_LEN;
213 	srbExec.execscsicmd.SRB_CDBLen		= 6;
214 	srbExec.execscsicmd.SRB_PostProc	= (LPVOID)hEvent;
215 	srbExec.execscsicmd.CDBByte [ 0 ]	= SCSI_INQUIRY;
216 	srbExec.execscsicmd.CDBByte [ 4 ]	= 36;  // allocation length per szBuffer [ ]
217 
218 	ResetEvent(hEvent);
219 	int dwStatus = pSendASPI32Command ((LPSRB)&srbExec);
220 //	LOG(LOG_MISC|LOG_ERROR,"SCSI: Get vendor command send");
221 
222 	if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,30000);
223 //	LOG(LOG_MISC|LOG_ERROR,"SCSI: Pending done.");
224 
225 	CloseHandle(hEvent);
226 	if (srbExec.execscsicmd.SRB_Status != SS_COMP) {
227 		strcpy (szBuffer, "error" );
228 		return false;
229 	} else {
230 		safe_strncpy(szBuffer,szBuffer+8,26);
231 		size_t len = strlen(szBuffer);
232 		for (size_t i=0; i<len; i++) if (szBuffer[i]<=32) szBuffer[i]='_';
233 	}
234 	return true;
235 }
236 
ScanRegistry(HKEY & hKeyBase)237 bool CDROM_Interface_Aspi::ScanRegistry(HKEY& hKeyBase)
238 // hKey has to be open
239 {
240 	FILETIME	time;
241 	ULONG		result,newKeyResult;
242 	char		subKey[256];
243 	ULONG		subKeySize= 256;
244 	HKEY		hNewKey;
245 
246 	ULONG index = 0;
247 	do {
248 		result = RegEnumKeyEx (hKeyBase,index,&subKey[0],&subKeySize,NULL,NULL,0,&time);
249 		if ((result==ERROR_SUCCESS) || (result==ERROR_MORE_DATA)) {
250 			// Open Key...
251 			newKeyResult = RegOpenKeyEx (hKeyBase,subKey,0,KEY_READ,&hNewKey);
252 			if (newKeyResult==ERROR_SUCCESS) {
253 				bool found = ScanRegistryFindKey(hNewKey);
254 				RegCloseKey(hNewKey);
255 				if (found) return true;
256 			};
257 			RegCloseKey(hNewKey);
258 		};
259 		index++;
260 	} while ((result==ERROR_SUCCESS) || (result==ERROR_MORE_DATA));
261 	return false;
262 };
263 
SetDevice(char * path,int forceCD)264 bool CDROM_Interface_Aspi::SetDevice(char* path, int forceCD)
265 {
266 	// load WNASPI32.DLL
267 	hASPI = LoadLibrary ( "WNASPI32.DLL" );
268 	if (!hASPI) return false;
269 	// Get Pointer to ASPI funcs
270     pGetASPI32SupportInfo	= (DWORD(*)(void))GetProcAddress(hASPI,"GetASPI32SupportInfo");
271     pSendASPI32Command		= (DWORD(*)(LPSRB))GetProcAddress(hASPI,"SendASPI32Command");
272 	if (!pGetASPI32SupportInfo || !pSendASPI32Command) return false;
273 	// Letter
274 	letter = toupper(path[0]);
275 
276 	// Check OS
277 	OSVERSIONINFO osi;
278 	osi.dwOSVersionInfoSize = sizeof(osi);
279 	GetVersionEx(&osi);
280 	if ((osi.dwPlatformId==VER_PLATFORM_WIN32_NT) && (osi.dwMajorVersion>4)) {
281 		if (GetDriveType(path)==DRIVE_CDROM) {
282 			// WIN XP/NT/2000
283 			int iDA,iDT,iDL;
284 			letter = path[0];
285 			HANDLE hF = OpenIOCTLFile(letter,FALSE);
286 			GetIOCTLAdapter(hF,&iDA,&iDT,&iDL);
287 			CloseHandle(hF);
288 			// Set SCSI IDs
289 			haId	= iDA;
290 			target	= iDT;
291 			lun		= iDL;
292 			return true;
293 		}
294 	} else {
295 		// win 95/98/ME have to scan the registry...
296 		// lets hope the layout is always the same... i dunno...
297 		char key[2048];
298 		HKEY hKeyBase;
299 		bool found = false;
300 		strcpy(key,"ENUM\\SCSI");
301 		if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,key,0,KEY_READ,&hKeyBase)==ERROR_SUCCESS) {
302 			found = ScanRegistry(hKeyBase);
303 		};
304 		RegCloseKey(hKeyBase);
305 		return found;
306 	}
307 	return false;
308 };
309 
GetAudioTracks(int & stTrack,int & endTrack,TMSF & leadOut)310 bool CDROM_Interface_Aspi::GetAudioTracks(int& stTrack, int& endTrack, TMSF& leadOut)
311 {
312 	TOC toc;
313 	if (GetTOC((LPTOC)&toc) == SS_COMP) {
314 		stTrack		= toc.cFirstTrack;
315 		endTrack	= toc.cLastTrack;
316 		leadOut.min	= (unsigned char)(toc.tracks[endTrack].lAddr >>  8) &0xFF;
317 		leadOut.sec	= (unsigned char)(toc.tracks[endTrack].lAddr >> 16) &0xFF;
318 		leadOut.fr	= (unsigned char)(toc.tracks[endTrack].lAddr >> 24) &0xFF;
319 		return true;
320 	}
321 	return false;
322 };
323 
GetAudioTrackInfo(int track,TMSF & start,unsigned char & attr)324 bool CDROM_Interface_Aspi::GetAudioTrackInfo	(int track, TMSF& start, unsigned char& attr)
325 {
326 	TOC toc;
327 	if (GetTOC((LPTOC)&toc) == SS_COMP) {
328 		start.min	= (unsigned char)(toc.tracks[track-1].lAddr >>  8) &0xFF;
329 		start.sec	= (unsigned char)(toc.tracks[track-1].lAddr >> 16) &0xFF;
330 		start.fr	= (unsigned char)(toc.tracks[track-1].lAddr >> 24) &0xFF;
331 		attr		= (toc.tracks[track-1].cAdrCtrl << 4) & 0xEF;
332 		return true;
333 	};
334 	return false;
335 };
336 
OpenIOCTLFile(char cLetter,BOOL bAsync)337 HANDLE CDROM_Interface_Aspi::OpenIOCTLFile(char cLetter,BOOL bAsync)
338 {
339 	HANDLE hF;
340 	char szFName[16];
341 	OSVERSIONINFO ov;
342 	DWORD dwFlags;
343 	DWORD dwIOCTLAttr;
344 //	if(bAsync) dwIOCTLAttr=FILE_FLAG_OVERLAPPED;
345 //	else
346 	dwIOCTLAttr=0;
347 
348 	memset(&ov,0,sizeof(OSVERSIONINFO));
349 	ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
350 	GetVersionEx(&ov);
351 
352 	if ((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) && (ov.dwMajorVersion>4))
353 		dwFlags = GENERIC_READ|GENERIC_WRITE;            // add gen write on W2k/XP
354 	else
355 		dwFlags = GENERIC_READ;
356 
357 	wsprintf(szFName, "\\\\.\\%c:",cLetter);
358 
359 	hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ,        // open drive
360 				NULL,OPEN_EXISTING,dwIOCTLAttr,NULL);
361 
362 	if (hF==INVALID_HANDLE_VALUE) {
363 		dwFlags^=GENERIC_WRITE;                         // mmm... no success
364 		hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ,      // -> open drive again
365 					NULL,OPEN_EXISTING,dwIOCTLAttr,NULL);
366 		if (hF==INVALID_HANDLE_VALUE) return NULL;
367 	}
368 	return hF;
369 }
370 
GetIOCTLAdapter(HANDLE hF,int * iDA,int * iDT,int * iDL)371 void CDROM_Interface_Aspi::GetIOCTLAdapter(HANDLE hF,int * iDA,int * iDT,int * iDL)
372 {
373 	char szBuf[1024];
374 	PSCSI_ADDRESS pSA;
375 	DWORD dwRet;
376 
377 	*iDA=*iDT=*iDL=-1;
378 	if(hF==NULL) return;
379 
380 	memset(szBuf,0,1024);
381 
382 	pSA=(PSCSI_ADDRESS)szBuf;
383 	pSA->Length=sizeof(SCSI_ADDRESS);
384 
385 	if(!DeviceIoControl(hF,IOCTL_SCSI_GET_ADDRESS,NULL,
386 					 0,pSA,sizeof(SCSI_ADDRESS),
387 					 &dwRet,NULL))
388 	return;
389 
390 	*iDA = pSA->PortNumber;
391 	*iDT = pSA->TargetId;
392 	*iDL = pSA->Lun;
393 }
394 
GetTOC(LPTOC toc)395 DWORD CDROM_Interface_Aspi::GetTOC(LPTOC toc)
396 {
397 //	SRB_ExecSCSICmd s;
398 	ASPI_SRB s;
399 	DWORD dwStatus;
400 
401 	hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
402 
403 	memset(&s,0,sizeof(s));
404 
405 	s.execscsicmd.SRB_Cmd        = SC_EXEC_SCSI_CMD;
406 	s.execscsicmd.SRB_HaId       = haId;
407 	s.execscsicmd.SRB_Target     = target;
408 	s.execscsicmd.SRB_Lun        = lun;
409 	s.execscsicmd.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
410 	s.execscsicmd.SRB_BufLen     = sizeof(*toc);
411 	s.execscsicmd.SRB_BufPointer = (BYTE FAR *)toc;
412 	s.execscsicmd.SRB_SenseLen   = SENSE_LEN;
413 	s.execscsicmd.SRB_CDBLen     = 0x0A;
414 	s.execscsicmd.SRB_PostProc   = (LPVOID)hEvent;
415 	s.execscsicmd.CDBByte[0]     = SCSI_READ_TOC;
416 	s.execscsicmd.CDBByte[1]     = 0x02; // 0x02 for MSF
417 	s.execscsicmd.CDBByte[7]     = 0x03;
418 	s.execscsicmd.CDBByte[8]     = 0x24;
419 
420 	ResetEvent(hEvent);
421 	dwStatus=pSendASPI32Command((LPSRB)&s);
422 
423 	if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,30000);
424 
425 	CloseHandle(hEvent);
426 
427 	return (s.execscsicmd.SRB_Status==SS_COMP);
428 }
429 
PlayAudioSector(unsigned long start,unsigned long len)430 bool CDROM_Interface_Aspi::PlayAudioSector(unsigned long start,unsigned long len)
431 {
432 //	SRB_ExecSCSICmd s;
433 	ASPI_SRB s;
434 	DWORD dwStatus;
435 
436 	hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
437 
438 	memset(&s,0,sizeof(s));
439 	s.execscsicmd.SRB_Cmd        = SC_EXEC_SCSI_CMD;
440 	s.execscsicmd.SRB_HaId       = haId;
441 	s.execscsicmd.SRB_Target     = target;
442 	s.execscsicmd.SRB_Lun        = lun;
443 	s.execscsicmd.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
444 	s.execscsicmd.SRB_BufLen     = 0;
445 	s.execscsicmd.SRB_BufPointer = 0;
446 	s.execscsicmd.SRB_SenseLen   = SENSE_LEN;
447 	s.execscsicmd.SRB_CDBLen     = 12;
448 	s.execscsicmd.SRB_PostProc   = (LPVOID)hEvent;
449 
450 	s.execscsicmd.CDBByte[0]     = SCSI_PLAYAUD_12;
451 	s.execscsicmd.CDBByte[1]     = lun << 5;
452 	s.execscsicmd.CDBByte[2]     = (unsigned char)((start >> 24) & 0xFF);
453 	s.execscsicmd.CDBByte[3]     = (unsigned char)((start >> 16) & 0xFF);
454 	s.execscsicmd.CDBByte[4]     = (unsigned char)((start >> 8) & 0xFF);
455 	s.execscsicmd.CDBByte[5]     = (unsigned char)((start & 0xFF));
456 	s.execscsicmd.CDBByte[6]     = (unsigned char)((len >> 24) & 0xFF);
457 	s.execscsicmd.CDBByte[7]     = (unsigned char)((len >> 16) & 0xFF);
458 	s.execscsicmd.CDBByte[8]     = (unsigned char)((len >> 8) & 0xFF);
459 	s.execscsicmd.CDBByte[9]     = (unsigned char)(len & 0xFF);
460 
461 	ResetEvent(hEvent);
462 
463 	dwStatus = pSendASPI32Command((LPSRB)&s);
464 
465 	if(dwStatus==SS_PENDING) WaitForSingleObject(hEvent,10000);
466 
467 	CloseHandle(hEvent);
468 
469 	return s.execscsicmd.SRB_Status==SS_COMP;
470 }
471 
StopAudio(void)472 bool CDROM_Interface_Aspi::StopAudio(void)
473 {
474 	return PauseAudio(false);
475 };
476 
PauseAudio(bool resume)477 bool CDROM_Interface_Aspi::PauseAudio(bool resume)
478 {
479 	//SRB_ExecSCSICmd s;
480 	ASPI_SRB s;
481 	DWORD dwStatus;
482 
483 	hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
484 
485 	memset(&s,0,sizeof(s));
486 
487 	s.execscsicmd.SRB_Cmd        = SC_EXEC_SCSI_CMD;
488 	s.execscsicmd.SRB_HaId       = haId;
489 	s.execscsicmd.SRB_Target     = target;
490 	s.execscsicmd.SRB_Lun        = lun;
491 	s.execscsicmd.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
492 	s.execscsicmd.SRB_BufLen     = 0x00;
493 	s.execscsicmd.SRB_SenseLen   = SENSE_LEN;
494 	s.execscsicmd.SRB_CDBLen     = 0x0A;
495 	s.execscsicmd.SRB_PostProc   = (LPVOID)hEvent;
496 	s.execscsicmd.CDBByte[0]     = 0x4B;
497 	s.execscsicmd.CDBByte[8]     = (unsigned char)resume;				// Pause
498 
499 	ResetEvent(hEvent);
500 	dwStatus=pSendASPI32Command((LPSRB)&s);
501 
502 	if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,30000);
503 
504 	CloseHandle(hEvent);
505 
506 	return (s.execscsicmd.SRB_Status==SS_COMP);
507 };
508 
GetAudioSub(unsigned char & attr,unsigned char & track,unsigned char & index,TMSF & relPos,TMSF & absPos)509 bool CDROM_Interface_Aspi::GetAudioSub(unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos)
510 {
511 	SUB_Q_CURRENT_POSITION pos;
512 //	SRB_ExecSCSICmd s;
513 	ASPI_SRB s;
514 	DWORD dwStatus;
515 
516 	hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
517 
518 	memset(&s,0,sizeof(s));
519 
520 	s.execscsicmd.SRB_Cmd        = SC_EXEC_SCSI_CMD;
521 	s.execscsicmd.SRB_HaId       = haId;
522 	s.execscsicmd.SRB_Target     = target;
523 	s.execscsicmd.SRB_Lun        = lun;
524 	s.execscsicmd.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
525 	s.execscsicmd.SRB_SenseLen   = SENSE_LEN;
526 
527 	s.execscsicmd.SRB_BufLen     = sizeof(pos);
528 	s.execscsicmd.SRB_BufPointer = (BYTE FAR *)&pos;
529 	s.execscsicmd.SRB_CDBLen     = 10;
530 	s.execscsicmd.SRB_PostProc   = (LPVOID)hEvent;
531 
532 	s.execscsicmd.CDBByte[0]     = SCSI_SUBCHANNEL;
533 	s.execscsicmd.CDBByte[1]     = (lun<<5)|2;   // lun & msf
534 	s.execscsicmd.CDBByte[2]     = 0x40;            // subq
535 	s.execscsicmd.CDBByte[3]     = 0x01;            // curr pos info
536 	s.execscsicmd.CDBByte[6]     = 0;               // track number (only in isrc mode, ignored)
537 	s.execscsicmd.CDBByte[7]     = 0;               // alloc len
538 	s.execscsicmd.CDBByte[8]     = sizeof(pos);
539 
540 	ResetEvent(hEvent);
541 
542 	dwStatus = pSendASPI32Command((LPSRB)&s);
543 
544 	if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF);
545 
546 	CloseHandle(hEvent);
547 
548 	if (s.execscsicmd.SRB_Status!=SS_COMP) return false;
549 
550 	attr		= (pos.Control<<4) &0xEF;
551 	track		= pos.TrackNumber;
552 	index		= pos.IndexNumber;
553 	absPos.min	= pos.AbsoluteAddress[1];
554 	absPos.sec	= pos.AbsoluteAddress[2];
555 	absPos.fr	= pos.AbsoluteAddress[3];
556 	relPos.min	= pos.TrackRelativeAddress[1];
557 	relPos.sec	= pos.TrackRelativeAddress[2];
558 	relPos.fr	= pos.TrackRelativeAddress[3];
559 
560 	return true;
561 };
562 
GetUPC(unsigned char & attr,char * upcdata)563 bool CDROM_Interface_Aspi::GetUPC(unsigned char& attr, char* upcdata)
564 {
565 	SUB_Q_MEDIA_CATALOG_NUMBER upc;
566 	ASPI_SRB s;
567 	//SRB_ExecSCSICmd s;
568 	DWORD dwStatus;
569 
570 	hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
571 
572 	memset(&s,0,sizeof(s));
573 
574 	s.execscsicmd.SRB_Cmd        = SC_EXEC_SCSI_CMD;
575 	s.execscsicmd.SRB_HaId       = haId;
576 	s.execscsicmd.SRB_Target     = target;
577 	s.execscsicmd.SRB_Lun        = lun;
578 	s.execscsicmd.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
579 	s.execscsicmd.SRB_SenseLen   = SENSE_LEN;
580 
581 	s.execscsicmd.SRB_BufLen     = sizeof(upc);
582 	s.execscsicmd.SRB_BufPointer = (BYTE FAR *)&upc;
583 	s.execscsicmd.SRB_CDBLen     = 10;
584 	s.execscsicmd.SRB_PostProc   = (LPVOID)hEvent;
585 
586 	s.execscsicmd.CDBByte[0]     = SCSI_SUBCHANNEL;
587 	s.execscsicmd.CDBByte[1]     = (lun<<5)|2;   // lun & msf
588 	s.execscsicmd.CDBByte[2]     = 0x40;            // subq
589 	s.execscsicmd.CDBByte[3]     = 0x02;            // get upc
590 	s.execscsicmd.CDBByte[6]     = 0;               // track number (only in isrc mode, ignored)
591 	s.execscsicmd.CDBByte[7]     = 0;               // alloc len
592 	s.execscsicmd.CDBByte[8]     = sizeof(upc);
593 
594 	ResetEvent(hEvent);
595 
596 	dwStatus = pSendASPI32Command((LPSRB)&s);
597 
598 	if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF);
599 
600 	CloseHandle(hEvent);
601 
602 	if (s.execscsicmd.SRB_Status!=SS_COMP) return false;
603 
604 //	attr = (upc.ADR<<4) | upc.Control;
605 	attr	= 0;
606 	// Convert to mscdex format
607 	for (int i=0; i<7; i++) upcdata[i] = upc.MediaCatalog[i];
608     for (int i=0; i<7; i++) upcdata[i] = (upc.MediaCatalog[i*2] << 4) | (upc.MediaCatalog[i*2+1] & 0x0F);
609 
610 	return true;
611 };
612 
GetAudioStatus(bool & playing,bool & pause)613 bool CDROM_Interface_Aspi::GetAudioStatus(bool& playing, bool& pause)
614 {
615 	playing = pause = false;
616 
617 	SUB_Q_HEADER sub;
618 //	SRB_ExecSCSICmd s;
619 	ASPI_SRB s;
620 	DWORD dwStatus;
621 
622 	hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
623 
624 	memset(&s,0,sizeof(s));
625 
626 	s.execscsicmd.SRB_Cmd        = SC_EXEC_SCSI_CMD;
627 	s.execscsicmd.SRB_HaId       = haId;
628 	s.execscsicmd.SRB_Target     = target;
629 	s.execscsicmd.SRB_Lun        = lun;
630 	s.execscsicmd.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
631 	s.execscsicmd.SRB_SenseLen   = SENSE_LEN;
632 
633 	s.execscsicmd.SRB_BufLen     = sizeof(sub);
634 	s.execscsicmd.SRB_BufPointer = (BYTE FAR *)&sub;
635 	s.execscsicmd.SRB_CDBLen     = 10;
636 	s.execscsicmd.SRB_PostProc   = (LPVOID)hEvent;
637 
638 	s.execscsicmd.CDBByte[0]     = SCSI_SUBCHANNEL;
639 	s.execscsicmd.CDBByte[1]     = (lun<<5)|2;   // lun & msf
640 	s.execscsicmd.CDBByte[2]     = 0x00;            // no subq
641 	s.execscsicmd.CDBByte[3]     = 0x00;            // dont care
642 	s.execscsicmd.CDBByte[6]     = 0;               // track number (only in isrc mode, ignored)
643 	s.execscsicmd.CDBByte[7]     = 0;               // alloc len
644 	s.execscsicmd.CDBByte[8]     = sizeof(sub);
645 
646 	ResetEvent(hEvent);
647 
648 	dwStatus = pSendASPI32Command((LPSRB)&s);
649 
650 	if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF);
651 
652 	CloseHandle(hEvent);
653 
654 	if (s.execscsicmd.SRB_Status!=SS_COMP) return false;
655 
656 	playing			= (sub.AudioStatus==0x11);
657 	pause			= (sub.AudioStatus==0x12);
658 
659 	return true;
660 };
661 
LoadUnloadMedia(bool unload)662 bool CDROM_Interface_Aspi::LoadUnloadMedia(bool unload)
663 {
664 	//SRB_ExecSCSICmd s;
665 	ASPI_SRB s;
666 	DWORD dwStatus;
667 
668 	hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
669 
670 	memset(&s,0,sizeof(s));
671 
672 	s.execscsicmd.SRB_Cmd        = SC_EXEC_SCSI_CMD;
673 	s.execscsicmd.SRB_HaId       = haId;
674 	s.execscsicmd.SRB_Target     = target;
675 	s.execscsicmd.SRB_Lun        = lun;
676 	s.execscsicmd.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
677 	s.execscsicmd.SRB_SenseLen   = SENSE_LEN;
678 
679 	s.execscsicmd.SRB_BufLen     = 0;
680 	s.execscsicmd.SRB_BufPointer = 0;
681 	s.execscsicmd.SRB_CDBLen     = 6; // 14;
682 	s.execscsicmd.SRB_PostProc   = (LPVOID)hEvent;
683 
684 	s.execscsicmd.CDBByte[0]     = SCSI_LOAD_UN;
685 	s.execscsicmd.CDBByte[1]     = (lun<<5)|1; // lun & immediate
686 	s.execscsicmd.CDBByte[4]     = (unload ? 0x02:0x03);		// unload/load media
687 
688 	ResetEvent(hEvent);
689 
690 	dwStatus = pSendASPI32Command((LPSRB)&s);
691 
692 	if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF);
693 
694 	CloseHandle(hEvent);
695 
696 	if (s.execscsicmd.SRB_Status!=SS_COMP) return false;
697 
698 	return true;
699 };
700 
GetMediaTrayStatus(bool & mediaPresent,bool & mediaChanged,bool & trayOpen)701 bool CDROM_Interface_Aspi::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen)
702 {
703 	// Seems not possible to get this values using ioctl...
704 	int		track1,track2;
705 	TMSF	leadOut;
706 	// If we can read, there's a media
707 	mediaPresent = GetAudioTracks(track1, track2, leadOut),
708 	trayOpen	 = !mediaPresent;
709 	mediaChanged = (oldLeadOut.min!=leadOut.min) || (oldLeadOut.sec!=leadOut.sec) || (oldLeadOut.fr!=leadOut.fr);
710 	// Save old values
711 	oldLeadOut.min = leadOut.min;
712 	oldLeadOut.sec = leadOut.sec;
713 	oldLeadOut.fr  = leadOut.fr;
714 	// always success
715 	return true;
716 };
717 
ReadSectors(PhysPt buffer,bool raw,unsigned long sector,unsigned long num)718 bool CDROM_Interface_Aspi::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num)
719 {
720 	//SRB_ExecSCSICmd s;
721 	ASPI_SRB s;
722 	DWORD dwStatus;
723 
724 	hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
725 
726 	memset(&s,0,sizeof(s));
727 
728 	Bitu   buflen	= raw?2352*num:2048*num;
729 	Bit8u* bufdata	= new Bit8u[buflen];
730 
731 	s.execscsicmd.SRB_Cmd        = SC_EXEC_SCSI_CMD;
732 	s.execscsicmd.SRB_HaId       = haId;
733 	s.execscsicmd.SRB_Target     = target;
734 	s.execscsicmd.SRB_Lun        = lun;
735 	s.execscsicmd.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
736 	s.execscsicmd.SRB_SenseLen   = SENSE_LEN;
737 
738 	s.execscsicmd.SRB_BufLen     = buflen;
739 	s.execscsicmd.SRB_BufPointer = (BYTE FAR*)bufdata;
740 	s.execscsicmd.SRB_CDBLen     = 12;
741 	s.execscsicmd.SRB_PostProc   = (LPVOID)hEvent;
742 
743 	s.execscsicmd.CDBByte[0]     = 0xBE;
744 	s.execscsicmd.CDBByte[2]     = (unsigned char)((sector >> 24) & 0xFF);
745 	s.execscsicmd.CDBByte[3]     = (unsigned char)((sector >> 16) & 0xFF);
746 	s.execscsicmd.CDBByte[4]     = (unsigned char)((sector >> 8) & 0xFF);
747 	s.execscsicmd.CDBByte[5]     = (unsigned char)((sector & 0xFF));
748 	s.execscsicmd.CDBByte[6]     = (unsigned char)((num >> 16) & 0xFF);
749 	s.execscsicmd.CDBByte[7]     = (unsigned char)((num >>  8) & 0xFF);
750 	s.execscsicmd.CDBByte[8]     = (unsigned char) (num & 0xFF);
751 	s.execscsicmd.CDBByte[9]	 = (raw?0xF0:0x10);
752 
753 	ResetEvent(hEvent);
754 
755 	dwStatus = pSendASPI32Command((LPSRB)&s);
756 
757 	if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF);
758 
759 	CloseHandle(hEvent);
760 
761 	// Copy to PhysPt
762 	MEM_BlockWrite(buffer,bufdata,buflen);
763 
764 	delete[] bufdata;
765 
766 	return (s.execscsicmd.SRB_Status==SS_COMP);
767 };
768 
769 #endif
770