1 /*
2 	NatFeat host CD-ROM access, Linux CD-ROM driver
3 
4 	ARAnyM (C) 2003-2005 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 
25 #ifdef NFCDROM_LINUX_SUPPORT
26 
27 #include "nfcdrom.h"
28 #include "nfcdrom_atari.h"
29 #include "nfcdrom_linux.h"
30 
31 #include <linux/cdrom.h>
32 #include <errno.h>
33 #include "toserror.h"
34 
35 #define DEBUG 0
36 #include "debug.h"
37 
38 /*--- Defines ---*/
39 
40 #define NFCD_NAME	"nf:cdrom:linux: "
41 
42 #ifndef MSF_TO_FRAMES
43 #define CD_FPS     75
44 #define MSF_TO_FRAMES(M, S, F)     ((M)*60*CD_FPS+(S)*CD_FPS+(F))
45 #endif
46 
47 /* Define this to use the alternative getmntent() code */
48 #ifndef __SVR4
49 #define USE_MNTENT
50 #endif
51 
52 #ifdef USE_MNTENT
53 #if defined(__USLC__)
54 #include <sys/mntent.h>
55 #else
56 #include <mntent.h>
57 #endif
58 
59 #ifndef _PATH_MNTTAB
60 #ifdef MNTTAB
61 #define _PATH_MNTTAB	MNTTAB
62 #else
63 #define _PATH_MNTTAB	"/etc/fstab"
64 #endif
65 #endif /* !_PATH_MNTTAB */
66 
67 #ifndef _PATH_MOUNTED
68 #define _PATH_MOUNTED	"/etc/mtab"
69 #endif /* !_PATH_MOUNTED */
70 
71 #ifndef MNTTYPE_CDROM
72 #define MNTTYPE_CDROM	"iso9660"
73 #endif
74 #ifndef MNTTYPE_SUPER
75 #define MNTTYPE_SUPER	"supermount"
76 #endif
77 #endif /* USE_MNTENT */
78 
79 #ifndef ENOMEDIUM
80 #define ENOMEDIUM ENOENT
81 #endif
82 #define ERRNO_TRAYEMPTY(errno)	\
83 	((errno == EIO)    || (errno == ENOENT) || \
84 	 (errno == EINVAL) || (errno == ENOMEDIUM))
85 
86 /*--- Private functions ---*/
87 
88 /* Check a drive to see if it is a CD-ROM */
CheckDrive(const char * drive,const char * mnttype,struct stat * stbuf)89 int CdromDriverLinux::CheckDrive(const char *drive, const char *mnttype, struct stat *stbuf)
90 {
91 	int is_cd, cdfd;
92 	struct cdrom_subchnl info;
93 
94 	/* If it doesn't exist, return -1 */
95 	if ( stat(drive, stbuf) < 0 ) {
96 		return(-1);
97 	}
98 
99 	/* If it does exist, verify that it's an available CD-ROM */
100 	is_cd = 0;
101 	if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
102 		cdfd = open(drive, (O_RDONLY|O_NONBLOCK), 0);
103 		if ( cdfd >= 0 ) {
104 			info.cdsc_format = CDROM_MSF;
105 			/* Under Linux, EIO occurs when a disk is not present.
106 			 */
107 			if ( (ioctl(cdfd, CDROMSUBCHNL, &info) == 0) ||
108 						ERRNO_TRAYEMPTY(errno) ) {
109 				is_cd = 1;
110 			}
111 			close(cdfd);
112 		}
113 #ifdef USE_MNTENT
114 		/* Even if we can't read it, it might be mounted */
115 		else if ( mnttype && (strcmp(mnttype, MNTTYPE_CDROM) == 0) ) {
116 			is_cd = 1;
117 		}
118 #endif
119 	}
120 	return(is_cd);
121 }
122 
123 /* Add a CD-ROM drive to our list of valid drives */
AddDrive(const char * drive,struct stat * stbuf)124 void CdromDriverLinux::AddDrive(const char *drive, struct stat *stbuf)
125 {
126 	int i;
127 
128 	if ( numcds < CD_MAX_DRIVES ) {
129 		/* Check to make sure it's not already in our list.
130 	 	   This can happen when we see a drive via symbolic link.
131 		 */
132 		for ( i=0; i<numcds; ++i ) {
133 			if ( stbuf->st_rdev == cddrives[i].cdmode ) {
134 			    D(bug("Duplicate drive detected: %s == %s", drive, cddrives[i].device));
135 				return;
136 			}
137 		}
138 
139 		/* Add this drive to our list */
140 		i = numcds;
141 		cddrives[i].device = strdup(drive);
142 		if ( cddrives[i].device == NULL ) {
143 			return;
144 		}
145 		cddrives[i].cdmode = stbuf->st_rdev;
146 		++numcds;
147 		D(bug("Added CD-ROM drive: %s", drive));
148 	}
149 }
150 
151 #ifdef USE_MNTENT
CheckMounts(const char * mtab)152 void CdromDriverLinux::CheckMounts(const char *mtab)
153 {
154 	FILE *mntfp;
155 	struct mntent *mntent;
156 	struct stat stbuf;
157 
158 	mntfp = setmntent(mtab, "r");
159 	if ( mntfp != NULL ) {
160 		char *tmp;
161 		char *mnt_type;
162 		size_t mnt_type_len;
163 		char *mnt_dev;
164 		size_t mnt_dev_len;
165 
166 		while ( (mntent=getmntent(mntfp)) != NULL ) {
167 			mnt_type_len = strlen(mntent->mnt_type) + 1;
168 			mnt_type = (char *)malloc(mnt_type_len);
169 			if (mnt_type == NULL)
170 				continue;  /* maybe you'll get lucky next time. */
171 
172 			mnt_dev_len = strlen(mntent->mnt_fsname) + 1;
173 			mnt_dev = (char *)malloc(mnt_dev_len);
174 			if (mnt_dev == NULL) {
175 				free(mnt_type);
176 				continue;
177 			}
178 
179 			strcpy(mnt_type, mntent->mnt_type);
180 			strcpy(mnt_dev, mntent->mnt_fsname);
181 
182 			/* Handle "supermount" filesystem mounts */
183 			if ( strcmp(mnt_type, MNTTYPE_SUPER) == 0 ) {
184 				tmp = strstr(mntent->mnt_opts, "fs=");
185 				if ( tmp ) {
186 					free(mnt_type);
187 					mnt_type = strdup(tmp + strlen("fs="));
188 					if ( mnt_type ) {
189 						tmp = strchr(mnt_type, ',');
190 						if ( tmp ) {
191 							*tmp = '\0';
192 						}
193 					}
194 				}
195 				tmp = strstr(mntent->mnt_opts, "dev=");
196 				if ( tmp ) {
197 					free(mnt_dev);
198 					mnt_dev = strdup(tmp + strlen("dev="));
199 					if ( mnt_dev ) {
200 						tmp = strchr(mnt_dev, ',');
201 						if ( tmp ) {
202 							*tmp = '\0';
203 						}
204 					}
205 				}
206 			}
207 			if ( strcmp(mnt_type, MNTTYPE_CDROM) == 0 ) {
208 				if (CheckDrive(mnt_dev, mnt_type, &stbuf) > 0) {
209 					AddDrive(mnt_dev, &stbuf);
210 				}
211 			}
212 			free(mnt_dev);
213 			free(mnt_type);
214 		}
215 		endmntent(mntfp);
216 	}
217 }
218 #endif /* USE_MNTENT */
219 
220 /*--- Public functions ---*/
221 
CdromDriverLinux()222 CdromDriverLinux::CdromDriverLinux()
223 {
224 	int i;
225 
226 	D(bug(NFCD_NAME "CdromDriverLinux()"));
227 	for (i=0; i<CD_MAX_DRIVES; i++) {
228 		cddrives[i].handle=-1;
229 		cddrives[i].device = NULL;
230 	}
231 	drives_scanned = false;
232 	numcds = 0;
233 }
234 
~CdromDriverLinux()235 CdromDriverLinux::~CdromDriverLinux()
236 {
237 	int i;
238 
239 	D(bug(NFCD_NAME "~CdromDriverLinux()"));
240 	for (i = 0; i < CD_MAX_DRIVES; i++)
241 	{
242 		CloseDrive(i);
243 		free(cddrives[i].device);
244 		cddrives[i].device = NULL;
245 	}
246 	drives_scanned = false;
247 }
248 
Count()249 int CdromDriverLinux::Count()
250 {
251 	if (!drives_scanned)
252 	{
253 		(void) DeviceName(0);
254 	}
255 	return numcds;
256 }
257 
DeviceName(int drive)258 const char *CdromDriverLinux::DeviceName(int drive)
259 {
260 	if (!drives_scanned)
261 	{
262 		/* checklist: /dev/cdrom, /dev/hd?, /dev/scd? /dev/sr? */
263 		static const char *const checklist[] = {
264 			"cdrom", "?a hd?", "?0 scd?", "?0 sr?", NULL
265 		};
266 		struct stat stbuf;
267 
268 #ifdef USE_MNTENT
269 		/* Check /dev/cdrom first :-) */
270 		if (CheckDrive("/dev/cdrom", NULL, &stbuf) > 0) {
271 			AddDrive("/dev/cdrom", &stbuf);
272 		}
273 
274 		/* Now check the currently mounted CD drives */
275 		CheckMounts(_PATH_MOUNTED);
276 
277 		/* Finally check possible mountable drives in /etc/fstab */
278 		CheckMounts(_PATH_MNTTAB);
279 
280 		/* If we found our drives, there's nothing left to do */
281 #endif /* USE_MNTENT */
282 		if ( numcds == 0 )
283 		{
284 			char drive[32];
285 			int i, j, exists;
286 
287 			/* Scan the system for CD-ROM drives.
288 			   Not always 100% reliable, so use the USE_MNTENT code above first.
289 			 */
290 			for ( i=0; checklist[i]; ++i ) {
291 				if ( checklist[i][0] == '?' ) {
292 					char *insert;
293 					exists = 1;
294 					for ( j=checklist[i][1]; exists; ++j ) {
295 						sprintf(drive, "/dev/%s", &checklist[i][3]);
296 						insert = strchr(drive, '?');
297 						if ( insert != NULL ) {
298 							*insert = j;
299 						}
300 						switch (CheckDrive(drive, NULL, &stbuf)) {
301 							/* Drive exists and is a CD-ROM */
302 							case 1:
303 								AddDrive(drive, &stbuf);
304 								break;
305 							/* Drive exists, but isn't a CD-ROM */
306 							case 0:
307 								break;
308 							/* Drive doesn't exist */
309 							case -1:
310 								exists = 0;
311 								break;
312 						}
313 					}
314 				} else {
315 					sprintf(drive, "/dev/%s", checklist[i]);
316 					if ( CheckDrive(drive, NULL, &stbuf) > 0 ) {
317 						AddDrive(drive, &stbuf);
318 					}
319 				}
320 			}
321 		}
322 		drives_scanned = true;
323 	}
324 	return cddrives[drive].device;
325 }
326 
327 /*--- Private functions ---*/
328 
OpenDrive(memptr device)329 int CdromDriverLinux::OpenDrive(memptr device)
330 {
331 	int drive;
332 
333 	drive = GetDrive(device);
334 	drive = DriveFromLetter(drive);
335 
336 	/* Drive exist ? */
337 	if (drive < 0 || drive >= CD_MAX_DRIVES || (drives_mask & (1<<drive)) == 0 ||
338 		DeviceName(drive = bx_options.nfcdroms[drive].physdevtohostdev) == NULL)
339 	{
340 		D(bug(NFCD_NAME " physical device %c does not exist", GetDrive(device)));
341 		return TOS_EUNDEV;
342 	}
343 
344 	/* Drive opened ? */
345 	if (cddrives[drive].handle>=0) {
346 		return drive;
347 	}
348 
349 	/* Open drive */
350 	cddrives[drive].handle=open(DeviceName(drive), O_RDONLY|O_EXCL|O_NONBLOCK, 0);
351 	if (cddrives[drive].handle<0) {
352 		cddrives[drive].handle=-1;
353 		int errorcode = errnoHost2Mint(errno, TOS_EFILNF);
354 		D(bug(NFCD_NAME " error opening drive %s: %s", DeviceName(drive), strerror(errno)));
355 		return errorcode;
356 	}
357 
358 	return drive;
359 }
360 
CloseDrive(int drive)361 void CdromDriverLinux::CloseDrive(int drive)
362 {
363 	/* Drive already closed ? */
364 	if (cddrives[drive].handle<0) {
365 		return;
366 	}
367 
368 	close(cddrives[drive].handle);
369 	cddrives[drive].handle=-1;
370 }
371 
cd_unixioctl(int drive,int request,void * buffer)372 int CdromDriverLinux::cd_unixioctl(int drive, int request, void *buffer)
373 {
374 	int errorcode = ioctl(cddrives[drive].handle, request, buffer);
375 	if (errorcode >= 0)
376 		return errorcode;
377 	return errnoHost2Mint(errno, TOS_EDRVNR);
378 }
379 
cd_read(memptr device,memptr buffer,uint32 first,uint32 length)380 int32 CdromDriverLinux::cd_read(memptr device, memptr buffer, uint32 first, uint32 length)
381 {
382 	int drive;
383 
384 	drive = OpenDrive(device);
385 	if (drive<0) {
386 		return drive;
387 	}
388 
389 	D(bug(NFCD_NAME "Read(%d,%d)", first, length));
390 
391 	if (lseek(cddrives[drive].handle, (off_t)first * CD_FRAMESIZE, SEEK_SET)<0) {
392 		D(bug(NFCD_NAME "Read(): can not seek to block %d", first));
393 		int errorcode = errnoHost2Mint(errno, TOS_ENOSYS);
394 		CloseDrive(drive);
395 		return errorcode;
396 	}
397 
398 	if (read(cddrives[drive].handle, Atari2HostAddr(buffer), length * CD_FRAMESIZE)<0) {
399 		int errorcode = errnoHost2Mint(errno, TOS_ENOSYS);
400 		D(bug(NFCD_NAME "Read(): can not read %d blocks", length));
401 		CloseDrive(drive);
402 		return errorcode;
403 	}
404 
405 	CloseDrive(drive);
406 	return TOS_E_OK;
407 }
408 
cd_status(memptr device,memptr ext_status)409 int32 CdromDriverLinux::cd_status(memptr device, memptr ext_status)
410 {
411 	UNUSED(ext_status);
412 	int drive, errorcode, mediachanged;
413 	unsigned long status;
414 
415 	drive = OpenDrive(device);
416 	if (drive<0) {
417 		return drive;
418 	}
419 
420 	status = 0;
421 	errorcode=cd_unixioctl(drive, CDROM_MEDIA_CHANGED, &status);
422 	D(bug(NFCD_NAME "Status(CDROM_MEDIA_CHANGED): errorcode=0x%08x", errorcode));
423 	if (errorcode<0) {
424 		CloseDrive(drive);
425 		return errorcode;
426 	}
427 	mediachanged = (errorcode==1);
428 
429 	status = 0;
430 	errorcode=cd_unixioctl(drive, CDROM_DRIVE_STATUS, &status);
431 	D(bug(NFCD_NAME "Status(CDROM_DRIVE_STATUS): errorcode=0x%08x", errorcode));
432 	if (errorcode<0) {
433 		CloseDrive(drive);
434 		return errorcode;
435 	}
436 	if (errorcode == CDS_DRIVE_NOT_READY) {
437 		CloseDrive(drive);
438 		return TOS_EDRVNR;
439 	}
440 
441 	CloseDrive(drive);
442 	return (mediachanged<<3);
443 }
444 
cd_ioctl(memptr device,uint16 opcode,memptr buffer)445 int32 CdromDriverLinux::cd_ioctl(memptr device, uint16 opcode, memptr buffer)
446 {
447 	int drive, errorcode = TOS_ENOSYS;
448 
449 	drive = OpenDrive(device);
450 	if (drive<0) {
451 		return drive;
452 	}
453 
454 	switch(opcode) {
455 		case ATARI_CDROMREADOFFSET:
456 			{
457 				struct cdrom_multisession cd_ms;
458 				Uint32 *lba = (Uint32 *)Atari2HostAddr(buffer);
459 				D(bug(NFCD_NAME " Ioctl(CDROMREADOFFSET)"));
460 				cd_ms.xa_flag = 1;
461 				cd_ms.addr_format = CDROM_LBA;
462 				errorcode = cd_unixioctl(drive, CDROMMULTISESSION, &cd_ms);
463 				if (errorcode >= 0)
464 				{
465 					if (cd_ms.addr_format == CDROM_LBA)
466 						*lba = SDL_SwapBE32(cd_ms.addr.lba);
467 					else
468 						*lba = SDL_SwapBE32(MSF_TO_FRAMES(cd_ms.addr.msf.minute, cd_ms.addr.msf.second, cd_ms.addr.msf.frame));
469 				}
470 			}
471 			break;
472 
473 		case ATARI_CDROMPAUSE:
474 			D(bug(NFCD_NAME " Ioctl(CDROMPAUSE)"));
475 			errorcode = cd_unixioctl(drive, CDROMPAUSE, 0l);
476 			break;
477 
478 		case ATARI_CDROMRESUME:
479 			D(bug(NFCD_NAME " Ioctl(CDROMRESUME)"));
480 			errorcode = cd_unixioctl(drive, CDROMRESUME, 0l);
481 			break;
482 
483 		case ATARI_CDROMPLAYMSF:
484 			{
485 				struct cdrom_msf cd_msf;
486 				atari_cdrom_msf_t *atari_msf;
487 
488 				atari_msf = (atari_cdrom_msf_t *) Atari2HostAddr(buffer);
489 				cd_msf.cdmsf_min0 = atari_msf->cdmsf_min0;
490 				cd_msf.cdmsf_sec0 = atari_msf->cdmsf_sec0;
491 				cd_msf.cdmsf_frame0 = atari_msf->cdmsf_frame0;
492 				cd_msf.cdmsf_min1 = atari_msf->cdmsf_min1;
493 				cd_msf.cdmsf_sec1 = atari_msf->cdmsf_sec1;
494 				cd_msf.cdmsf_frame1 = atari_msf->cdmsf_frame1;
495 
496 				D(bug(NFCD_NAME " Ioctl(CDROMPLAYMSF,%02d:%02d:%02d,%02d:%02d:%02d)",
497 					cd_msf.cdmsf_min0, cd_msf.cdmsf_sec0, cd_msf.cdmsf_frame0,
498 					cd_msf.cdmsf_min1, cd_msf.cdmsf_sec1, cd_msf.cdmsf_frame1
499 				));
500 
501 				errorcode=cd_unixioctl(drive, CDROMPLAYMSF, &cd_msf);
502 			}
503 			break;
504 
505 		case ATARI_CDROMPLAYTRKIND:
506 			{
507 				struct cdrom_ti cd_ti;
508 				atari_cdrom_ti *atari_ti;
509 
510 				atari_ti = (atari_cdrom_ti *) Atari2HostAddr(buffer);
511 				cd_ti.cdti_trk0 = atari_ti->cdti_trk0;
512 				cd_ti.cdti_ind0 = atari_ti->cdti_ind0;
513 				cd_ti.cdti_trk1 = atari_ti->cdti_trk1;
514 				cd_ti.cdti_ind1 = atari_ti->cdti_ind1;
515 
516 				D(bug(NFCD_NAME " Ioctl(CDROMPLAYTRKIND,%d.%d,%d.%d)",
517 					cd_ti.cdti_trk0, cd_ti.cdti_ind0,
518 					cd_ti.cdti_trk1, cd_ti.cdti_trk1
519 				));
520 
521 				errorcode=cd_unixioctl(drive, CDROMPLAYTRKIND, &cd_ti);
522 			}
523 			break;
524 
525 		case ATARI_CDROMREADTOCHDR:
526 			{
527 				struct cdrom_tochdr tochdr;
528 				atari_cdromtochdr_t *atari_tochdr;
529 
530 				atari_tochdr = (atari_cdromtochdr_t *)  Atari2HostAddr(buffer);
531 				D(bug(NFCD_NAME " Ioctl(CDROMREADTOCHDR)"));
532 				errorcode = cd_unixioctl(drive, CDROMREADTOCHDR, &tochdr);
533 				if (errorcode >= 0)
534 				{
535 					atari_tochdr->cdth_trk0 = tochdr.cdth_trk0;
536 					atari_tochdr->cdth_trk1 = tochdr.cdth_trk1;
537 				}
538 			}
539 			break;
540 
541 		case ATARI_CDROMREADTOCENTRY:
542 			{
543 				struct cdrom_tocentry tocentry;
544 				atari_cdromtocentry_t *atari_tocentry;
545 
546 				atari_tocentry = (atari_cdromtocentry_t *)  Atari2HostAddr(buffer);
547 				tocentry.cdte_track = atari_tocentry->cdte_track;
548 				tocentry.cdte_format = atari_tocentry->cdte_format;
549 
550 				D(bug(NFCD_NAME " Ioctl(CDROMREADTOCENTRY,0x%02x,0x%02x)", tocentry.cdte_track, tocentry.cdte_format));
551 				errorcode=cd_unixioctl(drive, CDROMREADTOCENTRY, &tocentry);
552 
553 				if (errorcode>=0) {
554 					atari_tocentry->cdte_track = tocentry.cdte_track;
555 					atari_tocentry->cdte_format = tocentry.cdte_format;
556 					atari_tocentry->cdte_info = (tocentry.cdte_adr & 0x0f)<<4;
557 					atari_tocentry->cdte_info |= tocentry.cdte_ctrl & 0x0f;
558 					atari_tocentry->cdte_datamode = tocentry.cdte_datamode;
559 					atari_tocentry->dummy = 0;
560 
561 					if (tocentry.cdte_format == CDROM_LBA) {
562 						atari_tocentry->cdte_addr = SDL_SwapBE32(tocentry.cdte_addr.lba);
563 					} else {
564 						atari_tocentry->cdte_addr = SDL_SwapBE32(((Uint32)tocentry.cdte_addr.msf.minute<<16) | ((Uint32)tocentry.cdte_addr.msf.second<<8) | (Uint32)tocentry.cdte_addr.msf.frame);
565 					}
566 				}
567 			}
568 			break;
569 
570 		case ATARI_CDROMSTOP:
571 			D(bug(NFCD_NAME " Ioctl(CDROMSTOP)"));
572 			errorcode = cd_unixioctl(drive, CDROMSTOP, 0l);
573 			break;
574 
575 		case ATARI_CDROMSTART:
576 			D(bug(NFCD_NAME " Ioctl(CDROMSTART)"));
577 			errorcode = cd_unixioctl(drive, CDROMSTART, 0l);
578 			break;
579 
580 		case ATARI_CDROMEJECT:
581 			D(bug(NFCD_NAME " Ioctl(CDROMEJECT)"));
582 			errorcode=cd_unixioctl(drive, buffer != 0 ? CDROMCLOSETRAY : CDROMEJECT, (void *)0);
583 			break;
584 
585 		case ATARI_CDROMVOLCTRL:
586 			{
587 				struct cdrom_volctrl volctrl;
588 				struct atari_cdrom_volctrl *v = (struct atari_cdrom_volctrl *) Atari2HostAddr(buffer);
589 
590 				D(bug(NFCD_NAME " Ioctl(CDROMVOLCTRL)"));
591 
592 				/* Write volume settings */
593 				volctrl.channel0 = v->channel0;
594 				volctrl.channel1 = v->channel1;
595 				volctrl.channel2 = v->channel2;
596 				volctrl.channel3 = v->channel3;
597 
598 				errorcode=cd_unixioctl(drive, CDROMVOLCTRL, &volctrl);
599 			}
600 			break;
601 
602 		case ATARI_CDROMAUDIOCTRL:
603 			{
604 				struct cdrom_volctrl volctrl;
605 				atari_cdrom_audioctrl_t *atari_audioctrl;
606 				atari_audioctrl = (atari_cdrom_audioctrl_t *) Atari2HostAddr(buffer);
607 
608 				D(bug(NFCD_NAME " Ioctl(CDROMAUDIOCTRL,0x%04x)", atari_audioctrl->set));
609 
610 				if (atari_audioctrl->set == 0) {
611 					/* Read volume settings */
612 					errorcode=cd_unixioctl(drive, CDROMVOLREAD, &volctrl);
613 					if (errorcode>=0) {
614 						atari_audioctrl->channel[0].selection =
615 							atari_audioctrl->channel[1].selection =
616 							atari_audioctrl->channel[2].selection =
617 							atari_audioctrl->channel[3].selection = 0;
618 						atari_audioctrl->channel[0].volume = volctrl.channel0;
619 						atari_audioctrl->channel[1].volume = volctrl.channel1;
620 						atari_audioctrl->channel[2].volume = volctrl.channel2;
621 						atari_audioctrl->channel[3].volume = volctrl.channel3;
622 					}
623 				} else {
624 					/* Write volume settings */
625 					volctrl.channel0 = atari_audioctrl->channel[0].volume;
626 					volctrl.channel1 = atari_audioctrl->channel[1].volume;
627 					volctrl.channel2 = atari_audioctrl->channel[2].volume;
628 					volctrl.channel3 = atari_audioctrl->channel[3].volume;
629 
630 					errorcode=cd_unixioctl(drive, CDROMVOLCTRL, &volctrl);
631 				}
632 			}
633 			break;
634 
635 		case ATARI_CDROMSUBCHNL:
636 			{
637 				/* Structure is different between Atari and Linux */
638 				struct cdrom_subchnl subchnl;
639 				atari_cdromsubchnl_t *atari_subchnl;
640 
641 				atari_subchnl = (atari_cdromsubchnl_t *) Atari2HostAddr(buffer);
642 
643 				subchnl.cdsc_format = atari_subchnl->cdsc_format;
644 
645 				D(bug(NFCD_NAME " Ioctl(READSUBCHNL,0x%02x)", atari_subchnl->cdsc_format));
646 
647 				errorcode=cd_unixioctl(drive, CDROMSUBCHNL, &subchnl);
648 
649 				if (errorcode>=0) {
650 					atari_subchnl->cdsc_format = subchnl.cdsc_format;
651 					atari_subchnl->cdsc_audiostatus = subchnl.cdsc_audiostatus;
652 					atari_subchnl->cdsc_resvd = 0;
653 					atari_subchnl->cdsc_info = (subchnl.cdsc_adr & 0x0f)<<4;
654 					atari_subchnl->cdsc_info |= subchnl.cdsc_ctrl & 0x0f;
655 					atari_subchnl->cdsc_trk = subchnl.cdsc_trk;
656 					atari_subchnl->cdsc_ind = subchnl.cdsc_ind;
657 
658 					if (subchnl.cdsc_format == CDROM_LBA) {
659 						atari_subchnl->cdsc_absaddr = SDL_SwapBE32(subchnl.cdsc_absaddr.lba);
660 						atari_subchnl->cdsc_reladdr = SDL_SwapBE32(subchnl.cdsc_reladdr.lba);
661 					} else {
662 						atari_subchnl->cdsc_absaddr = SDL_SwapBE32(subchnl.cdsc_absaddr.msf.minute<<16);
663 						atari_subchnl->cdsc_absaddr |= SDL_SwapBE32(subchnl.cdsc_absaddr.msf.second<<8);
664 						atari_subchnl->cdsc_absaddr |= SDL_SwapBE32(subchnl.cdsc_absaddr.msf.frame);
665 
666 						atari_subchnl->cdsc_reladdr = SDL_SwapBE32(subchnl.cdsc_reladdr.msf.minute<<16);
667 						atari_subchnl->cdsc_reladdr |= SDL_SwapBE32(subchnl.cdsc_reladdr.msf.second<<8);
668 						atari_subchnl->cdsc_reladdr |= SDL_SwapBE32(subchnl.cdsc_reladdr.msf.frame);
669 					}
670 				}
671 			}
672 			break;
673 
674 		case ATARI_CDROMREADMODE2:
675 		case ATARI_CDROMREADMODE1:
676 			{
677 				struct cdrom_read cd_read;
678 				atari_cdrom_read_t *atari_cdread;
679 
680 				atari_cdread = (atari_cdrom_read_t *) Atari2HostAddr(buffer);
681 				cd_read.cdread_lba = SDL_SwapBE32(atari_cdread->cdread_lba);
682 				cd_read.cdread_bufaddr = (char *)Atari2HostAddr(SDL_SwapBE32(atari_cdread->cdread_bufaddr));
683 				cd_read.cdread_buflen = SDL_SwapBE32(atari_cdread->cdread_buflen);
684 
685 				D(bug(NFCD_NAME " Ioctl(%s)", opcode == ATARI_CDROMREADMODE1 ? "CDROMREADMODE1" : "CDROMREADMODE2"));
686 				errorcode=cd_unixioctl(drive, opcode == ATARI_CDROMREADMODE1 ? CDROMREADMODE1 : CDROMREADMODE2, &cd_read);
687 			}
688 			break;
689 
690 		case ATARI_CDROMPREVENTREMOVAL:
691 			D(bug(NFCD_NAME " Ioctl(CDROMPREVENTREMOVAL)"));
692 			errorcode=cd_unixioctl(drive, CDROM_LOCKDOOR, (void *)1);
693 			break;
694 
695 		case ATARI_CDROMALLOWREMOVAL:
696 			D(bug(NFCD_NAME " Ioctl(CDROMALLOWREMOVAL)"));
697 			errorcode=cd_unixioctl(drive, CDROM_LOCKDOOR, (void *)0);
698 			break;
699 
700 		case ATARI_CDROMREADDA:
701 			{
702 				struct cdrom_msf cd_msf;
703 				atari_cdrom_msf_t *atari_msf;
704 
705 				atari_msf = (atari_cdrom_msf_t *) Atari2HostAddr(buffer);
706 				cd_msf.cdmsf_min0 = atari_msf->cdmsf_min0;
707 				cd_msf.cdmsf_sec0 = atari_msf->cdmsf_sec0;
708 				cd_msf.cdmsf_frame0 = atari_msf->cdmsf_frame0;
709 				cd_msf.cdmsf_min1 = atari_msf->cdmsf_min1;
710 				cd_msf.cdmsf_sec1 = atari_msf->cdmsf_sec1;
711 				cd_msf.cdmsf_frame1 = atari_msf->cdmsf_frame1;
712 				D(bug(NFCD_NAME " Ioctl(CDROMREADDA)"));
713 				errorcode=cd_unixioctl(drive, CDROMREADRAW, &cd_msf);
714 			}
715 			break;
716 
717 		case ATARI_CDROMRESET:
718 			D(bug(NFCD_NAME " Ioctl(CDROMRESET)"));
719 			break;
720 
721 		case ATARI_CDROMGETMCN:
722 			{
723 				atari_mcn_t	*atari_mcn;
724 				cdrom_mcn mcn;
725 
726 				atari_mcn = (atari_mcn_t *) Atari2HostAddr(buffer);
727 				memset(atari_mcn, 0, sizeof(atari_mcn_t));
728 
729 				D(bug(NFCD_NAME " Ioctl(CDROMGETMCN)"));
730 				errorcode=cd_unixioctl(drive, CDROM_GET_MCN, &mcn);
731 				if (errorcode >= 0)
732 					Host2AtariSafeStrncpy(buffer + offsetof(atari_mcn_t, mcn), (const char *)mcn.medium_catalog_number, MIN(sizeof(atari_mcn->mcn), sizeof(mcn.medium_catalog_number)));
733 			}
734 			break;
735 
736 		case ATARI_CDROMGETTISRC:
737 			D(bug(NFCD_NAME " Ioctl(CDROMGETTISRC) (NI)"));
738 			break;
739 
740 		default:
741 			D(bug(NFCD_NAME " Ioctl(0x%04x) (NI)", opcode));
742 			break;
743 	}
744 	CloseDrive(drive);
745 	return errorcode;
746 }
747 
cd_startaudio(memptr device,uint32 dummy,memptr buffer)748 int32 CdromDriverLinux::cd_startaudio(memptr device, uint32 dummy, memptr buffer)
749 {
750 	UNUSED(dummy);
751 	int drive, errorcode;
752 	struct cdrom_ti	track_index;
753 	metados_bos_tracks_t	*atari_track_index;
754 
755 	drive = OpenDrive(device);
756 	if (drive<0) {
757 		return drive;
758 	}
759 
760 	atari_track_index = (metados_bos_tracks_t *) Atari2HostAddr(buffer);
761 	track_index.cdti_trk0 = atari_track_index->first;
762 	track_index.cdti_ind0 = 1;
763 	track_index.cdti_trk1 = atari_track_index->first + atari_track_index->count -1;
764 	track_index.cdti_ind0 = 99;
765 
766 	errorcode=cd_unixioctl(drive, CDROMPLAYTRKIND, &track_index);
767 	CloseDrive(drive);
768 	return errorcode;
769 }
770 
cd_stopaudio(memptr device)771 int32 CdromDriverLinux::cd_stopaudio(memptr device)
772 {
773 	int drive, errorcode;
774 
775 	drive = OpenDrive(device);
776 	if (drive<0) {
777 		return drive;
778 	}
779 
780 	errorcode=cd_unixioctl(drive, CDROMSTOP, NULL);
781 	CloseDrive(drive);
782 	return errorcode;
783 }
784 
cd_setsongtime(memptr device,uint32 dummy,uint32 start_msf,uint32 end_msf)785 int32 CdromDriverLinux::cd_setsongtime(memptr device, uint32 dummy, uint32 start_msf, uint32 end_msf)
786 {
787 	UNUSED(dummy);
788 	int drive, errorcode;
789 	struct cdrom_msf audio_bloc;
790 
791 	drive = OpenDrive(device);
792 	if (drive<0) {
793 		return drive;
794 	}
795 
796 	audio_bloc.cdmsf_min0 = (start_msf>>16) & 0xff;
797 	audio_bloc.cdmsf_sec0 = (start_msf>>8) & 0xff;
798 	audio_bloc.cdmsf_frame0 = (start_msf>>0) & 0xff;
799 	D(bug(NFCD_NAME " start: %02d:%02d:%02d", (start_msf>>16) & 0xff, (start_msf>>8) & 0xff, start_msf & 0xff));
800 
801 	audio_bloc.cdmsf_min1 = (end_msf>>16) & 0xff;
802 	audio_bloc.cdmsf_sec1 = (end_msf>>8) & 0xff;
803 	audio_bloc.cdmsf_frame1 = (end_msf>>0) & 0xff;
804 	D(bug(NFCD_NAME " end:   %02d:%02d:%02d", (end_msf>>16) & 0xff, (end_msf>>8) & 0xff, end_msf & 0xff));
805 
806 	errorcode=cd_unixioctl(drive, CDROMPLAYMSF, &audio_bloc);
807 	CloseDrive(drive);
808 	return errorcode;
809 }
810 
cd_gettoc(memptr device,uint32 dummy,memptr buffer)811 int32 CdromDriverLinux::cd_gettoc(memptr device, uint32 dummy, memptr buffer)
812 {
813 	UNUSED(dummy);
814 	int drive, i, numtracks, errorcode;
815 	struct cdrom_tochdr tochdr;
816 	struct cdrom_tocentry tocentry;
817 	atari_tocentry_t *atari_tocentry;
818 
819 	drive = OpenDrive(device);
820 	if (drive<0) {
821 		return drive;
822 	}
823 
824 	/* Read TOC header */
825 	errorcode=cd_unixioctl(drive, CDROMREADTOCHDR, &tochdr);
826 	if (errorcode<0) {
827 		CloseDrive(drive);
828 		return errorcode;
829 	}
830 
831 	D(bug(NFCD_NAME "GetToc():  TOC header read"));
832 
833 	numtracks = tochdr.cdth_trk1-tochdr.cdth_trk0+1;
834 
835 	/* Read TOC entries */
836 	atari_tocentry = (atari_tocentry_t *) Atari2HostAddr(buffer);
837 	for (i=0; i<=numtracks; i++) {
838 		D(bug(NFCD_NAME "GetToc():  reading TOC entry for track %d", i));
839 
840 		tocentry.cdte_track = tochdr.cdth_trk0+i;
841 		if (i == numtracks) {
842 			tocentry.cdte_track = CDROM_LEADOUT;
843 		}
844 		tocentry.cdte_format = CDROM_MSF;
845 
846 		errorcode = cd_unixioctl(drive, CDROMREADTOCENTRY, &tocentry);
847 		if (errorcode<0) {
848 			CloseDrive(drive);
849 			return errorcode;
850 		}
851 
852 		atari_tocentry[i].track = tocentry.cdte_track;
853 		atari_tocentry[i].minute = BinaryToBcd(tocentry.cdte_addr.msf.minute);
854 		atari_tocentry[i].second = BinaryToBcd(tocentry.cdte_addr.msf.second);
855 		atari_tocentry[i].frame = BinaryToBcd(tocentry.cdte_addr.msf.frame);
856 		if (tocentry.cdte_track == CDROM_LEADOUT) {
857 			atari_tocentry[i].track = CDROM_LEADOUT_CDAR;
858 		}
859 
860 		D(bug(NFCD_NAME "GetToc():   track %d, id 0x%02x, %s",
861 			i, tocentry.cdte_track,
862 			tocentry.cdte_ctrl & CDROM_DATA_TRACK ? "data" : "audio"
863 		));
864 
865 		if (tocentry.cdte_format == CDROM_MSF) {
866 			D(bug(NFCD_NAME "GetToc():    msf %02d:%02d:%02d, bcd: %02x:%02x:%02x",
867 				tocentry.cdte_addr.msf.minute,
868 				tocentry.cdte_addr.msf.second,
869 				tocentry.cdte_addr.msf.frame,
870 				atari_tocentry[i].minute,
871 				atari_tocentry[i].second,
872 				atari_tocentry[i].frame
873 			));
874 		} else {
875 			D(bug(NFCD_NAME "GetToc():    lba 0x%08x", tocentry.cdte_addr.lba));
876 		}
877 	}
878 
879 	atari_tocentry[numtracks+1].track =
880 		atari_tocentry[numtracks+1].minute =
881 		atari_tocentry[numtracks+1].second =
882 		atari_tocentry[numtracks+1].frame = 0;
883 
884 	CloseDrive(drive);
885 	return TOS_E_OK;
886 }
887 
cd_discinfo(memptr device,memptr buffer)888 int32 CdromDriverLinux::cd_discinfo(memptr device, memptr buffer)
889 {
890 	int drive, errorcode;
891 	struct cdrom_tochdr tochdr;
892 	struct cdrom_subchnl subchnl;
893 	struct cdrom_tocentry tocentry;
894 	atari_discinfo_t	*discinfo;
895 
896 	drive = OpenDrive(device);
897 	if (drive<0) {
898 		return drive;
899 	}
900 
901 	/* Read TOC header */
902 	errorcode=cd_unixioctl(drive, CDROMREADTOCHDR, &tochdr);
903 	if (errorcode<0) {
904 		CloseDrive(drive);
905 		return errorcode;
906 	}
907 	D(bug(NFCD_NAME "DiscInfo():  TOC header read"));
908 
909 	discinfo = (atari_discinfo_t *) Atari2HostAddr(buffer);
910 	memset(discinfo, 0, sizeof(atari_discinfo_t));
911 
912 	discinfo->first = discinfo->current = tochdr.cdth_trk0;
913 	discinfo->last = tochdr.cdth_trk1;
914 	discinfo->index = 1;
915 
916 	/* Read subchannel */
917 	subchnl.cdsc_format = CDROM_MSF;
918 	errorcode=cd_unixioctl(drive, CDROMSUBCHNL, &subchnl);
919 	if (errorcode<0) {
920 		CloseDrive(drive);
921 		return errorcode;
922 	}
923 	D(bug(NFCD_NAME "DiscInfo():  Subchannel read"));
924 
925 	discinfo->current = subchnl.cdsc_trk;	/* current track */
926 	discinfo->index = subchnl.cdsc_ind;	/* current index */
927 
928 	discinfo->relative.track = 0;
929 	discinfo->relative.minute = BinaryToBcd(subchnl.cdsc_reladdr.msf.minute);
930 	discinfo->relative.second = BinaryToBcd(subchnl.cdsc_reladdr.msf.second);
931 	discinfo->relative.frame = BinaryToBcd(subchnl.cdsc_reladdr.msf.frame);
932 
933 	discinfo->absolute.track = 0;
934 	discinfo->absolute.minute = BinaryToBcd(subchnl.cdsc_absaddr.msf.minute);
935 	discinfo->absolute.second = BinaryToBcd(subchnl.cdsc_absaddr.msf.second);
936 	discinfo->absolute.frame = BinaryToBcd(subchnl.cdsc_absaddr.msf.frame);
937 
938 	/* Read toc entry for start of disc, to select disc type */
939 	tocentry.cdte_track = tochdr.cdth_trk0;
940 	tocentry.cdte_format = CDROM_MSF;
941 
942 	errorcode = cd_unixioctl(drive, CDROMREADTOCENTRY, &tocentry);
943 	if (errorcode<0) {
944 		CloseDrive(drive);
945 		return errorcode;
946 	}
947 	discinfo->disctype = ((tocentry.cdte_ctrl & CDROM_DATA_TRACK) == CDROM_DATA_TRACK);
948 
949 	/* Read toc entry for end of disc */
950 	tocentry.cdte_track = CDROM_LEADOUT;
951 	tocentry.cdte_format = CDROM_MSF;
952 
953 	errorcode = cd_unixioctl(drive, CDROMREADTOCENTRY, &tocentry);
954 	if (errorcode<0) {
955 		CloseDrive(drive);
956 		return errorcode;
957 	}
958 
959 	D(bug(NFCD_NAME "DiscInfo():  Toc entry read"));
960 
961 	discinfo->end.track = 0;
962 	discinfo->end.minute = BinaryToBcd(tocentry.cdte_addr.msf.minute);
963 	discinfo->end.second = BinaryToBcd(tocentry.cdte_addr.msf.second);
964 	discinfo->end.frame = BinaryToBcd(tocentry.cdte_addr.msf.frame);
965 
966 	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",
967 		discinfo->first, discinfo->last, discinfo->current, discinfo->index,
968 		discinfo->relative.minute, discinfo->relative.second, discinfo->relative.frame,
969 		discinfo->absolute.minute, discinfo->absolute.second, discinfo->absolute.frame,
970 		discinfo->end.minute, discinfo->end.second, discinfo->end.frame));
971 
972 	CloseDrive(drive);
973 	return TOS_E_OK;
974 }
975 
976 /*
977 vim:ts=4:sw=4:
978 */
979 
980 #endif /* NFCDROM_LINUX_SUPPORT */
981