src/cdrom/linux/SDL_syscdrom.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 14 Dec 2001 13:13:20 +0000
changeset 254 4fc12b8edf74
parent 252 e8157fcb3114
child 297 f6ffac90895c
permissions -rw-r--r--
*** empty log message ***
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@0
     3
    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@0
     6
    modify it under the terms of the GNU Library General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@0
     8
    version 2 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@0
    13
    Library General Public License for more details.
slouken@0
    14
slouken@0
    15
    You should have received a copy of the GNU Library General Public
slouken@0
    16
    License along with this library; if not, write to the Free
slouken@0
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@0
    22
slouken@0
    23
#ifdef SAVE_RCSID
slouken@0
    24
static char rcsid =
slouken@0
    25
 "@(#) $Id$";
slouken@0
    26
#endif
slouken@0
    27
slouken@0
    28
/* Functions for system-level CD-ROM audio control */
slouken@0
    29
slouken@0
    30
#include <sys/types.h>
slouken@0
    31
#include <stdlib.h>
slouken@0
    32
#include <sys/stat.h>
slouken@0
    33
#include <sys/ioctl.h>
slouken@0
    34
#include <fcntl.h>
slouken@0
    35
#include <stdio.h>
slouken@0
    36
#include <string.h>
slouken@0
    37
#include <errno.h>
slouken@0
    38
#include <unistd.h>
slouken@0
    39
#ifdef __linux__
slouken@0
    40
#include <linux/cdrom.h>
slouken@0
    41
#endif
slouken@0
    42
#ifdef __SVR4
slouken@0
    43
#include <sys/cdio.h>
slouken@0
    44
#endif
slouken@0
    45
slouken@0
    46
/* Define this to use the alternative getmntent() code */
slouken@0
    47
#ifndef __SVR4
slouken@0
    48
#define USE_MNTENT
slouken@0
    49
#endif
slouken@0
    50
slouken@0
    51
#ifdef USE_MNTENT
slouken@0
    52
#if defined(__USLC__)
slouken@0
    53
#include <sys/mntent.h>
slouken@0
    54
#else
slouken@0
    55
#include <mntent.h>
slouken@0
    56
#endif
slouken@0
    57
slouken@0
    58
#ifndef _PATH_MNTTAB
slouken@0
    59
#ifdef MNTTAB
slouken@0
    60
#define _PATH_MNTTAB	MNTTAB
slouken@0
    61
#else
slouken@0
    62
#define _PATH_MNTTAB	"/etc/fstab"
slouken@0
    63
#endif
slouken@0
    64
#endif /* !_PATH_MNTTAB */
slouken@0
    65
slouken@0
    66
#ifndef _PATH_MOUNTED
slouken@0
    67
#define _PATH_MOUNTED	"/etc/mtab"
slouken@0
    68
#endif /* !_PATH_MOUNTED */
slouken@0
    69
slouken@0
    70
#ifndef MNTTYPE_CDROM
slouken@0
    71
#define MNTTYPE_CDROM	"iso9660"
slouken@0
    72
#endif
slouken@0
    73
#ifndef MNTTYPE_SUPER
slouken@0
    74
#define MNTTYPE_SUPER	"supermount"
slouken@0
    75
#endif
slouken@0
    76
#endif /* USE_MNTENT */
slouken@0
    77
slouken@0
    78
#include "SDL_error.h"
slouken@0
    79
#include "SDL_cdrom.h"
slouken@0
    80
#include "SDL_syscdrom.h"
slouken@0
    81
slouken@0
    82
slouken@0
    83
/* The maximum number of CD-ROM drives we'll detect */
slouken@0
    84
#define MAX_DRIVES	16	
slouken@0
    85
slouken@0
    86
/* A list of available CD-ROM drives */
slouken@0
    87
static char *SDL_cdlist[MAX_DRIVES];
slouken@0
    88
static dev_t SDL_cdmode[MAX_DRIVES];
slouken@0
    89
slouken@0
    90
/* The system-dependent CD control functions */
slouken@0
    91
static const char *SDL_SYS_CDName(int drive);
slouken@0
    92
static int SDL_SYS_CDOpen(int drive);
slouken@0
    93
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
slouken@0
    94
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
slouken@0
    95
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
slouken@0
    96
static int SDL_SYS_CDPause(SDL_CD *cdrom);
slouken@0
    97
static int SDL_SYS_CDResume(SDL_CD *cdrom);
slouken@0
    98
static int SDL_SYS_CDStop(SDL_CD *cdrom);
slouken@0
    99
static int SDL_SYS_CDEject(SDL_CD *cdrom);
slouken@0
   100
static void SDL_SYS_CDClose(SDL_CD *cdrom);
slouken@0
   101
slouken@0
   102
/* Some ioctl() errno values which occur when the tray is empty */
slouken@0
   103
#define ERRNO_TRAYEMPTY(errno)	\
slouken@0
   104
	((errno == EIO) || (errno == ENOENT) || (errno == EINVAL))
slouken@0
   105
slouken@0
   106
/* Check a drive to see if it is a CD-ROM */
slouken@0
   107
static int CheckDrive(char *drive, char *mnttype, struct stat *stbuf)
slouken@0
   108
{
slouken@0
   109
	int is_cd, cdfd;
slouken@0
   110
	struct cdrom_subchnl info;
slouken@0
   111
slouken@0
   112
	/* If it doesn't exist, return -1 */
slouken@0
   113
	if ( stat(drive, stbuf) < 0 ) {
slouken@0
   114
		return(-1);
slouken@0
   115
	}
slouken@0
   116
slouken@0
   117
	/* If it does exist, verify that it's an available CD-ROM */
slouken@0
   118
	is_cd = 0;
slouken@0
   119
	if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
slouken@0
   120
		cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
slouken@0
   121
		if ( cdfd >= 0 ) {
slouken@0
   122
			info.cdsc_format = CDROM_MSF;
slouken@0
   123
			/* Under Linux, EIO occurs when a disk is not present.
slouken@0
   124
			 */
slouken@0
   125
			if ( (ioctl(cdfd, CDROMSUBCHNL, &info) == 0) ||
slouken@0
   126
						ERRNO_TRAYEMPTY(errno) ) {
slouken@0
   127
				is_cd = 1;
slouken@0
   128
			}
slouken@0
   129
			close(cdfd);
slouken@0
   130
		}
slouken@0
   131
#ifdef USE_MNTENT
slouken@0
   132
		/* Even if we can't read it, it might be mounted */
slouken@0
   133
		else if ( mnttype && (strcmp(mnttype, MNTTYPE_CDROM) == 0) ) {
slouken@0
   134
			is_cd = 1;
slouken@0
   135
		}
slouken@0
   136
#endif
slouken@0
   137
	}
slouken@0
   138
	return(is_cd);
slouken@0
   139
}
slouken@0
   140
slouken@0
   141
/* Add a CD-ROM drive to our list of valid drives */
slouken@0
   142
static void AddDrive(char *drive, struct stat *stbuf)
slouken@0
   143
{
slouken@0
   144
	int i;
slouken@0
   145
slouken@0
   146
	if ( SDL_numcds < MAX_DRIVES ) {
slouken@0
   147
		/* Check to make sure it's not already in our list.
slouken@0
   148
	 	   This can happen when we see a drive via symbolic link.
slouken@0
   149
		 */
slouken@0
   150
		for ( i=0; i<SDL_numcds; ++i ) {
slouken@0
   151
			if ( stbuf->st_rdev == SDL_cdmode[i] ) {
slouken@0
   152
#ifdef DEBUG_CDROM
slouken@0
   153
  fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
slouken@0
   154
#endif
slouken@0
   155
				return;
slouken@0
   156
			}
slouken@0
   157
		}
slouken@0
   158
slouken@0
   159
		/* Add this drive to our list */
slouken@0
   160
		i = SDL_numcds;
slouken@0
   161
		SDL_cdlist[i] = (char *)malloc(strlen(drive)+1);
slouken@0
   162
		if ( SDL_cdlist[i] == NULL ) {
slouken@0
   163
			SDL_OutOfMemory();
slouken@0
   164
			return;
slouken@0
   165
		}
slouken@0
   166
		strcpy(SDL_cdlist[i], drive);
slouken@0
   167
		SDL_cdmode[i] = stbuf->st_rdev;
slouken@0
   168
		++SDL_numcds;
slouken@0
   169
#ifdef DEBUG_CDROM
slouken@0
   170
  fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
slouken@0
   171
#endif
slouken@0
   172
	}
slouken@0
   173
}
slouken@0
   174
slouken@0
   175
#ifdef USE_MNTENT
slouken@0
   176
static void CheckMounts(const char *mtab)
slouken@0
   177
{
slouken@0
   178
	FILE *mntfp;
slouken@0
   179
	struct mntent *mntent;
slouken@0
   180
	struct stat stbuf;
slouken@0
   181
slouken@0
   182
	mntfp = setmntent(mtab, "r");
slouken@0
   183
	if ( mntfp != NULL ) {
slouken@139
   184
		char *tmp;
slouken@139
   185
		char *mnt_type;
slouken@139
   186
		char *mnt_dev;
slouken@0
   187
slouken@0
   188
		while ( (mntent=getmntent(mntfp)) != NULL ) {
slouken@139
   189
			mnt_type = malloc(strlen(mntent->mnt_type) + 1);
slouken@139
   190
			if (mnt_type == NULL)
slouken@139
   191
				continue;  /* maybe you'll get lucky next time. */
slouken@139
   192
slouken@139
   193
			mnt_dev = malloc(strlen(mntent->mnt_fsname) + 1);
slouken@139
   194
			if (mnt_dev == NULL) {
slouken@139
   195
				free(mnt_type);
slouken@139
   196
				continue;
slouken@139
   197
			}
slouken@139
   198
slouken@0
   199
			strcpy(mnt_type, mntent->mnt_type);
slouken@0
   200
			strcpy(mnt_dev, mntent->mnt_fsname);
slouken@0
   201
slouken@0
   202
			/* Handle "supermount" filesystem mounts */
slouken@0
   203
			if ( strcmp(mnt_type, MNTTYPE_SUPER) == 0 ) {
slouken@0
   204
				tmp = strstr(mntent->mnt_opts, "fs=");
slouken@0
   205
				if ( tmp ) {
slouken@247
   206
					free(mnt_type);
slouken@247
   207
					mnt_type = strdup(tmp + strlen("fs="));
slouken@247
   208
					if ( mnt_type ) {
slouken@247
   209
						tmp = strchr(mnt_type, ',');
slouken@247
   210
						if ( tmp ) {
slouken@247
   211
							*tmp = '\0';
slouken@247
   212
						}
slouken@0
   213
					}
slouken@0
   214
				}
slouken@0
   215
				tmp = strstr(mntent->mnt_opts, "dev=");
slouken@0
   216
				if ( tmp ) {
slouken@247
   217
					free(mnt_dev);
slouken@247
   218
					mnt_dev = strdup(tmp + strlen("dev="));
slouken@247
   219
					if ( mnt_dev ) {
slouken@247
   220
						tmp = strchr(mnt_dev, ',');
slouken@247
   221
						if ( tmp ) {
slouken@247
   222
							*tmp = '\0';
slouken@247
   223
						}
slouken@0
   224
					}
slouken@0
   225
				}
slouken@0
   226
			}
slouken@0
   227
			if ( strcmp(mnt_type, MNTTYPE_CDROM) == 0 ) {
slouken@0
   228
#ifdef DEBUG_CDROM
slouken@0
   229
  fprintf(stderr, "Checking mount path from %s: %s mounted on %s of %s\n",
slouken@0
   230
	mtab, mnt_dev, mntent->mnt_dir, mnt_type);
slouken@0
   231
#endif
slouken@0
   232
				if (CheckDrive(mnt_dev, mnt_type, &stbuf) > 0) {
slouken@0
   233
					AddDrive(mnt_dev, &stbuf);
slouken@0
   234
				}
slouken@0
   235
			}
slouken@139
   236
			free(mnt_dev);
slouken@139
   237
			free(mnt_type);
slouken@0
   238
		}
slouken@0
   239
		endmntent(mntfp);
slouken@0
   240
	}
slouken@0
   241
}
slouken@0
   242
#endif /* USE_MNTENT */
slouken@0
   243
slouken@0
   244
int  SDL_SYS_CDInit(void)
slouken@0
   245
{
slouken@0
   246
	/* checklist: /dev/cdrom, /dev/hd?, /dev/scd? /dev/sr? */
slouken@0
   247
	static char *checklist[] = {
slouken@0
   248
		"cdrom", "?a hd?", "?0 scd?", "?0 sr?", NULL
slouken@0
   249
	};
slouken@0
   250
	char *SDLcdrom;
slouken@0
   251
	int i, j, exists;
slouken@0
   252
	char drive[32];
slouken@0
   253
	struct stat stbuf;
slouken@0
   254
slouken@0
   255
	/* Fill in our driver capabilities */
slouken@0
   256
	SDL_CDcaps.Name = SDL_SYS_CDName;
slouken@0
   257
	SDL_CDcaps.Open = SDL_SYS_CDOpen;
slouken@0
   258
	SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
slouken@0
   259
	SDL_CDcaps.Status = SDL_SYS_CDStatus;
slouken@0
   260
	SDL_CDcaps.Play = SDL_SYS_CDPlay;
slouken@0
   261
	SDL_CDcaps.Pause = SDL_SYS_CDPause;
slouken@0
   262
	SDL_CDcaps.Resume = SDL_SYS_CDResume;
slouken@0
   263
	SDL_CDcaps.Stop = SDL_SYS_CDStop;
slouken@0
   264
	SDL_CDcaps.Eject = SDL_SYS_CDEject;
slouken@0
   265
	SDL_CDcaps.Close = SDL_SYS_CDClose;
slouken@0
   266
slouken@0
   267
	/* Look in the environment for our CD-ROM drive list */
slouken@0
   268
	SDLcdrom = getenv("SDL_CDROM");	/* ':' separated list of devices */
slouken@0
   269
	if ( SDLcdrom != NULL ) {
slouken@0
   270
		char *cdpath, *delim;
slouken@0
   271
		cdpath = malloc(strlen(SDLcdrom)+1);
slouken@0
   272
		if ( cdpath != NULL ) {
slouken@0
   273
			strcpy(cdpath, SDLcdrom);
slouken@0
   274
			SDLcdrom = cdpath;
slouken@0
   275
			do {
slouken@0
   276
				delim = strchr(SDLcdrom, ':');
slouken@0
   277
				if ( delim ) {
slouken@0
   278
					*delim++ = '\0';
slouken@0
   279
				}
slouken@0
   280
#ifdef DEBUG_CDROM
slouken@0
   281
  fprintf(stderr, "Checking CD-ROM drive from SDL_CDROM: %s\n", SDLcdrom);
slouken@0
   282
#endif
slouken@0
   283
				if ( CheckDrive(SDLcdrom, NULL, &stbuf) > 0 ) {
slouken@0
   284
					AddDrive(SDLcdrom, &stbuf);
slouken@0
   285
				}
slouken@0
   286
				if ( delim ) {
slouken@0
   287
					SDLcdrom = delim;
slouken@0
   288
				} else {
slouken@0
   289
					SDLcdrom = NULL;
slouken@0
   290
				}
slouken@0
   291
			} while ( SDLcdrom );
slouken@0
   292
			free(cdpath);
slouken@0
   293
		}
slouken@0
   294
slouken@0
   295
		/* If we found our drives, there's nothing left to do */
slouken@0
   296
		if ( SDL_numcds > 0 ) {
slouken@0
   297
			return(0);
slouken@0
   298
		}
slouken@0
   299
	}
slouken@0
   300
slouken@0
   301
#ifdef USE_MNTENT
slouken@0
   302
	/* Check /dev/cdrom first :-) */
slouken@0
   303
	if (CheckDrive("/dev/cdrom", NULL, &stbuf) > 0) {
slouken@0
   304
		AddDrive("/dev/cdrom", &stbuf);
slouken@0
   305
	}
slouken@0
   306
slouken@0
   307
	/* Now check the currently mounted CD drives */
slouken@0
   308
	CheckMounts(_PATH_MOUNTED);
slouken@0
   309
slouken@0
   310
	/* Finally check possible mountable drives in /etc/fstab */
slouken@0
   311
	CheckMounts(_PATH_MNTTAB);
slouken@0
   312
slouken@0
   313
	/* If we found our drives, there's nothing left to do */
slouken@0
   314
	if ( SDL_numcds > 0 ) {
slouken@0
   315
		return(0);
slouken@0
   316
	}
slouken@0
   317
#endif /* USE_MNTENT */
slouken@0
   318
slouken@0
   319
	/* Scan the system for CD-ROM drives.
slouken@0
   320
	   Not always 100% reliable, so use the USE_MNTENT code above first.
slouken@0
   321
	 */
slouken@0
   322
	for ( i=0; checklist[i]; ++i ) {
slouken@0
   323
		if ( checklist[i][0] == '?' ) {
slouken@0
   324
			char *insert;
slouken@0
   325
			exists = 1;
slouken@0
   326
			for ( j=checklist[i][1]; exists; ++j ) {
slouken@0
   327
				sprintf(drive, "/dev/%s", &checklist[i][3]);
slouken@0
   328
				insert = strchr(drive, '?');
slouken@0
   329
				if ( insert != NULL ) {
slouken@0
   330
					*insert = j;
slouken@0
   331
				}
slouken@0
   332
#ifdef DEBUG_CDROM
slouken@0
   333
  fprintf(stderr, "Checking possible CD-ROM drive: %s\n", drive);
slouken@0
   334
#endif
slouken@0
   335
				switch (CheckDrive(drive, NULL, &stbuf)) {
slouken@0
   336
					/* Drive exists and is a CD-ROM */
slouken@0
   337
					case 1:
slouken@0
   338
						AddDrive(drive, &stbuf);
slouken@0
   339
						break;
slouken@0
   340
					/* Drive exists, but isn't a CD-ROM */
slouken@0
   341
					case 0:
slouken@0
   342
						break;
slouken@0
   343
					/* Drive doesn't exist */
slouken@0
   344
					case -1:
slouken@0
   345
						exists = 0;
slouken@0
   346
						break;
slouken@0
   347
				}
slouken@0
   348
			}
slouken@0
   349
		} else {
slouken@0
   350
			sprintf(drive, "/dev/%s", checklist[i]);
slouken@0
   351
#ifdef DEBUG_CDROM
slouken@0
   352
  fprintf(stderr, "Checking possible CD-ROM drive: %s\n", drive);
slouken@0
   353
#endif
slouken@0
   354
			if ( CheckDrive(drive, NULL, &stbuf) > 0 ) {
slouken@0
   355
				AddDrive(drive, &stbuf);
slouken@0
   356
			}
slouken@0
   357
		}
slouken@0
   358
	}
slouken@0
   359
	return(0);
slouken@0
   360
}
slouken@0
   361
slouken@0
   362
/* General ioctl() CD-ROM command function */
slouken@0
   363
static int SDL_SYS_CDioctl(int id, int command, void *arg)
slouken@0
   364
{
slouken@0
   365
	int retval;
slouken@0
   366
slouken@0
   367
	retval = ioctl(id, command, arg);
slouken@0
   368
	if ( retval < 0 ) {
slouken@0
   369
		SDL_SetError("ioctl() error: %s", strerror(errno));
slouken@0
   370
	}
slouken@0
   371
	return(retval);
slouken@0
   372
}
slouken@0
   373
slouken@0
   374
static const char *SDL_SYS_CDName(int drive)
slouken@0
   375
{
slouken@0
   376
	return(SDL_cdlist[drive]);
slouken@0
   377
}
slouken@0
   378
slouken@0
   379
static int SDL_SYS_CDOpen(int drive)
slouken@0
   380
{
slouken@0
   381
	return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0));
slouken@0
   382
}
slouken@0
   383
slouken@0
   384
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
slouken@0
   385
{
slouken@0
   386
	struct cdrom_tochdr toc;
slouken@0
   387
	int i, okay;
slouken@0
   388
	struct cdrom_tocentry entry;
slouken@0
   389
slouken@0
   390
	okay = 0;
slouken@0
   391
	if ( SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc) == 0 ) {
slouken@0
   392
		cdrom->numtracks = toc.cdth_trk1-toc.cdth_trk0+1;
slouken@0
   393
		if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
slouken@0
   394
			cdrom->numtracks = SDL_MAX_TRACKS;
slouken@0
   395
		}
slouken@0
   396
		/* Read all the track TOC entries */
slouken@0
   397
		for ( i=0; i<=cdrom->numtracks; ++i ) {
slouken@0
   398
			if ( i == cdrom->numtracks ) {
slouken@0
   399
				cdrom->track[i].id = CDROM_LEADOUT;
slouken@0
   400
			} else {
slouken@0
   401
				cdrom->track[i].id = toc.cdth_trk0+i;
slouken@0
   402
			}
slouken@0
   403
			entry.cdte_track = cdrom->track[i].id;
slouken@0
   404
			entry.cdte_format = CDROM_MSF;
slouken@0
   405
			if ( SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCENTRY,
slouken@0
   406
								&entry) < 0 ) {
slouken@0
   407
				break;
slouken@0
   408
			} else {
slouken@0
   409
				if ( entry.cdte_ctrl & CDROM_DATA_TRACK ) {
slouken@0
   410
					cdrom->track[i].type = SDL_DATA_TRACK;
slouken@0
   411
				} else {
slouken@0
   412
					cdrom->track[i].type = SDL_AUDIO_TRACK;
slouken@0
   413
				}
slouken@0
   414
				cdrom->track[i].offset = MSF_TO_FRAMES(
slouken@0
   415
						entry.cdte_addr.msf.minute,
slouken@0
   416
						entry.cdte_addr.msf.second,
slouken@0
   417
						entry.cdte_addr.msf.frame);
slouken@0
   418
				cdrom->track[i].length = 0;
slouken@0
   419
				if ( i > 0 ) {
slouken@0
   420
					cdrom->track[i-1].length =
slouken@0
   421
						cdrom->track[i].offset-
slouken@0
   422
						cdrom->track[i-1].offset;
slouken@0
   423
				}
slouken@0
   424
			}
slouken@0
   425
		}
slouken@0
   426
		if ( i == (cdrom->numtracks+1) ) {
slouken@0
   427
			okay = 1;
slouken@0
   428
		}
slouken@0
   429
	}
slouken@0
   430
	return(okay ? 0 : -1);
slouken@0
   431
}
slouken@0
   432
slouken@0
   433
/* Get CD-ROM status */
slouken@0
   434
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
slouken@0
   435
{
slouken@0
   436
	CDstatus status;
slouken@0
   437
	struct cdrom_tochdr toc;
slouken@0
   438
	struct cdrom_subchnl info;
slouken@0
   439
slouken@0
   440
	info.cdsc_format = CDROM_MSF;
slouken@0
   441
	if ( ioctl(cdrom->id, CDROMSUBCHNL, &info) < 0 ) {
slouken@0
   442
		if ( ERRNO_TRAYEMPTY(errno) ) {
slouken@0
   443
			status = CD_TRAYEMPTY;
slouken@0
   444
		} else {
slouken@0
   445
			status = CD_ERROR;
slouken@0
   446
		}
slouken@0
   447
	} else {
slouken@0
   448
		switch (info.cdsc_audiostatus) {
slouken@0
   449
			case CDROM_AUDIO_INVALID:
slouken@0
   450
			case CDROM_AUDIO_NO_STATUS:
slouken@0
   451
				/* Try to determine if there's a CD available */
slouken@0
   452
				if (ioctl(cdrom->id, CDROMREADTOCHDR, &toc)==0)
slouken@0
   453
					status = CD_STOPPED;
slouken@0
   454
				else
slouken@0
   455
					status = CD_TRAYEMPTY;
slouken@0
   456
				break;
slouken@0
   457
			case CDROM_AUDIO_COMPLETED:
slouken@0
   458
				status = CD_STOPPED;
slouken@0
   459
				break;
slouken@0
   460
			case CDROM_AUDIO_PLAY:
slouken@0
   461
				status = CD_PLAYING;
slouken@0
   462
				break;
slouken@0
   463
			case CDROM_AUDIO_PAUSED:
slouken@0
   464
				/* Workaround buggy CD-ROM drive */
slouken@0
   465
				if ( info.cdsc_trk == CDROM_LEADOUT ) {
slouken@0
   466
					status = CD_STOPPED;
slouken@0
   467
				} else {
slouken@0
   468
					status = CD_PAUSED;
slouken@0
   469
				}
slouken@0
   470
				break;
slouken@0
   471
			default:
slouken@0
   472
				status = CD_ERROR;
slouken@0
   473
				break;
slouken@0
   474
		}
slouken@0
   475
	}
slouken@0
   476
	if ( position ) {
slouken@0
   477
		if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
slouken@0
   478
			*position = MSF_TO_FRAMES(
slouken@0
   479
					info.cdsc_absaddr.msf.minute,
slouken@0
   480
					info.cdsc_absaddr.msf.second,
slouken@0
   481
					info.cdsc_absaddr.msf.frame);
slouken@0
   482
		} else {
slouken@0
   483
			*position = 0;
slouken@0
   484
		}
slouken@0
   485
	}
slouken@0
   486
	return(status);
slouken@0
   487
}
slouken@0
   488
slouken@0
   489
/* Start play */
slouken@0
   490
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
slouken@0
   491
{
slouken@0
   492
	struct cdrom_msf playtime;
slouken@0
   493
slouken@0
   494
	FRAMES_TO_MSF(start,
slouken@0
   495
	   &playtime.cdmsf_min0, &playtime.cdmsf_sec0, &playtime.cdmsf_frame0);
slouken@0
   496
	FRAMES_TO_MSF(start+length,
slouken@0
   497
	   &playtime.cdmsf_min1, &playtime.cdmsf_sec1, &playtime.cdmsf_frame1);
slouken@0
   498
#ifdef DEBUG_CDROM
slouken@0
   499
  fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
slouken@0
   500
	playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
slouken@0
   501
	playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
slouken@0
   502
#endif
slouken@0
   503
	return(SDL_SYS_CDioctl(cdrom->id, CDROMPLAYMSF, &playtime));
slouken@0
   504
}
slouken@0
   505
slouken@0
   506
/* Pause play */
slouken@0
   507
static int SDL_SYS_CDPause(SDL_CD *cdrom)
slouken@0
   508
{
slouken@0
   509
	return(SDL_SYS_CDioctl(cdrom->id, CDROMPAUSE, 0));
slouken@0
   510
}
slouken@0
   511
slouken@0
   512
/* Resume play */
slouken@0
   513
static int SDL_SYS_CDResume(SDL_CD *cdrom)
slouken@0
   514
{
slouken@0
   515
	return(SDL_SYS_CDioctl(cdrom->id, CDROMRESUME, 0));
slouken@0
   516
}
slouken@0
   517
slouken@0
   518
/* Stop play */
slouken@0
   519
static int SDL_SYS_CDStop(SDL_CD *cdrom)
slouken@0
   520
{
slouken@0
   521
	return(SDL_SYS_CDioctl(cdrom->id, CDROMSTOP, 0));
slouken@0
   522
}
slouken@0
   523
slouken@0
   524
/* Eject the CD-ROM */
slouken@0
   525
static int SDL_SYS_CDEject(SDL_CD *cdrom)
slouken@0
   526
{
slouken@0
   527
	return(SDL_SYS_CDioctl(cdrom->id, CDROMEJECT, 0));
slouken@0
   528
}
slouken@0
   529
slouken@0
   530
/* Close the CD-ROM handle */
slouken@0
   531
static void SDL_SYS_CDClose(SDL_CD *cdrom)
slouken@0
   532
{
slouken@0
   533
	close(cdrom->id);
slouken@0
   534
}
slouken@0
   535
slouken@0
   536
void SDL_SYS_CDQuit(void)
slouken@0
   537
{
slouken@0
   538
	int i;
slouken@0
   539
slouken@0
   540
	if ( SDL_numcds > 0 ) {
slouken@0
   541
		for ( i=0; i<SDL_numcds; ++i ) {
slouken@0
   542
			free(SDL_cdlist[i]);
slouken@0
   543
		}
slouken@0
   544
		SDL_numcds = 0;
slouken@0
   545
	}
slouken@0
   546
}
slouken@0
   547