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