Home | History | Annotate | Download | only in aix
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 Sam Lantinga
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Lesser General Public
      7     License as published by the Free Software Foundation; either
      8     version 2.1 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Lesser General Public License for more details.
     14 
     15     You should have received a copy of the GNU Lesser General Public
     16     License along with this library; if not, write to the Free Software
     17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     18 
     19     Carsten Griwodz
     20     griff (at) kom.tu-darmstadt.de
     21 
     22     based on linux/SDL_syscdrom.c by Sam Lantinga
     23 */
     24 #include "SDL_config.h"
     25 
     26 #ifdef SDL_CDROM_AIX
     27 
     28 /* Functions for system-level CD-ROM audio control */
     29 
     30 /*#define DEBUG_CDROM 1*/
     31 
     32 #include <sys/types.h>
     33 #include <sys/stat.h>
     34 #include <fcntl.h>
     35 #include <errno.h>
     36 #include <unistd.h>
     37 
     38 #include <sys/ioctl.h>
     39 #include <sys/devinfo.h>
     40 #include <sys/mntctl.h>
     41 #include <sys/statfs.h>
     42 #include <sys/vmount.h>
     43 #include <fstab.h>
     44 #include <sys/scdisk.h>
     45 
     46 #include "SDL_cdrom.h"
     47 #include "../SDL_syscdrom.h"
     48 
     49 /* The maximum number of CD-ROM drives we'll detect */
     50 #define MAX_DRIVES	16
     51 
     52 /* A list of available CD-ROM drives */
     53 static char *SDL_cdlist[MAX_DRIVES];
     54 static dev_t SDL_cdmode[MAX_DRIVES];
     55 
     56 /* The system-dependent CD control functions */
     57 static const char *SDL_SYS_CDName(int drive);
     58 static int         SDL_SYS_CDOpen(int drive);
     59 static int         SDL_SYS_CDGetTOC(SDL_CD *cdrom);
     60 static CDstatus    SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
     61 static int         SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
     62 static int         SDL_SYS_CDPause(SDL_CD *cdrom);
     63 static int         SDL_SYS_CDResume(SDL_CD *cdrom);
     64 static int         SDL_SYS_CDStop(SDL_CD *cdrom);
     65 static int         SDL_SYS_CDEject(SDL_CD *cdrom);
     66 static void        SDL_SYS_CDClose(SDL_CD *cdrom);
     67 static int         SDL_SYS_CDioctl(int id, int command, void *arg);
     68 
     69 /* Check a drive to see if it is a CD-ROM */
     70 static int CheckDrive(char *drive, struct stat *stbuf)
     71 {
     72     int is_cd;
     73     int cdfd;
     74     int ret;
     75     struct devinfo info;
     76 
     77     /* If it doesn't exist, return -1 */
     78     if ( stat(drive, stbuf) < 0 ) {
     79         return -1;
     80     }
     81 
     82     /* If it does exist, verify that it's an available CD-ROM */
     83     is_cd = 0;
     84     if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
     85         cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
     86         if ( cdfd >= 0 ) {
     87             ret = SDL_SYS_CDioctl( cdfd, IOCINFO, &info );
     88 	    if ( ret < 0 ) {
     89 		/* Some kind of error */
     90 		is_cd = 0;
     91 	    } else {
     92 		if ( info.devtype == DD_CDROM ) {
     93 		    is_cd = 1;
     94 		} else {
     95 		    is_cd = 0;
     96 		}
     97 	    }
     98             close(cdfd);
     99 	}
    100 #ifdef DEBUG_CDROM
    101 	else
    102 	{
    103             fprintf(stderr, "Could not open drive %s (%s)\n", drive, strerror(errno));
    104 	}
    105 #endif
    106     }
    107     return is_cd;
    108 }
    109 
    110 /* Add a CD-ROM drive to our list of valid drives */
    111 static void AddDrive(char *drive, struct stat *stbuf)
    112 {
    113 	int i;
    114 
    115 	if ( SDL_numcds < MAX_DRIVES ) {
    116 		/* Check to make sure it's not already in our list.
    117 	 	   This can happen when we see a drive via symbolic link.
    118 		 */
    119 		for ( i=0; i<SDL_numcds; ++i ) {
    120 			if ( stbuf->st_rdev == SDL_cdmode[i] ) {
    121 #ifdef DEBUG_CDROM
    122   fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
    123 #endif
    124 				return;
    125 			}
    126 		}
    127 
    128 		/* Add this drive to our list */
    129 		i = SDL_numcds;
    130 		SDL_cdlist[i] = SDL_strdup(drive);
    131 		if ( SDL_cdlist[i] == NULL ) {
    132 			SDL_OutOfMemory();
    133 			return;
    134 		}
    135 		SDL_cdmode[i] = stbuf->st_rdev;
    136 		++SDL_numcds;
    137 #ifdef DEBUG_CDROM
    138   fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
    139 #endif
    140 	}
    141 }
    142 
    143 static void CheckMounts()
    144 {
    145     char*          buffer;
    146     int            bufsz;
    147     struct vmount* ptr;
    148     int            ret;
    149 
    150     buffer = (char*)SDL_malloc(10);
    151     bufsz  = 10;
    152     if ( buffer==NULL )
    153     {
    154         fprintf(stderr, "Could not allocate 10 bytes in aix/SDL_syscdrom.c:CheckMounts\n" );
    155 	exit ( -10 );
    156     }
    157 
    158     do
    159     {
    160 	/* mntctrl() returns an array of all mounted filesystems */
    161         ret = mntctl ( MCTL_QUERY, bufsz, buffer );
    162         if ( ret == 0 )
    163         {
    164 				   /* Buffer was too small, realloc.    */
    165             bufsz = *(int*)buffer; /* Required size is in first word.   */
    166 				   /* (whatever a word is in AIX 4.3.3) */
    167 				   /* int seems to be OK in 32bit mode. */
    168             SDL_free(buffer);
    169             buffer = (char*)SDL_malloc(bufsz);
    170             if ( buffer==NULL )
    171             {
    172                 fprintf(stderr,
    173 			"Could not allocate %d bytes in aix/SDL_syscdrom.c:CheckMounts\n",
    174 			bufsz );
    175 	        exit ( -10 );
    176             }
    177         }
    178 	else if ( ret < 0 )
    179 	{
    180 #ifdef DEBUG_CDROM
    181             fprintf(stderr, "Error reading vmount structures\n");
    182 #endif
    183 	    return;
    184 	}
    185     }
    186     while ( ret == 0 );
    187 
    188 #ifdef DEBUG_CDROM
    189     fprintf ( stderr, "Read %d vmount structures\n",ret );
    190 #endif
    191     ptr = (struct vmount*)buffer;
    192     do
    193     {
    194             switch(ptr->vmt_gfstype)
    195             {
    196             case MNT_CDROM :
    197                 {
    198 		    struct stat stbuf;
    199 		    char*       text;
    200 
    201 		    text = (char*)ptr + ptr->vmt_data[VMT_OBJECT].vmt_off;
    202 #ifdef DEBUG_CDROM
    203   fprintf(stderr, "Checking mount path: %s mounted on %s\n",
    204 	text, (char*)ptr + ptr->vmt_data[VMT_STUB].vmt_off );
    205 #endif
    206 		    if ( CheckDrive( text, &stbuf) > 0)
    207 		    {
    208 		        AddDrive( text, &stbuf);
    209 		    }
    210                 }
    211                 break;
    212             default :
    213                 break;
    214             }
    215             ptr = (struct vmount*)((char*)ptr + ptr->vmt_length);
    216             ret--;
    217     }
    218     while ( ret > 0 );
    219 
    220     free ( buffer );
    221 }
    222 
    223 static int CheckNonmounts()
    224 {
    225 #ifdef _THREAD_SAFE
    226     AFILE_t      fsFile = NULL;
    227     int          passNo = 0;
    228     int          ret;
    229     struct fstab entry;
    230     struct stat  stbuf;
    231 
    232     ret = setfsent_r( &fsFile, &passNo );
    233     if ( ret != 0 ) return -1;
    234     do
    235     {
    236         ret = getfsent_r ( &entry, &fsFile, &passNo );
    237         if ( ret == 0 ) {
    238             char* l = SDL_strrchr(entry.fs_spec,'/');
    239             if ( l != NULL ) {
    240                 if ( !SDL_strncmp("cd",++l,2) ) {
    241 #ifdef DEBUG_CDROM
    242                     fprintf(stderr,
    243 			    "Found unmounted CD ROM drive with device name %s\n",
    244 			    entry.fs_spec);
    245 #endif
    246 		    if ( CheckDrive( entry.fs_spec, &stbuf) > 0)
    247 		    {
    248 		        AddDrive( entry.fs_spec, &stbuf);
    249 		    }
    250                 }
    251             }
    252         }
    253     }
    254     while ( ret == 0 );
    255     ret = endfsent_r ( &fsFile );
    256     if ( ret != 0 ) return -1;
    257     return 0;
    258 #else
    259     struct fstab* entry;
    260     struct stat  stbuf;
    261 
    262     setfsent();
    263     do
    264     {
    265         entry = getfsent();
    266         if ( entry != NULL ) {
    267             char* l = SDL_strrchr(entry->fs_spec,'/');
    268             if ( l != NULL ) {
    269                 if ( !SDL_strncmp("cd",++l,2) ) {
    270 #ifdef DEBUG_CDROM
    271                     fprintf(stderr,"Found unmounted CD ROM drive with device name %s", entry->fs_spec);
    272 #endif
    273 		    if ( CheckDrive( entry->fs_spec, &stbuf) > 0)
    274 		    {
    275 		        AddDrive( entry->fs_spec, &stbuf);
    276 		    }
    277                 }
    278             }
    279         }
    280     }
    281     while ( entry != NULL );
    282     endfsent();
    283 #endif
    284 }
    285 
    286 int  SDL_SYS_CDInit(void)
    287 {
    288 	char *SDLcdrom;
    289 	struct stat stbuf;
    290 
    291 	/* Fill in our driver capabilities */
    292 	SDL_CDcaps.Name = SDL_SYS_CDName;
    293 	SDL_CDcaps.Open = SDL_SYS_CDOpen;
    294 	SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
    295 	SDL_CDcaps.Status = SDL_SYS_CDStatus;
    296 	SDL_CDcaps.Play = SDL_SYS_CDPlay;
    297 	SDL_CDcaps.Pause = SDL_SYS_CDPause;
    298 	SDL_CDcaps.Resume = SDL_SYS_CDResume;
    299 	SDL_CDcaps.Stop = SDL_SYS_CDStop;
    300 	SDL_CDcaps.Eject = SDL_SYS_CDEject;
    301 	SDL_CDcaps.Close = SDL_SYS_CDClose;
    302 
    303 	/* Look in the environment for our CD-ROM drive list */
    304 	SDLcdrom = SDL_getenv("SDL_CDROM");	/* ':' separated list of devices */
    305 	if ( SDLcdrom != NULL ) {
    306 		char *cdpath, *delim;
    307 		size_t len = SDL_strlen(SDLcdrom)+1;
    308 		cdpath = SDL_stack_alloc(char, len);
    309 		if ( cdpath != NULL ) {
    310 			SDL_strlcpy(cdpath, SDLcdrom, len);
    311 			SDLcdrom = cdpath;
    312 			do {
    313 				delim = SDL_strchr(SDLcdrom, ':');
    314 				if ( delim ) {
    315 					*delim++ = '\0';
    316 				}
    317 #ifdef DEBUG_CDROM
    318   fprintf(stderr, "Checking CD-ROM drive from SDL_CDROM: %s\n", SDLcdrom);
    319 #endif
    320 				if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) {
    321 					AddDrive(SDLcdrom, &stbuf);
    322 				}
    323 				if ( delim ) {
    324 					SDLcdrom = delim;
    325 				} else {
    326 					SDLcdrom = NULL;
    327 				}
    328 			} while ( SDLcdrom );
    329 			SDL_stack_free(cdpath);
    330 		}
    331 
    332 		/* If we found our drives, there's nothing left to do */
    333 		if ( SDL_numcds > 0 ) {
    334 			return(0);
    335 		}
    336 	}
    337 
    338 	CheckMounts();
    339 	CheckNonmounts();
    340 
    341 	return 0;
    342 }
    343 
    344 /* General ioctl() CD-ROM command function */
    345 static int SDL_SYS_CDioctl(int id, int command, void *arg)
    346 {
    347     int retval;
    348 
    349     retval = ioctl(id, command, arg);
    350     if ( retval < 0 ) {
    351         SDL_SetError("ioctl() error: %s", strerror(errno));
    352     }
    353     return retval;
    354 }
    355 
    356 static const char *SDL_SYS_CDName(int drive)
    357 {
    358 	return(SDL_cdlist[drive]);
    359 }
    360 
    361 static int SDL_SYS_CDOpen(int drive)
    362 {
    363     int   fd;
    364     char* lastsl;
    365     char* cdromname;
    366     size_t len;
    367 
    368     /*
    369      * We found /dev/cd? drives and that is in our list. But we can
    370      * open only the /dev/rcd? versions of those devices for Audio CD.
    371      */
    372     len = SDL_strlen(SDL_cdlist[drive])+2;
    373     cdromname = (char*)SDL_malloc(len);
    374     SDL_strlcpy(cdromname,SDL_cdlist[drive],len);
    375     lastsl = SDL_strrchr(cdromname,'/');
    376     if (lastsl) {
    377 	*lastsl = 0;
    378 	SDL_strlcat(cdromname,"/r",len);
    379 	lastsl = SDL_strrchr(SDL_cdlist[drive],'/');
    380 	if (lastsl) {
    381 	    lastsl++;
    382 	    SDL_strlcat(cdromname,lastsl,len);
    383 	}
    384     }
    385 
    386 #ifdef DEBUG_CDROM
    387     fprintf(stderr, "Should open drive %s, opening %s\n", SDL_cdlist[drive], cdromname);
    388 #endif
    389 
    390     /*
    391      * Use exclusive access. Don't use SC_DIAGNOSTICS as xmcd does because they
    392      * require root priviledges, and we don't want that. SC_SINGLE provides
    393      * exclusive access with less trouble.
    394      */
    395     fd = openx(cdromname, O_RDONLY, NULL, SC_SINGLE);
    396     if ( fd < 0 )
    397     {
    398 #ifdef DEBUG_CDROM
    399             fprintf(stderr, "Could not open drive %s (%s)\n", cdromname, strerror(errno));
    400 #endif
    401     }
    402     else
    403     {
    404 	struct mode_form_op cdMode;
    405 	int                 ret;
    406 #ifdef DEBUG_CDROM
    407 	cdMode.action = CD_GET_MODE;
    408 	ret = SDL_SYS_CDioctl(fd, DK_CD_MODE, &cdMode);
    409 	if ( ret < 0 ) {
    410             fprintf(stderr,
    411 	            "Could not get drive mode for %s (%s)\n",
    412 		    cdromname, strerror(errno));
    413 	} else {
    414 	    switch(cdMode.cd_mode_form) {
    415 		case CD_MODE1 :
    416                     fprintf(stderr,
    417 	                "Drive mode for %s is %s\n",
    418 		        cdromname, "CD-ROM Data Mode 1");
    419 		    break;
    420 		case CD_MODE2_FORM1 :
    421                     fprintf(stderr,
    422 	                "Drive mode for %s is %s\n",
    423 		        cdromname, "CD-ROM XA Data Mode 2 Form 1");
    424 		    break;
    425 		case CD_MODE2_FORM2 :
    426                     fprintf(stderr,
    427 	                "Drive mode for %s is %s\n",
    428 		        cdromname, "CD-ROM XA Data Mode 2 Form 2");
    429 		    break;
    430 		case CD_DA :
    431                     fprintf(stderr,
    432 	                "Drive mode for %s is %s\n",
    433 		        cdromname, "CD-DA");
    434 		    break;
    435 		default :
    436                     fprintf(stderr,
    437 	                "Drive mode for %s is %s\n",
    438 		        cdromname, "unknown");
    439 		    break;
    440 	    }
    441 	}
    442 #endif
    443 
    444 	cdMode.action       = CD_CHG_MODE;
    445 	cdMode.cd_mode_form = CD_DA;
    446 	ret = SDL_SYS_CDioctl(fd, DK_CD_MODE, &cdMode);
    447 	if ( ret < 0 ) {
    448 #ifdef DEBUG_CDROM
    449             fprintf(stderr,
    450 	            "Could not set drive mode for %s (%s)\n",
    451 		    cdromname, strerror(errno));
    452 #endif
    453             SDL_SetError("ioctl() error: Could not set CD drive mode, %s",
    454 	                 strerror(errno));
    455 	} else {
    456 #ifdef DEBUG_CDROM
    457             fprintf(stderr,
    458 	            "Drive mode for %s set to CD_DA\n",
    459 		    cdromname);
    460 #endif
    461 	}
    462     }
    463     SDL_free(cdromname);
    464     return fd;
    465 }
    466 
    467 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
    468 {
    469     struct cd_audio_cmd cmd;
    470     struct cd_audio_cmd entry;
    471     int                 i;
    472     int                 okay;
    473 
    474     cmd.audio_cmds = CD_TRK_INFO_AUDIO;
    475     cmd.msf_flag   = FALSE;
    476     if ( SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd) < 0 ) {
    477 	return -1;
    478     }
    479 
    480     okay = 0;
    481     cdrom->numtracks = cmd.indexing.track_index.last_track
    482 		     - cmd.indexing.track_index.first_track+1;
    483     if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
    484         cdrom->numtracks = SDL_MAX_TRACKS;
    485     }
    486 
    487     /* Read all the track TOC entries */
    488     for ( i=0; i<=cdrom->numtracks; ++i ) {
    489         if ( i == cdrom->numtracks ) {
    490             cdrom->track[i].id = 0xAA;;
    491         } else {
    492             cdrom->track[i].id = cmd.indexing.track_index.first_track+i;
    493         }
    494         entry.audio_cmds         = CD_GET_TRK_MSF;
    495 	entry.indexing.track_msf.track = cdrom->track[i].id;
    496 	if ( SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &entry) < 0 ) {
    497             break;
    498         } else {
    499             cdrom->track[i].type = 0;    /* don't know how to detect 0x04 data track */
    500             cdrom->track[i].offset = MSF_TO_FRAMES(
    501                 entry.indexing.track_msf.mins,
    502                 entry.indexing.track_msf.secs,
    503                 entry.indexing.track_msf.frames);
    504             cdrom->track[i].length = 0;
    505             if ( i > 0 ) {
    506                 cdrom->track[i-1].length = cdrom->track[i].offset
    507 		                         - cdrom->track[i-1].offset;
    508             }
    509         }
    510     }
    511     if ( i == (cdrom->numtracks+1) ) {
    512         okay = 1;
    513     }
    514     return(okay ? 0 : -1);
    515 }
    516 
    517 /* Get CD-ROM status */
    518 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
    519 {
    520     CDstatus            status;
    521     struct cd_audio_cmd cmd;
    522     cmd.audio_cmds = CD_INFO_AUDIO;
    523 
    524     if ( SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd) < 0 ) {
    525 #ifdef DEBUG_CDROM
    526     fprintf(stderr, "ioctl failed in SDL_SYS_CDStatus (%s)\n", SDL_GetError());
    527 #endif
    528         status = CD_ERROR;
    529     } else {
    530         switch (cmd.status) {
    531             case CD_NO_AUDIO:
    532             case CD_COMPLETED:
    533                 status = CD_STOPPED;
    534                 break;
    535             case CD_PLAY_AUDIO:
    536                 status = CD_PLAYING;
    537                 break;
    538             case CD_PAUSE_AUDIO:
    539                 status = CD_PAUSED;
    540                 break;
    541             case CD_NOT_VALID:
    542 #ifdef DEBUG_CDROM
    543     fprintf(stderr, "cdStatus failed with CD_NOT_VALID\n");
    544 #endif
    545                 status = CD_ERROR;
    546                 break;
    547             case CD_STATUS_ERROR:
    548 #ifdef DEBUG_CDROM
    549     fprintf(stderr, "cdStatus failed with CD_STATUS_ERROR\n");
    550 #endif
    551                 status = CD_ERROR;
    552                 break;
    553             default:
    554 #ifdef DEBUG_CDROM
    555     fprintf(stderr, "cdStatus failed with unknown error\n");
    556 #endif
    557                 status = CD_ERROR;
    558                 break;
    559         }
    560     }
    561     if ( position ) {
    562         if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
    563             *position = MSF_TO_FRAMES( cmd.indexing.info_audio.current_mins,
    564                                        cmd.indexing.info_audio.current_secs,
    565                                        cmd.indexing.info_audio.current_frames);
    566         } else {
    567             *position = 0;
    568         }
    569     }
    570     return status;
    571 }
    572 
    573 /* Start play */
    574 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
    575 {
    576     struct cd_audio_cmd cmd;
    577 
    578     /*
    579      * My CD Rom is muted by default. I think I read that this is new with
    580      * AIX 4.3. SDL does not change the volume, so I need a kludge. Maybe
    581      * its better to do this elsewhere?
    582      */
    583     cmd.audio_cmds = CD_PLAY_AUDIO | CD_SET_VOLUME;
    584     cmd.msf_flag   = TRUE;
    585     FRAMES_TO_MSF(start,
    586                   &cmd.indexing.msf.first_mins,
    587                   &cmd.indexing.msf.first_secs,
    588                   &cmd.indexing.msf.first_frames);
    589     FRAMES_TO_MSF(start+length,
    590                   &cmd.indexing.msf.last_mins,
    591                   &cmd.indexing.msf.last_secs,
    592                   &cmd.indexing.msf.last_frames);
    593     cmd.volume_type     = CD_VOLUME_ALL;
    594     cmd.all_channel_vol = 255;   /* This is a uchar. What is a good value? No docu! */
    595     cmd.out_port_0_sel  = CD_AUDIO_CHNL_0;
    596     cmd.out_port_1_sel  = CD_AUDIO_CHNL_1;
    597     cmd.out_port_2_sel  = CD_AUDIO_CHNL_2;
    598     cmd.out_port_3_sel  = CD_AUDIO_CHNL_3;
    599 
    600 #ifdef DEBUG_CDROM
    601   fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
    602 	cmd.indexing.msf.first_mins,
    603 	cmd.indexing.msf.first_secs,
    604 	cmd.indexing.msf.first_frames,
    605 	cmd.indexing.msf.last_mins,
    606 	cmd.indexing.msf.last_secs,
    607 	cmd.indexing.msf.last_frames);
    608 #endif
    609 	return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
    610 }
    611 
    612 /* Pause play */
    613 static int SDL_SYS_CDPause(SDL_CD *cdrom)
    614 {
    615     struct cd_audio_cmd cmd;
    616     cmd.audio_cmds = CD_PAUSE_AUDIO;
    617     return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
    618 }
    619 
    620 /* Resume play */
    621 static int SDL_SYS_CDResume(SDL_CD *cdrom)
    622 {
    623     struct cd_audio_cmd cmd;
    624     cmd.audio_cmds = CD_RESUME_AUDIO;
    625     return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
    626 }
    627 
    628 /* Stop play */
    629 static int SDL_SYS_CDStop(SDL_CD *cdrom)
    630 {
    631     struct cd_audio_cmd cmd;
    632     cmd.audio_cmds = CD_STOP_AUDIO;
    633     return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
    634 }
    635 
    636 /* Eject the CD-ROM */
    637 static int SDL_SYS_CDEject(SDL_CD *cdrom)
    638 {
    639     return(SDL_SYS_CDioctl(cdrom->id, DKEJECT, 0));
    640 }
    641 
    642 /* Close the CD-ROM handle */
    643 static void SDL_SYS_CDClose(SDL_CD *cdrom)
    644 {
    645     close(cdrom->id);
    646 }
    647 
    648 void SDL_SYS_CDQuit(void)
    649 {
    650 	int i;
    651 
    652 	if ( SDL_numcds > 0 ) {
    653 		for ( i=0; i<SDL_numcds; ++i ) {
    654 			SDL_free(SDL_cdlist[i]);
    655 		}
    656 		SDL_numcds = 0;
    657 	}
    658 }
    659 
    660 #endif /* SDL_CDROM_AIX */
    661