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