1 /*
2 NatFeat host CD-ROM access
3
4 ARAnyM (C) 2003 Patrice Mandin
5
6 This program 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 This program 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 this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "sysdeps.h"
22 #include "cpu_emulation.h"
23 #include "parameters.h"
24 #include "nfcdrom_sdl.h"
25
26 #if !SDL_VERSION_ATLEAST(2, 0, 0)
27
28 #include "nfcdrom_atari.h"
29 #include "../../atari/nfcdrom/nfcdrom_nfapi.h"
30 #include "toserror.h"
31
32 #define DEBUG 0
33 #include "debug.h"
34
35 #include <cstdlib>
36 #include <errno.h>
37
38 /*--- Defines ---*/
39
40 #define NFCD_NAME "nf:cdrom:sdl: "
41
42 /*--- Constructor/desctructor ---*/
43
CdromDriverSdl(void)44 CdromDriverSdl::CdromDriverSdl(void)
45 {
46 D(bug(NFCD_NAME "CdromDriverSdl()"));
47 for (int i=0; i<CD_MAX_DRIVES; i++) {
48 drive_handles[i]=NULL;
49 }
50 }
51
~CdromDriverSdl(void)52 CdromDriverSdl::~CdromDriverSdl(void)
53 {
54 D(bug(NFCD_NAME "~CdromDriverSdl()"));
55 }
56
57 /*--- Public functions ---*/
58
Count()59 int CdromDriverSdl::Count()
60 {
61 return SDL_CDNumDrives();
62 }
63
DeviceName(int drive)64 const char *CdromDriverSdl::DeviceName(int drive)
65 {
66 return SDL_CDName(drive);
67 }
68
69 /*--- Protected functions ---*/
70
OpenDrive(memptr device)71 int CdromDriverSdl::OpenDrive(memptr device)
72 {
73 int drive;
74
75 drive = GetDrive(device);
76 drive = DriveFromLetter(drive);
77
78 /* Drive exist ? */
79 if (drive < 0 || drive >= CD_MAX_DRIVES || (drives_mask & (1<<drive))==0) {
80 D(bug(NFCD_NAME " physical device %c does not exist", GetDrive(device)));
81 return TOS_EUNDEV;
82 }
83
84 /* Drive opened ? */
85 if (drive_handles[drive]) {
86 return drive;
87 }
88
89 /* Open drive */
90 drive_handles[drive]=SDL_CDOpen(bx_options.nfcdroms[drive].physdevtohostdev);
91 if (drive_handles[drive]==NULL) {
92 D(bug(NFCD_NAME " error opening SDL CD drive %d (%s)", bx_options.nfcdroms[drive].physdevtohostdev, DeviceName(bx_options.nfcdroms[drive].physdevtohostdev)));
93 return TOS_EFILNF;
94 }
95
96 D(bug(NFCD_NAME "DriveOpened: %c", DriveToLetter(drive)));
97 return drive;
98 }
99
CloseDrive(int drive)100 void CdromDriverSdl::CloseDrive(int drive)
101 {
102 /* D(bug(NFCD_NAME "CloseDrive(%c)", DriveToLetter(drive)));*/
103
104 /* Drive already closed ? */
105 if (drive_handles[drive]==NULL) {
106 return;
107 }
108
109 SDL_CDClose(drive_handles[drive]);
110 drive_handles[drive]=NULL;
111 }
112
113 /*--- MetaDOS functions ---*/
114
cd_status(memptr device,memptr ext_status)115 int32 CdromDriverSdl::cd_status(memptr device, memptr ext_status)
116 {
117 UNUSED(ext_status);
118 int drive, mediachanged;
119 CDstatus status;
120
121 D(bug(NFCD_NAME "Status()"));
122 drive = OpenDrive(device);
123 if (drive<0) {
124 return drive;
125 }
126
127 mediachanged = 1; /* Can not check media changed: return always changed */
128
129 status = SDL_CDStatus(drive_handles[drive]);
130 CloseDrive(drive);
131
132 if ((status == CD_TRAYEMPTY) || (status == CD_ERROR)) {
133 return TOS_EDRVNR;
134 }
135
136 return (mediachanged<<3);
137 }
138
cd_ioctl(memptr device,uint16 opcode,memptr buffer)139 int32 CdromDriverSdl::cd_ioctl(memptr device, uint16 opcode, memptr buffer)
140 {
141 int drive, errorcode;
142 CDstatus status;
143 SDL_CD *cur_cd;
144
145 D(bug(NFCD_NAME "Ioctl(0x%04x)", opcode));
146 drive = OpenDrive(device);
147 if (drive<0) {
148 return drive;
149 }
150
151 cur_cd = drive_handles[drive];
152 /*
153 * brain-damaged SDL error system, which sometimes just calls
154 * SDL_SetError() and does not set errno, and only returns
155 * strings as error codes, requires us to clear errno
156 */
157 errno = 0;
158
159 status = SDL_CDStatus(cur_cd);
160
161 errorcode = TOS_ENOSYS;
162 switch(opcode) {
163 case ATARI_CDROMREADOFFSET: /* CDROMREADOFFSET */
164 break;
165 case ATARI_CDROMPAUSE: /* CDROMPAUSE */
166 {
167 errorcode=SDL_CDPause(cur_cd);
168 }
169 break;
170 case ATARI_CDROMRESUME: /* CDROMRESUME */
171 {
172 errorcode=SDL_CDResume(cur_cd);
173 }
174 break;
175 case ATARI_CDROMPLAYMSF: /* CDROMPLAYMSF */
176 {
177 unsigned char *atari_msf;
178 int start, length;
179
180 atari_msf = (unsigned char *) Atari2HostAddr(buffer);
181 D(bug(NFCD_NAME " Ioctl(CDROMPLAYMSF)"));
182
183 start = MSF_TO_FRAMES(atari_msf[0],atari_msf[1],atari_msf[2]);
184 length = MSF_TO_FRAMES(atari_msf[3],atari_msf[4],atari_msf[5])-start;
185
186 errorcode=SDL_CDPlay(cur_cd, start, length);
187 }
188 break;
189 case ATARI_CDROMPLAYTRKIND: /* CDROMPLAYTRKIND */
190 {
191 unsigned char *atari_ti;
192 int start, length, i;
193
194 atari_ti = (unsigned char *) Atari2HostAddr(buffer);
195 D(bug(NFCD_NAME " Ioctl(CDROMPLAYTRKIND)"));
196
197 start = cur_cd->track[atari_ti[0]].offset;
198 length = 0;
199 for (i=atari_ti[0]; i<atari_ti[2]; i++) {
200 length += cur_cd->track[i].length;
201 }
202
203 errorcode=SDL_CDPlay(cur_cd, start, length);
204 }
205 break;
206 case ATARI_CDROMREADTOCHDR: /* CDROMREADTOCHDR */
207 {
208 atari_cdromtochdr_t *atari_tochdr;
209
210 atari_tochdr = (atari_cdromtochdr_t *) Atari2HostAddr(buffer);
211 D(bug(NFCD_NAME " Ioctl(READTOCHDR)"));
212
213 if CD_INDRIVE(status) {
214 atari_tochdr->cdth_trk0 = cur_cd->track[0].id;
215 atari_tochdr->cdth_trk1 = cur_cd->track[cur_cd->numtracks-1].id;
216 errorcode=0;
217 } else {
218 errorcode=TOS_EDRVNR;
219 }
220 }
221 break;
222 case ATARI_CDROMREADTOCENTRY: /* CDROMREADTOCENTRY */
223 {
224 unsigned char *atari_tocentry;
225 int i, minute, second, frame;
226
227 atari_tocentry = (unsigned char *) Atari2HostAddr(buffer);
228 D(bug(NFCD_NAME " Ioctl(READTOCENTRY)"));
229
230 atari_tocentry[2] = 0;
231 atari_tocentry[3] = 0;
232 atari_tocentry[4] = atari_tocentry[5] = 0;
233 atari_tocentry[6] = atari_tocentry[7] = atari_tocentry[8] = atari_tocentry[9] =0;
234 errorcode=TOS_EDRVNR;
235 if CD_INDRIVE(status) {
236 /* Search the track */
237 for (i=0; i<=cur_cd->numtracks; i++) {
238 if (cur_cd->track[i].id == atari_tocentry[0]) {
239 atari_tocentry[2] = cur_cd->track[i].type & 0x0f;
240 if (atari_tocentry[1] == CDROM_LBA) {
241 *((unsigned long *) &atari_tocentry[6]) = SDL_SwapBE32(cur_cd->track[i].offset);
242 } else {
243 FRAMES_TO_MSF(cur_cd->track[i].offset, &minute, &second, &frame);
244 atari_tocentry[7] = minute;
245 atari_tocentry[8] = second;
246 atari_tocentry[9] = frame;
247 }
248 errorcode=0;
249 break;
250 }
251 }
252 }
253 }
254 break;
255 case ATARI_CDROMSTOP: /* CDROMSTOP */
256 {
257 errorcode=SDL_CDStop(cur_cd);
258 }
259 break;
260 case ATARI_CDROMSTART: /* CDROMSTART */
261 break;
262 case ATARI_CDROMEJECT: /* CDROMEJECT */
263 {
264 errorcode=SDL_CDEject(cur_cd);
265 }
266 break;
267 case ATARI_CDROMVOLCTRL: /* CDROMVOLCTRL */
268 break;
269 case ATARI_CDROMSUBCHNL: /* CDROMSUBCHNL */
270 {
271 unsigned char *atari_subchnl;
272 int minute, second, frame, abs_addr, rel_addr;
273
274 atari_subchnl = (unsigned char *) Atari2HostAddr(buffer);
275 D(bug(NFCD_NAME " Ioctl(READSUBCHNL,0x%02x)", atari_subchnl[0]));
276
277 atari_subchnl[1] = CDROM_AUDIO_INVALID; /* audiostatus */
278 atari_subchnl[5] = 1; /* index */
279 atari_subchnl[2] = /* reserved */
280 atari_subchnl[3] = /* adr+ctrl */
281 atari_subchnl[4] = /* track */
282 atari_subchnl[6] = /* abs_addr */
283 atari_subchnl[7] =
284 atari_subchnl[8] =
285 atari_subchnl[9] =
286 atari_subchnl[10] = /* rel_addr */
287 atari_subchnl[11] =
288 atari_subchnl[12] =
289 atari_subchnl[13] = 0;
290
291 switch(status) {
292 case CD_TRAYEMPTY:
293 atari_subchnl[1] = CDROM_AUDIO_NO_STATUS;
294 break;
295 case CD_STOPPED:
296 atari_subchnl[1] = CDROM_AUDIO_COMPLETED;
297 break;
298 case CD_PLAYING:
299 atari_subchnl[1] = CDROM_AUDIO_PLAY;
300 break;
301 case CD_PAUSED:
302 atari_subchnl[1] = CDROM_AUDIO_PAUSED;
303 break;
304 case CD_ERROR:
305 atari_subchnl[1] = CDROM_AUDIO_ERROR;
306 break;
307 }
308 if CD_INDRIVE(status) {
309 rel_addr = cur_cd->cur_frame;
310 abs_addr = cur_cd->track[cur_cd->cur_track].offset + rel_addr;
311
312 atari_subchnl[4] = cur_cd->track[cur_cd->cur_track].id;
313 atari_subchnl[3] = cur_cd->track[cur_cd->cur_track].type == SDL_DATA_TRACK ? CDROM_DATA_TRACK : 0;
314 if (atari_subchnl[0] == CDROM_LBA) {
315 *((unsigned long *) &atari_subchnl[6]) =
316 SDL_SwapBE32(abs_addr);
317 *((unsigned long *) &atari_subchnl[10]) =
318 SDL_SwapBE32(rel_addr);
319 } else {
320 FRAMES_TO_MSF(abs_addr, &minute, &second, &frame);
321 *((Uint32 *) &atari_subchnl[6]) =
322 SDL_SwapBE32((minute<<16)|(second<<8)|frame);
323 FRAMES_TO_MSF(rel_addr, &minute, &second, &frame);
324 *((Uint32 *) &atari_subchnl[10]) =
325 SDL_SwapBE32((minute<<16)|(second<<8)|frame);
326 }
327 D(bug(NFCD_NAME "Ioctl(CDROMSUBCHNL): Format=%d, Status=0x%02x, Info=0x%02x, Trk=%d, Ind=%d, Abs=0x%08x, Rel=0x%08x",
328 atari_subchnl[0],
329 atari_subchnl[1],
330 atari_subchnl[3],
331 atari_subchnl[4],
332 atari_subchnl[5],
333 SDL_SwapBE32(*(Uint32 *)&atari_subchnl[6]),
334 SDL_SwapBE32(*(Uint32 *)&atari_subchnl[10])));
335 errorcode=0;
336 } else {
337 errorcode=TOS_EDRVNR;
338 }
339 }
340 break;
341 case ATARI_CDROMREADMODE2: /* CDROMREADMODE2 */
342 case ATARI_CDROMREADMODE1: /* CDROMREADMODE1 */
343 break;
344 case ATARI_CDROMPREVENTREMOVAL: /* CDROMPREVENTREMOVAL */
345 break;
346 case ATARI_CDROMALLOWREMOVAL: /* CDROMALLOWREMOVAL */
347 break;
348 case ATARI_CDROMAUDIOCTRL: /* CDROMAUDIOCTRL */
349 break;
350 case ATARI_CDROMREADDA: /* CDROMREADDA */
351 break;
352 case ATARI_CDROMRESET: /* unused */
353 break;
354 case ATARI_CDROMGETMCN: /* CDROMGETMCN */
355 break;
356 case ATARI_CDROMGETTISRC: /* CDROMGETTISRC */
357 break;
358 }
359 if (errorcode == CD_ERROR)
360 {
361 if (errno != 0)
362 errorcode = errnoHost2Mint(errno, TOS_EDRVNR);
363 else
364 errorcode = TOS_EDRVNR;
365 }
366 CloseDrive(drive);
367 return errorcode;
368 }
369
cd_startaudio(memptr device,uint32 dummy,memptr buffer)370 int32 CdromDriverSdl::cd_startaudio(memptr device, uint32 dummy, memptr buffer)
371 {
372 UNUSED(dummy);
373 int drive, errorcode;
374 metados_bos_tracks_t *atari_track_index;
375
376 D(bug(NFCD_NAME "StartAudio()"));
377 drive = OpenDrive(device);
378 if (drive<0) {
379 return drive;
380 }
381
382 if (CD_INDRIVE(SDL_CDStatus(drive_handles[drive]))<=0) {
383 return TOS_ENOSYS;
384 }
385
386 atari_track_index = (metados_bos_tracks_t *) Atari2HostAddr(buffer);
387
388 errno = 0;
389 errorcode = SDL_CDPlayTracks(drive_handles[drive],
390 atari_track_index->first, 0,
391 atari_track_index->count, 0);
392
393 if (errorcode == CD_ERROR)
394 {
395 if (errno != 0)
396 errorcode = errnoHost2Mint(errno, TOS_EDRVNR);
397 else
398 errorcode = TOS_EDRVNR;
399 }
400 CloseDrive(drive);
401 return errorcode;
402 }
403
cd_stopaudio(memptr device)404 int32 CdromDriverSdl::cd_stopaudio(memptr device)
405 {
406 int drive, errorcode;
407
408 D(bug(NFCD_NAME "StopAudio()"));
409 drive = OpenDrive(device);
410 if (drive<0) {
411 return drive;
412 }
413
414 errno = 0;
415 errorcode = SDL_CDStop(drive_handles[drive]);
416 if (errorcode == CD_ERROR)
417 {
418 if (errno != 0)
419 errorcode = errnoHost2Mint(errno, TOS_EDRVNR);
420 else
421 errorcode = TOS_EDRVNR;
422 }
423
424 CloseDrive(drive);
425 return errorcode;
426 }
427
cd_setsongtime(memptr device,uint32 dummy,uint32 start_msf,uint32 end_msf)428 int32 CdromDriverSdl::cd_setsongtime(memptr device, uint32 dummy, uint32 start_msf, uint32 end_msf)
429 {
430 UNUSED(dummy);
431 int drive, errorcode, start, length;
432
433 D(bug(NFCD_NAME "SetSongTime()"));
434 drive = OpenDrive(device);
435 if (drive<0) {
436 return drive;
437 }
438
439 errno = 0;
440 if (CD_INDRIVE(SDL_CDStatus(drive_handles[drive]))<=0) {
441 return TOS_ENOSYS;
442 }
443
444 start = MSF_TO_FRAMES((start_msf>>16) & 0xff, (start_msf>>8) & 0xff, (start_msf>>0) & 0xff);
445 length = start;
446 length += MSF_TO_FRAMES((end_msf>>16) & 0xff, (end_msf>>8) & 0xff, (end_msf>>0) & 0xff);
447
448 errorcode=SDL_CDPlay(drive_handles[drive], start, length);
449 if (errorcode == CD_ERROR)
450 {
451 if (errno != 0)
452 errorcode = errnoHost2Mint(errno, TOS_EDRVNR);
453 else
454 errorcode = TOS_EDRVNR;
455 }
456 CloseDrive(drive);
457 return errorcode;
458 }
459
cd_gettoc(memptr device,uint32 dummy,memptr buffer)460 int32 CdromDriverSdl::cd_gettoc(memptr device, uint32 dummy, memptr buffer)
461 {
462 UNUSED(dummy);
463 int drive, i;
464 SDL_CD *cur_cd;
465 atari_tocentry_t *atari_tocentry;
466
467 D(bug(NFCD_NAME "GetToc()"));
468 drive = OpenDrive(device);
469 if (drive<0) {
470 return drive;
471 }
472
473 if (CD_INDRIVE(SDL_CDStatus(drive_handles[drive]))<=0) {
474 return TOS_ENOSYS;
475 }
476
477 cur_cd = drive_handles[drive];
478
479 atari_tocentry = (atari_tocentry_t *) Atari2HostAddr(buffer);
480 for (i=0; i<=cur_cd->numtracks; i++) {
481 int minute, second, frame;
482
483 FRAMES_TO_MSF(cur_cd->track[i].offset, &minute, &second, &frame);
484 atari_tocentry[i].track = cur_cd->track[i].id;
485 if (i == cur_cd->numtracks) {
486 atari_tocentry[i].track = CDROM_LEADOUT_CDAR;
487 }
488 atari_tocentry[i].minute = BinaryToBcd(minute);
489 atari_tocentry[i].second = BinaryToBcd(second);
490 atari_tocentry[i].frame = BinaryToBcd(frame);
491 D(bug(NFCD_NAME "GetToc(): %02x: msf %02d:%02d:%02d, bcd: %02x:%02x:%02x",
492 atari_tocentry[i].track,
493 minute,
494 second,
495 frame,
496 atari_tocentry[i].minute,
497 atari_tocentry[i].second,
498 atari_tocentry[i].frame
499 ));
500 }
501
502 atari_tocentry[cur_cd->numtracks+1].track =
503 atari_tocentry[cur_cd->numtracks+1].minute =
504 atari_tocentry[cur_cd->numtracks+1].second =
505 atari_tocentry[cur_cd->numtracks+1].frame = 0;
506
507 CloseDrive(drive);
508 return TOS_E_OK;
509 }
510
cd_discinfo(memptr device,memptr buffer)511 int32 CdromDriverSdl::cd_discinfo(memptr device, memptr buffer)
512 {
513 int drive, minute, second, frame;
514 SDL_CD *cur_cd;
515 atari_discinfo_t *discinfo;
516
517 D(bug(NFCD_NAME "DiscInfo()"));
518 drive = OpenDrive(device);
519 if (drive<0) {
520 return drive;
521 }
522
523 if (CD_INDRIVE(SDL_CDStatus(drive_handles[drive]))<=0) {
524 return TOS_ENOSYS;
525 }
526
527 cur_cd = drive_handles[drive];
528
529 discinfo = (atari_discinfo_t *) Atari2HostAddr(buffer);
530 memset(discinfo, 0, sizeof(atari_discinfo_t));
531
532 discinfo->first = cur_cd->track[0].id;
533 discinfo->last = cur_cd->track[cur_cd->numtracks-1].id;
534 discinfo->current = cur_cd->track[cur_cd->cur_track].id;
535 discinfo->index = 1;
536 discinfo->disctype = (cur_cd->track[0].type == SDL_AUDIO_TRACK) ? 0 : 1;
537
538 FRAMES_TO_MSF(cur_cd->cur_frame, &minute, &second, &frame);
539 discinfo->relative.track = 0;
540 discinfo->relative.minute = BinaryToBcd(minute);
541 discinfo->relative.second = BinaryToBcd(second);
542 discinfo->relative.frame = BinaryToBcd(frame);
543
544 FRAMES_TO_MSF(cur_cd->track[cur_cd->cur_track].offset + cur_cd->cur_frame, &minute, &second, &frame);
545 discinfo->absolute.track = 0;
546 discinfo->absolute.minute = BinaryToBcd(minute);
547 discinfo->absolute.second = BinaryToBcd(second);
548 discinfo->absolute.frame = BinaryToBcd(frame);
549
550 FRAMES_TO_MSF(cur_cd->track[cur_cd->numtracks].offset, &minute, &second, &frame);
551 discinfo->end.track = 0;
552 discinfo->end.minute = BinaryToBcd(minute);
553 discinfo->end.second = BinaryToBcd(second);
554 discinfo->end.frame = BinaryToBcd(frame);
555
556 D(bug(NFCD_NAME "DiscInfo(): first=%d, last=%d, current=%d, ind=%d, rel=%02x:%02x:%02x, abs=%02x:%02x:%02x, end=%02x:%02x:%02x",
557 discinfo->first, discinfo->last, discinfo->current, discinfo->index,
558 discinfo->relative.minute, discinfo->relative.second, discinfo->relative.frame,
559 discinfo->absolute.minute, discinfo->absolute.second, discinfo->absolute.frame,
560 discinfo->end.minute, discinfo->end.second, discinfo->end.frame));
561
562 CloseDrive(drive);
563 return TOS_E_OK;
564 }
565
566 #endif
567