PCem

view src/cdrom-ioctl.c @ 148:d08a822e6603

Force CD-ROM TOC to be loaded on startup, booting from CD-ROM should be more reliable.
author TomW
date Thu Aug 21 20:44:18 2014 +0100
parents 42d0b879eb9e
children
line source
1 /*Win32 CD-ROM support via IOCTL*/
3 #include <windows.h>
4 #include <io.h>
5 #include "ddk/ntddcdrm.h"
6 //#include "ntddcdrm.h"
7 #include "ibm.h"
8 #include "ide.h"
9 #include "cdrom-ioctl.h"
11 int cdrom_drive;
13 typedef struct _CDROM_TOC_SESSION_DATA {
14 UCHAR Length[2];
15 UCHAR FirstCompleteSession;
16 UCHAR LastCompleteSession;
17 TRACK_DATA TrackData[1];
18 } CDROM_TOC_SESSION_DATA, *PCDROM_TOC_SESSION_DATA;
19 static ATAPI ioctl_atapi;
21 static uint32_t last_block = 0;
22 static int ioctl_inited = 0;
23 static char ioctl_path[8];
24 static void ioctl_close(void);
25 static HANDLE hIOCTL;
26 static CDROM_TOC toc;
27 static int tocvalid = 0;
29 #define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)-150)
31 enum
32 {
33 CD_STOPPED = 0,
34 CD_PLAYING,
35 CD_PAUSED
36 };
38 static int ioctl_cd_state = CD_STOPPED;
39 static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0;
41 #define BUF_SIZE 32768
42 static int16_t cd_buffer[BUF_SIZE];
43 static int cd_buflen = 0;
44 void ioctl_audio_callback(int16_t *output, int len)
45 {
46 RAW_READ_INFO in;
47 DWORD count;
49 // return;
50 // pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount());
51 if (ioctl_cd_state != CD_PLAYING)
52 {
53 memset(output, 0, len * 2);
54 return;
55 }
56 while (cd_buflen < len)
57 {
58 if (ioctl_cd_pos < ioctl_cd_end)
59 {
60 in.DiskOffset.LowPart = ioctl_cd_pos * 2048;
61 in.DiskOffset.HighPart = 0;
62 in.SectorCount = 1;
63 in.TrackMode = CDDA;
64 ioctl_open(0);
65 // pclog("Read to %i\n", cd_buflen);
66 if (!DeviceIoControl(hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &cd_buffer[cd_buflen], 2352, &count, NULL))
67 {
68 // pclog("DeviceIoControl returned false\n");
69 memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2);
70 ioctl_cd_state = CD_STOPPED;
71 cd_buflen = len;
72 }
73 else
74 {
75 // pclog("DeviceIoControl returned true\n");
76 ioctl_cd_pos++;
77 cd_buflen += (2352 / 2);
78 }
79 ioctl_close();
80 }
81 else
82 {
83 memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2);
84 ioctl_cd_state = CD_STOPPED;
85 cd_buflen = len;
86 }
87 }
88 memcpy(output, cd_buffer, len * 2);
89 // for (c = 0; c < BUF_SIZE - len; c++)
90 // cd_buffer[c] = cd_buffer[c + cd_buflen];
91 memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2);
92 cd_buflen -= len;
93 // pclog("Done %i\n", GetTickCount());
94 }
96 void ioctl_audio_stop()
97 {
98 ioctl_cd_state = CD_STOPPED;
99 }
101 static int get_track_nr(uint32_t pos)
102 {
103 int c;
104 int track = 0;
106 if (!tocvalid)
107 return 0;
109 for (c = toc.FirstTrack; c < toc.LastTrack; c++)
110 {
111 uint32_t track_address = toc.TrackData[c].Address[3] +
112 (toc.TrackData[c].Address[2] * 75) +
113 (toc.TrackData[c].Address[1] * 75 * 60);
115 if (track_address <= pos)
116 track = c;
117 }
118 return track;
119 }
121 static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf)
122 {
123 if (!cdrom_drive) return;
124 pclog("Play audio - %08X %08X %i\n", pos, len, ismsf);
125 if (ismsf)
126 {
127 pos = (pos & 0xff) + (((pos >> 8) & 0xff) * 75) + (((pos >> 16) & 0xff) * 75 * 60);
128 len = (len & 0xff) + (((len >> 8) & 0xff) * 75) + (((len >> 16) & 0xff) * 75 * 60);
129 pclog("MSF - pos = %08X len = %08X\n", pos, len);
130 }
131 else
132 len += pos;
133 ioctl_cd_pos = pos;// + 150;
134 ioctl_cd_end = len;// + 150;
135 ioctl_cd_state = CD_PLAYING;
136 pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len);
137 /* CDROM_PLAY_AUDIO_MSF msf;
138 long size;
139 BOOL b;
140 if (ismsf)
141 {
142 msf.StartingF=pos&0xFF;
143 msf.StartingS=(pos>>8)&0xFF;
144 msf.StartingM=(pos>>16)&0xFF;
145 msf.EndingF=len&0xFF;
146 msf.EndingS=(len>>8)&0xFF;
147 msf.EndingM=(len>>16)&0xFF;
148 }
149 else
150 {
151 msf.StartingF=(uint8_t)(addr%75); addr/=75;
152 msf.StartingS=(uint8_t)(addr%60); addr/=60;
153 msf.StartingM=(uint8_t)(addr);
154 addr=pos+len+150;
155 msf.EndingF=(uint8_t)(addr%75); addr/=75;
156 msf.EndingS=(uint8_t)(addr%60); addr/=60;
157 msf.EndingM=(uint8_t)(addr);
158 }
159 ioctl_open(0);
160 b = DeviceIoControl(hIOCTL,IOCTL_CDROM_PLAY_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL);
161 pclog("DeviceIoControl returns %i\n", (int) b);
162 ioctl_close();*/
163 }
165 static void ioctl_pause(void)
166 {
167 if (!cdrom_drive) return;
168 if (ioctl_cd_state == CD_PLAYING)
169 ioctl_cd_state = CD_PAUSED;
170 // ioctl_open(0);
171 // DeviceIoControl(hIOCTL,IOCTL_CDROM_PAUSE_AUDIO,NULL,0,NULL,0,&size,NULL);
172 // ioctl_close();
173 }
175 static void ioctl_resume(void)
176 {
177 if (!cdrom_drive) return;
178 if (ioctl_cd_state == CD_PAUSED)
179 ioctl_cd_state = CD_PLAYING;
180 // ioctl_open(0);
181 // DeviceIoControl(hIOCTL,IOCTL_CDROM_RESUME_AUDIO,NULL,0,NULL,0,&size,NULL);
182 // ioctl_close();
183 }
185 static void ioctl_stop(void)
186 {
187 if (!cdrom_drive) return;
188 ioctl_cd_state = CD_STOPPED;
189 // ioctl_open(0);
190 // DeviceIoControl(hIOCTL,IOCTL_CDROM_STOP_AUDIO,NULL,0,NULL,0,&size,NULL);
191 // ioctl_close();
192 }
194 static void ioctl_seek(uint32_t pos)
195 {
196 if (!cdrom_drive) return;
197 // ioctl_cd_state = CD_STOPPED;
198 pclog("Seek %08X\n", pos);
199 ioctl_cd_pos = pos;
200 ioctl_cd_state = CD_STOPPED;
201 /* pos+=150;
202 CDROM_SEEK_AUDIO_MSF msf;
203 msf.F=(uint8_t)(pos%75); pos/=75;
204 msf.S=(uint8_t)(pos%60); pos/=60;
205 msf.M=(uint8_t)(pos);
206 // pclog("Seek to %02i:%02i:%02i\n",msf.M,msf.S,msf.F);
207 ioctl_open(0);
208 DeviceIoControl(hIOCTL,IOCTL_CDROM_SEEK_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL);
209 ioctl_close();*/
210 }
212 static int ioctl_ready(void)
213 {
214 long size;
215 int temp;
216 CDROM_TOC ltoc;
217 // pclog("Ready? %i\n",cdrom_drive);
218 if (!cdrom_drive) return 0;
219 ioctl_open(0);
220 temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&ltoc,sizeof(ltoc),&size,NULL);
221 ioctl_close();
222 if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) ||
223 (ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) ||
224 (ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3]) ||
225 !tocvalid)
226 {
227 ioctl_cd_state = CD_STOPPED;
228 /* pclog("Not ready %02X %02X %02X %02X %02X %02X %i\n",ltoc.TrackData[ltoc.LastTrack].Address[1],ltoc.TrackData[ltoc.LastTrack].Address[2],ltoc.TrackData[ltoc.LastTrack].Address[3],
229 toc.TrackData[ltoc.LastTrack].Address[1], toc.TrackData[ltoc.LastTrack].Address[2], toc.TrackData[ltoc.LastTrack].Address[3],tocvalid);*/
230 // atapi_discchanged();
231 /* ioctl_open(0);
232 temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL);
233 ioctl_close();*/
234 toc=ltoc;
235 tocvalid=1;
236 return 0;
237 }
238 // pclog("IOCTL says ready\n");
239 return 1;
240 // return (temp)?1:0;
241 }
243 static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf)
244 {
245 CDROM_SUB_Q_DATA_FORMAT insub;
246 SUB_Q_CHANNEL_DATA sub;
247 long size;
248 int pos=0;
249 if (!cdrom_drive) return 0;
251 insub.Format = IOCTL_CDROM_CURRENT_POSITION;
252 ioctl_open(0);
253 DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),&size,NULL);
254 ioctl_close();
256 if (ioctl_cd_state == CD_PLAYING || ioctl_cd_state == CD_PAUSED)
257 {
258 uint32_t cdpos = ioctl_cd_pos;
259 int track = get_track_nr(cdpos);
260 uint32_t track_address = toc.TrackData[track].Address[3] +
261 (toc.TrackData[track].Address[2] * 75) +
262 (toc.TrackData[track].Address[1] * 75 * 60);
264 b[pos++] = sub.CurrentPosition.Control;
265 b[pos++] = track + 1;
266 b[pos++] = sub.CurrentPosition.IndexNumber;
268 if (msf)
269 {
270 uint32_t dat = cdpos;
271 b[pos + 3] = (uint8_t)(dat % 75); dat /= 75;
272 b[pos + 2] = (uint8_t)(dat % 60); dat /= 60;
273 b[pos + 1] = (uint8_t)dat;
274 b[pos] = 0;
275 pos += 4;
276 dat = cdpos - track_address;
277 b[pos + 3] = (uint8_t)(dat % 75); dat /= 75;
278 b[pos + 2] = (uint8_t)(dat % 60); dat /= 60;
279 b[pos + 1] = (uint8_t)dat;
280 b[pos] = 0;
281 pos += 4;
282 }
283 else
284 {
285 b[pos++] = (cdpos >> 24) & 0xff;
286 b[pos++] = (cdpos >> 16) & 0xff;
287 b[pos++] = (cdpos >> 8) & 0xff;
288 b[pos++] = cdpos & 0xff;
289 cdpos -= track_address;
290 b[pos++] = (cdpos >> 24) & 0xff;
291 b[pos++] = (cdpos >> 16) & 0xff;
292 b[pos++] = (cdpos >> 8) & 0xff;
293 b[pos++] = cdpos & 0xff;
294 }
296 if (ioctl_cd_state == CD_PLAYING) return 0x11;
297 return 0x12;
298 }
300 b[pos++]=sub.CurrentPosition.Control;
301 b[pos++]=sub.CurrentPosition.TrackNumber;
302 b[pos++]=sub.CurrentPosition.IndexNumber;
304 if (msf)
305 {
306 int c;
307 for (c = 0; c < 4; c++)
308 b[pos++] = sub.CurrentPosition.AbsoluteAddress[c];
309 for (c = 0; c < 4; c++)
310 b[pos++] = sub.CurrentPosition.TrackRelativeAddress[c];
311 }
312 else
313 {
314 uint32_t temp = MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]);
315 b[pos++] = temp >> 24;
316 b[pos++] = temp >> 16;
317 b[pos++] = temp >> 8;
318 b[pos++] = temp;
319 temp = MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3]);
320 b[pos++] = temp >> 24;
321 b[pos++] = temp >> 16;
322 b[pos++] = temp >> 8;
323 b[pos++] = temp;
324 }
326 return 0x13;
327 }
329 static void ioctl_eject(void)
330 {
331 long size;
332 if (!cdrom_drive) return;
333 ioctl_cd_state = CD_STOPPED;
334 ioctl_open(0);
335 DeviceIoControl(hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&size,NULL);
336 ioctl_close();
337 }
339 static void ioctl_load(void)
340 {
341 long size;
342 if (!cdrom_drive) return;
343 ioctl_cd_state = CD_STOPPED;
344 ioctl_open(0);
345 DeviceIoControl(hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,&size,NULL);
346 ioctl_close();
347 }
349 static void ioctl_readsector(uint8_t *b, int sector)
350 {
351 LARGE_INTEGER pos;
352 long size;
353 if (!cdrom_drive) return;
354 ioctl_cd_state = CD_STOPPED;
355 pos.QuadPart=sector*2048;
356 ioctl_open(0);
357 SetFilePointer(hIOCTL,pos.LowPart,&pos.HighPart,FILE_BEGIN);
358 ReadFile(hIOCTL,b,2048,&size,NULL);
359 ioctl_close();
360 }
362 static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single)
363 {
364 int len=4;
365 long size;
366 int c,d;
367 uint32_t temp;
368 if (!cdrom_drive) return 0;
369 ioctl_cd_state = CD_STOPPED;
370 ioctl_open(0);
371 DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL);
372 ioctl_close();
373 tocvalid=1;
374 // pclog("Read TOC done! %i\n",single);
375 b[2]=toc.FirstTrack;
376 b[3]=toc.LastTrack;
377 d=0;
378 for (c=0;c<=toc.LastTrack;c++)
379 {
380 if (toc.TrackData[c].TrackNumber>=starttrack)
381 {
382 d=c;
383 break;
384 }
385 }
386 b[2]=toc.TrackData[c].TrackNumber;
387 last_block = 0;
388 for (c=d;c<=toc.LastTrack;c++)
389 {
390 uint32_t address;
391 if ((len+8)>maxlen) break;
392 // pclog("Len %i max %i Track %02X - %02X %02X %i %i %i %i %08X\n",len,maxlen,toc.TrackData[c].TrackNumber,toc.TrackData[c].Adr,toc.TrackData[c].Control,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3],MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));
393 b[len++]=0; /*Reserved*/
394 b[len++]=(toc.TrackData[c].Adr<<4)|toc.TrackData[c].Control;
395 b[len++]=toc.TrackData[c].TrackNumber;
396 b[len++]=0; /*Reserved*/
397 address = MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]);
398 if (address > last_block)
399 last_block = address;
401 if (msf)
402 {
403 b[len++]=toc.TrackData[c].Address[0];
404 b[len++]=toc.TrackData[c].Address[1];
405 b[len++]=toc.TrackData[c].Address[2];
406 b[len++]=toc.TrackData[c].Address[3];
407 }
408 else
409 {
410 temp=MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]);
411 b[len++]=temp>>24;
412 b[len++]=temp>>16;
413 b[len++]=temp>>8;
414 b[len++]=temp;
415 }
416 if (single) break;
417 }
418 b[0] = (uint8_t)(((len-2) >> 8) & 0xff);
419 b[1] = (uint8_t)((len-2) & 0xff);
420 /* pclog("Table of Contents (%i bytes) : \n",size);
421 pclog("First track - %02X\n",toc.FirstTrack);
422 pclog("Last track - %02X\n",toc.LastTrack);
423 for (c=0;c<=toc.LastTrack;c++)
424 pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]);
425 for (c=0;c<=toc.LastTrack;c++)
426 pclog("Track %02X - number %02X control %02X adr %02X address %06X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));*/
427 return len;
428 }
430 static void ioctl_readtoc_session(unsigned char *b, int msf, int maxlen)
431 {
432 int len=4;
433 int size;
434 uint32_t temp;
435 CDROM_READ_TOC_EX toc_ex;
436 CDROM_TOC_SESSION_DATA toc;
437 if (!cdrom_drive) return;
438 ioctl_cd_state = CD_STOPPED;
439 memset(&toc_ex,0,sizeof(toc_ex));
440 memset(&toc,0,sizeof(toc));
441 toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_SESSION;
442 toc_ex.Msf=msf;
443 toc_ex.SessionTrack=0;
444 ioctl_open(0);
445 DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL);
446 ioctl_close();
447 // pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber);
448 b[2]=toc.FirstCompleteSession;
449 b[3]=toc.LastCompleteSession;
450 b[len++]=0; /*Reserved*/
451 b[len++]=(toc.TrackData[0].Adr<<4)|toc.TrackData[0].Control;
452 b[len++]=toc.TrackData[0].TrackNumber;
453 b[len++]=0; /*Reserved*/
454 if (msf)
455 {
456 b[len++]=toc.TrackData[0].Address[0];
457 b[len++]=toc.TrackData[0].Address[1];
458 b[len++]=toc.TrackData[0].Address[2];
459 b[len++]=toc.TrackData[0].Address[3];
460 }
461 else
462 {
463 temp=MSFtoLBA(toc.TrackData[0].Address[1],toc.TrackData[0].Address[2],toc.TrackData[0].Address[3]);
464 b[len++]=temp>>24;
465 b[len++]=temp>>16;
466 b[len++]=temp>>8;
467 b[len++]=temp;
468 }
469 }
471 static uint32_t ioctl_size()
472 {
473 unsigned char b[4096];
475 atapi->readtoc(b, 0, 0, 4096, 0);
477 return last_block;
478 }
480 void ioctl_reset()
481 {
482 CDROM_TOC ltoc;
483 int temp;
484 long size;
486 if (!cdrom_drive)
487 {
488 tocvalid = 0;
489 return;
490 }
492 ioctl_open(0);
493 temp = DeviceIoControl(hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, &ltoc, sizeof(ltoc), &size, NULL);
494 ioctl_close();
496 toc = ltoc;
497 tocvalid = 1;
498 }
500 int ioctl_open(char d)
501 {
502 // char s[8];
503 if (!ioctl_inited)
504 {
505 sprintf(ioctl_path,"\\\\.\\%c:",d);
506 pclog("Path is %s\n",ioctl_path);
507 tocvalid=0;
508 }
509 // pclog("Opening %s\n",ioctl_path);
510 hIOCTL = CreateFile(/*"\\\\.\\g:"*/ioctl_path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
511 if (!hIOCTL)
512 {
513 //fatal("IOCTL");
514 }
515 atapi=&ioctl_atapi;
516 if (!ioctl_inited)
517 {
518 ioctl_inited=1;
519 CloseHandle(hIOCTL);
520 }
521 return 0;
522 }
524 static void ioctl_close(void)
525 {
526 CloseHandle(hIOCTL);
527 }
529 static void ioctl_exit(void)
530 {
531 ioctl_stop();
532 ioctl_inited=0;
533 tocvalid=0;
534 }
536 static ATAPI ioctl_atapi=
537 {
538 ioctl_ready,
539 ioctl_readtoc,
540 ioctl_readtoc_session,
541 ioctl_getcurrentsubchannel,
542 ioctl_readsector,
543 ioctl_playaudio,
544 ioctl_seek,
545 ioctl_load,
546 ioctl_eject,
547 ioctl_pause,
548 ioctl_resume,
549 ioctl_size,
550 ioctl_stop,
551 ioctl_exit
552 };