Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/yabause/src/cd-windows.c
2 views
1
/* Copyright 2004-2005 Theo Berkau
2
Copyright 2005 Joost Peters
3
4
This file is part of Yabause.
5
6
Yabause is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
10
11
Yabause is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
15
16
You should have received a copy of the GNU General Public License
17
along with Yabause; if not, write to the Free Software
18
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
21
#include <windows.h>
22
#include <stdio.h>
23
#include "windows/cd.h"
24
25
//////////////////////////////////////////////////////////////////////////////
26
27
static HANDLE hCDROM;
28
static SCSI_PASS_THROUGH_DIRECT sptd;
29
static int KillCDThread=0;
30
static HANDLE thread_handle=INVALID_HANDLE_VALUE;
31
static int drivestatus=0;
32
static DWORD thread_id;
33
34
CDInterface ArchCD = {
35
CDCORE_SPTI,
36
"Windows SPTI Driver",
37
SPTICDInit,
38
SPTICDDeInit,
39
SPTICDGetStatus,
40
SPTICDReadTOC,
41
SPTICDReadSectorFAD,
42
SPTICDReadAheadFAD,
43
};
44
45
//////////////////////////////////////////////////////////////////////////////
46
// SPTI Interface
47
//////////////////////////////////////////////////////////////////////////////
48
49
DWORD WINAPI __stdcall SPTICDThread(void *b);
50
51
int SPTICDInit(const char *cdrom_name) {
52
char pipe_name[7];
53
54
sprintf(pipe_name, "\\\\.\\?:");
55
pipe_name[4] = cdrom_name[0];
56
57
if ((hCDROM = CreateFileA(pipe_name, GENERIC_READ | GENERIC_WRITE,
58
FILE_SHARE_READ | FILE_SHARE_WRITE,
59
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
60
NULL)) == INVALID_HANDLE_VALUE)
61
{
62
return -1;
63
}
64
65
// Setup a separate thread for handling SPTI commands(that way the emulation
66
// code doesn't have to wait for a response)
67
KillCDThread=0;
68
thread_handle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) SPTICDThread,(void *) &KillCDThread,0,&thread_id);
69
70
// Set it to highest priority to avoid breaks
71
// SetThreadPriority(thread_handle,THREAD_PRIORITY_HIGHEST);
72
73
return 0;
74
}
75
76
//////////////////////////////////////////////////////////////////////////////
77
78
void SPTICDDeInit() {
79
if (thread_handle != INVALID_HANDLE_VALUE)
80
{
81
// Set the flag telling it to stop
82
KillCDThread=1;
83
if (WaitForSingleObject(thread_handle,INFINITE) == WAIT_TIMEOUT)
84
{
85
// Couldn't close thread cleanly
86
TerminateThread(thread_handle,0);
87
}
88
CloseHandle(thread_handle);
89
thread_handle = INVALID_HANDLE_VALUE;
90
}
91
92
CloseHandle(hCDROM);
93
}
94
95
//////////////////////////////////////////////////////////////////////////////
96
97
DWORD WINAPI __stdcall SPTICDThread(void *b)
98
{
99
while (KillCDThread != 1)
100
{
101
DWORD dwBytesReturned;
102
unsigned char statusbuf[8];
103
BOOL success;
104
105
// Check to see if we have any work to do(for now, let's just do a drive
106
// status check once a second)
107
108
sptd.Length=sizeof(sptd);
109
sptd.PathId=0; //
110
sptd.TargetId=0; // Don't need these, they're automatically generated
111
sptd.Lun=0; //
112
sptd.CdbLength=12;
113
sptd.SenseInfoLength=0; // No sense data
114
sptd.DataIn=SCSI_IOCTL_DATA_IN;
115
sptd.TimeOutValue=60; // may need to be changed
116
sptd.DataBuffer=(PVOID)&(statusbuf);
117
sptd.SenseInfoOffset=0;
118
sptd.DataTransferLength=8; // may need to change this
119
120
sptd.Cdb[0]=0xBD; // CDB12 code
121
sptd.Cdb[1]=0; // Reserved
122
sptd.Cdb[2]=0; // Reserved
123
sptd.Cdb[3]=0; // Reserved
124
sptd.Cdb[4]=0; // Reserved
125
sptd.Cdb[5]=0; // Reserved
126
sptd.Cdb[6]=0; // Reserved
127
sptd.Cdb[7]=0; // Reserved
128
sptd.Cdb[8]=0; // Allocation Length(byte 1)
129
sptd.Cdb[9]=8; // Allocation Length(byte 2) (may have to change this)
130
sptd.Cdb[10]=0; // Reserved
131
sptd.Cdb[11]=0; // Control
132
sptd.Cdb[12]=0;
133
sptd.Cdb[13]=0;
134
sptd.Cdb[14]=0;
135
sptd.Cdb[15]=0;
136
137
success=DeviceIoControl(hCDROM, IOCTL_SCSI_PASS_THROUGH_DIRECT,
138
(PVOID)&sptd, (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT),
139
NULL, 0, &dwBytesReturned, NULL);
140
141
if (success)
142
{
143
// Figure out drive status
144
145
// Is door open?
146
if (statusbuf[1] & 0x10)
147
drivestatus = 3;
148
else
149
{
150
// Ok, so the door is closed, now is there a disc there?
151
success = DeviceIoControl(hCDROM, IOCTL_STORAGE_CHECK_VERIFY,
152
NULL, 0, NULL, 0, &dwBytesReturned, NULL);
153
if (!success)
154
drivestatus = 2;
155
else
156
drivestatus = 0;
157
}
158
}
159
else
160
drivestatus = 2;
161
162
Sleep(1000);
163
}
164
165
return 0;
166
}
167
168
//////////////////////////////////////////////////////////////////////////////
169
170
int SPTICDGetStatus() {
171
// This function is called periodically to see what the status of the
172
// drive is.
173
//
174
// Should return one of the following values:
175
// 0 - CD Present, disc spinning
176
// 1 - CD Present, disc not spinning
177
// 2 - CD not present
178
// 3 - Tray open
179
//
180
// If you really don't want to bother too much with this function, just
181
// return status 0. Though it is kind of nice when the bios's cd player,
182
// etc. recognizes when you've ejected the tray and popped in another disc.
183
/*
184
DWORD dwBytesReturned;
185
unsigned char statusbuf[8];
186
BOOL success;
187
188
sptd.Length=sizeof(sptd);
189
sptd.PathId=0; //
190
sptd.TargetId=0; // Don't need these, they're automatically generated
191
sptd.Lun=0; //
192
sptd.CdbLength=12;
193
sptd.SenseInfoLength=0; // No sense data
194
sptd.DataIn=SCSI_IOCTL_DATA_IN;
195
sptd.TimeOutValue=60; // may need to be changed
196
sptd.DataBuffer=(PVOID)&(statusbuf);
197
sptd.SenseInfoOffset=0;
198
sptd.DataTransferLength=8; // may need to change this
199
200
sptd.Cdb[0]=0xBD; // CDB12 code
201
sptd.Cdb[1]=0; // Reserved
202
sptd.Cdb[2]=0; // Reserved
203
sptd.Cdb[3]=0; // Reserved
204
sptd.Cdb[4]=0; // Reserved
205
sptd.Cdb[5]=0; // Reserved
206
sptd.Cdb[6]=0; // Reserved
207
sptd.Cdb[7]=0; // Reserved
208
sptd.Cdb[8]=0; // Allocation Length(byte 1)
209
sptd.Cdb[9]=8; // Allocation Length(byte 2) (may have to change this)
210
sptd.Cdb[10]=0; // Reserved
211
sptd.Cdb[11]=0; // Control
212
sptd.Cdb[12]=0;
213
sptd.Cdb[13]=0;
214
sptd.Cdb[14]=0;
215
sptd.Cdb[15]=0;
216
217
success=DeviceIoControl(hCDROM, IOCTL_SCSI_PASS_THROUGH_DIRECT,
218
(PVOID)&sptd, (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT),
219
NULL, 0, &dwBytesReturned, NULL);
220
221
if (success)
222
{
223
// Figure out drive status
224
225
// Is door open?
226
if (statusbuf[1] & 0x10) return 3;
227
228
// Ok, so the door is closed, now is there a disc there?
229
success = DeviceIoControl(hCDROM, IOCTL_STORAGE_CHECK_VERIFY,
230
NULL, 0, NULL, 0, &dwBytesReturned, NULL);
231
if (!success)
232
return 2;
233
234
return 0;
235
}
236
237
return 2;
238
*/
239
return drivestatus;
240
}
241
242
//////////////////////////////////////////////////////////////////////////////
243
244
#define MSF_TO_FAD(m,s,f) ((m * 4500) + (s * 75) + f)
245
246
s32 SPTICDReadTOC(u32 *TOC) {
247
// FILE *debugfp;
248
CDROM_TOC ctTOC;
249
DWORD dwNotUsed;
250
int i;
251
252
if (hCDROM != INVALID_HANDLE_VALUE)
253
{
254
memset(TOC, 0xFF, 0xCC * 2);
255
memset(&ctTOC, 0xFF, sizeof(CDROM_TOC));
256
257
if (DeviceIoControl (hCDROM, IOCTL_CDROM_READ_TOC,
258
NULL, 0, &ctTOC, sizeof(ctTOC),
259
&dwNotUsed, NULL) == 0)
260
{
261
return 0;
262
}
263
264
// convert TOC to saturn format
265
for (i = 0; i < ctTOC.LastTrack; i++)
266
{
267
TOC[i] = (ctTOC.TrackData[i].Control << 28) |
268
(ctTOC.TrackData[i].Adr << 24) |
269
MSF_TO_FAD(ctTOC.TrackData[i].Address[1], ctTOC.TrackData[i].Address[2], ctTOC.TrackData[i].Address[3]);
270
}
271
272
// Do First, Last, and Lead out sections here
273
274
TOC[99] = (ctTOC.TrackData[0].Control << 28) |
275
(ctTOC.TrackData[0].Adr << 24) |
276
(ctTOC.FirstTrack << 16);
277
278
TOC[100] = (ctTOC.TrackData[ctTOC.LastTrack - 1].Control << 28) |
279
(ctTOC.TrackData[ctTOC.LastTrack - 1].Adr << 24) |
280
(ctTOC.LastTrack << 16);
281
282
TOC[101] = (ctTOC.TrackData[ctTOC.LastTrack].Control << 28) |
283
(ctTOC.TrackData[ctTOC.LastTrack].Adr << 24) |
284
MSF_TO_FAD(ctTOC.TrackData[ctTOC.LastTrack].Address[1], ctTOC.TrackData[ctTOC.LastTrack].Address[2], ctTOC.TrackData[ctTOC.LastTrack].Address[3]);
285
286
// debugfp = fopen("cot2toc.bin", "wb");
287
// fwrite((void *)TOC, 1, 0xCC * 2, debugfp);
288
// fclose(debugfp);
289
290
return (0xCC * 2);
291
}
292
293
return 0;
294
}
295
296
//////////////////////////////////////////////////////////////////////////////
297
298
int SPTICDReadSectorFAD(u32 FAD, void *buffer) {
299
// This function is supposed to read exactly 1 -RAW- 2352-byte sector at
300
// the specified FAD address to buffer. Should return true if successful,
301
// false if there was an error.
302
//
303
// Special Note: To convert from FAD to LBA/LSN, minus 150.
304
//
305
// The whole process needed to be changed since I need more control over
306
// sector detection, etc. Not to mention it means less work for the porter
307
// since they only have to implement raw sector reading as opposed to
308
// implementing mode 1, mode 2 form1/form2, -and- raw sector reading.
309
310
DWORD dwBytesReturned;
311
BOOL success;
312
313
sptd.Length=sizeof(sptd);
314
sptd.PathId=0; //
315
sptd.TargetId=0; // Don't need these, they're automatically generated
316
sptd.Lun=0; //
317
sptd.CdbLength=12;
318
sptd.SenseInfoLength=0; // No sense data
319
sptd.DataIn=SCSI_IOCTL_DATA_IN;
320
sptd.TimeOutValue=60; // may need to be changed
321
sptd.DataBuffer=(PVOID)buffer;
322
sptd.SenseInfoOffset=0;
323
sptd.DataTransferLength=2352;
324
325
sptd.Cdb[0]=0xBE; // CDB12 code
326
sptd.Cdb[1]=0; // Sector Type, RELADR
327
FAD -= 150;
328
sptd.Cdb[2]=(unsigned char)((FAD & 0xFF000000) >> 24); // lba(byte 1)
329
sptd.Cdb[3]=(unsigned char)((FAD & 0x00FF0000) >> 16); // lba(byte 2)
330
sptd.Cdb[4]=(unsigned char)((FAD & 0x0000FF00) >> 8); // lba(byte 3)
331
sptd.Cdb[5]=(unsigned char)(FAD & 0x000000FF); // lba(byte 4)
332
sptd.Cdb[6]=0; // number of sectors(byte 1)
333
sptd.Cdb[7]=0; // number of sectors(byte 2)
334
sptd.Cdb[8]=1; // number of sectors(byte 3)
335
sptd.Cdb[9]=0xF8; // Sync + All Headers + User data + EDC/ECC
336
sptd.Cdb[10]=0;
337
sptd.Cdb[11]=0;
338
sptd.Cdb[12]=0;
339
sptd.Cdb[13]=0;
340
sptd.Cdb[14]=0;
341
sptd.Cdb[15]=0;
342
343
success=DeviceIoControl(hCDROM,
344
IOCTL_SCSI_PASS_THROUGH_DIRECT,
345
(PVOID)&sptd, (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT),
346
NULL, 0,
347
&dwBytesReturned,
348
NULL);
349
350
if (!success)
351
{
352
return 0;
353
}
354
355
return 1;
356
}
357
358
//////////////////////////////////////////////////////////////////////////////
359
360
void SPTICDReadAheadFAD(u32 FAD) {
361
// No-op
362
}
363
364
//////////////////////////////////////////////////////////////////////////////
365
366