src/cdrom/freebsd/SDL_syscdrom.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. ERRNO_TRAYEMPTY
  2. CheckDrive
  3. AddDrive
  4. SDL_SYS_CDInit
  5. SDL_SYS_CDioctl
  6. SDL_SYS_CDName
  7. SDL_SYS_CDOpen
  8. SDL_SYS_CDGetTOC
  9. SDL_SYS_CDStatus
  10. SDL_SYS_CDPlay
  11. SDL_SYS_CDPause
  12. SDL_SYS_CDResume
  13. SDL_SYS_CDStop
  14. SDL_SYS_CDEject
  15. SDL_SYS_CDClose
  16. SDL_SYS_CDQuit

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
   4 
   5     This library is free software; you can redistribute it and/or
   6     modify it under the terms of the GNU Library General Public
   7     License as published by the Free Software Foundation; either
   8     version 2 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     Library General Public License for more details.
  14 
  15     You should have received a copy of the GNU Library General Public
  16     License along with this library; if not, write to the Free
  17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 
  19     Sam Lantinga
  20     slouken@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_syscdrom.c,v 1.2.2.3 2001/02/10 07:20:04 hercules Exp $";
  26 #endif
  27 
  28 /* Functions for system-level CD-ROM audio control */
  29 
  30 #include <sys/types.h>
  31 #include <stdlib.h>
  32 #include <sys/stat.h>
  33 #include <fcntl.h>
  34 #include <stdio.h>
  35 #include <string.h>
  36 #include <errno.h>
  37 #include <unistd.h>
  38 #include <sys/cdio.h>
  39 
  40 #include "SDL_error.h"
  41 #include "SDL_cdrom.h"
  42 #include "SDL_syscdrom.h"
  43 
  44 
  45 /* The maximum number of CD-ROM drives we'll detect */
  46 #define MAX_DRIVES      16      
  47 
  48 /* A list of available CD-ROM drives */
  49 static char *SDL_cdlist[MAX_DRIVES];
  50 static dev_t SDL_cdmode[MAX_DRIVES];
  51 
  52 /* The system-dependent CD control functions */
  53 static const char *SDL_SYS_CDName(int drive);
  54 static int SDL_SYS_CDOpen(int drive);
  55 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
  56 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
  57 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
  58 static int SDL_SYS_CDPause(SDL_CD *cdrom);
  59 static int SDL_SYS_CDResume(SDL_CD *cdrom);
  60 static int SDL_SYS_CDStop(SDL_CD *cdrom);
  61 static int SDL_SYS_CDEject(SDL_CD *cdrom);
  62 static void SDL_SYS_CDClose(SDL_CD *cdrom);
  63 
  64 /* Some ioctl() errno values which occur when the tray is empty */
  65 #define ERRNO_TRAYEMPTY(errno)  \
     /* [<][>][^][v][top][bottom][index][help] */
  66         ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL))
  67 
  68 /* Check a drive to see if it is a CD-ROM */
  69 static int CheckDrive(char *drive, struct stat *stbuf)
     /* [<][>][^][v][top][bottom][index][help] */
  70 {
  71         int is_cd, cdfd;
  72         struct ioc_read_subchannel info;
  73 
  74         /* If it doesn't exist, return -1 */
  75         if ( stat(drive, stbuf) < 0 ) {
  76                 return(-1);
  77         }
  78 
  79         /* If it does exist, verify that it's an available CD-ROM */
  80         is_cd = 0;
  81         if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
  82                 cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
  83                 if ( cdfd >= 0 ) {
  84                         info.address_format = CD_MSF_FORMAT;
  85                         info.data_format = CD_CURRENT_POSITION;
  86                         info.data_len = 0;
  87                         info.data = NULL;
  88                         /* Under Linux, EIO occurs when a disk is not present.
  89                            This isn't 100% reliable, so we use the USE_MNTENT
  90                            code above instead.
  91                          */
  92                         if ( (ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) ||
  93                                                 ERRNO_TRAYEMPTY(errno) ) {
  94                                 is_cd = 1;
  95                         }
  96                         close(cdfd);
  97                 }
  98         }
  99         return(is_cd);
 100 }
 101 
 102 /* Add a CD-ROM drive to our list of valid drives */
 103 static void AddDrive(char *drive, struct stat *stbuf)
     /* [<][>][^][v][top][bottom][index][help] */
 104 {
 105         int i;
 106 
 107         if ( SDL_numcds < MAX_DRIVES ) {
 108                 /* Check to make sure it's not already in our list.
 109                    This can happen when we see a drive via symbolic link.
 110                  */
 111                 for ( i=0; i<SDL_numcds; ++i ) {
 112                         if ( stbuf->st_rdev == SDL_cdmode[i] ) {
 113 #ifdef DEBUG_CDROM
 114   fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
 115 #endif
 116                                 return;
 117                         }
 118                 }
 119 
 120                 /* Add this drive to our list */
 121                 i = SDL_numcds;
 122                 SDL_cdlist[i] = (char *)malloc(strlen(drive)+1);
 123                 if ( SDL_cdlist[i] == NULL ) {
 124                         SDL_OutOfMemory();
 125                         return;
 126                 }
 127                 strcpy(SDL_cdlist[i], drive);
 128                 SDL_cdmode[i] = stbuf->st_rdev;
 129                 ++SDL_numcds;
 130 #ifdef DEBUG_CDROM
 131   fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
 132 #endif
 133         }
 134 }
 135 
 136 int  SDL_SYS_CDInit(void)
     /* [<][>][^][v][top][bottom][index][help] */
 137 {
 138         /* checklist: /dev/cdrom,/dev/cd?c /dev/acd?c
 139                         /dev/matcd?c /dev/mcd?c /dev/scd?c */
 140         static char *checklist[] = {
 141         "cdrom", "?0 cd?", "?0 acd?", "?0 matcd?", "?0 mcd?", "?0 scd?",NULL
 142         };
 143         char *SDLcdrom;
 144         int i, j, exists;
 145         char drive[32];
 146         struct stat stbuf;
 147 
 148         /* Fill in our driver capabilities */
 149         SDL_CDcaps.Name = SDL_SYS_CDName;
 150         SDL_CDcaps.Open = SDL_SYS_CDOpen;
 151         SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
 152         SDL_CDcaps.Status = SDL_SYS_CDStatus;
 153         SDL_CDcaps.Play = SDL_SYS_CDPlay;
 154         SDL_CDcaps.Pause = SDL_SYS_CDPause;
 155         SDL_CDcaps.Resume = SDL_SYS_CDResume;
 156         SDL_CDcaps.Stop = SDL_SYS_CDStop;
 157         SDL_CDcaps.Eject = SDL_SYS_CDEject;
 158         SDL_CDcaps.Close = SDL_SYS_CDClose;
 159 
 160         /* Look in the environment for our CD-ROM drive list */
 161         SDLcdrom = getenv("SDL_CDROM"); /* ':' separated list of devices */
 162         if ( SDLcdrom != NULL ) {
 163                 char *cdpath, *delim;
 164                 cdpath = malloc(strlen(SDLcdrom)+1);
 165                 if ( cdpath != NULL ) {
 166                         strcpy(cdpath, SDLcdrom);
 167                         SDLcdrom = cdpath;
 168                         do {
 169                                 delim = strchr(SDLcdrom, ':');
 170                                 if ( delim ) {
 171                                         *delim++ = '\0';
 172                                 }
 173                                 if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) {
 174                                         AddDrive(SDLcdrom, &stbuf);
 175                                 }
 176                                 if ( delim ) {
 177                                         SDLcdrom = delim;
 178                                 } else {
 179                                         SDLcdrom = NULL;
 180                                 }
 181                         } while ( SDLcdrom );
 182                         free(cdpath);
 183                 }
 184 
 185                 /* If we found our drives, there's nothing left to do */
 186                 if ( SDL_numcds > 0 ) {
 187                         return(0);
 188                 }
 189         }
 190 
 191         /* Scan the system for CD-ROM drives */
 192         for ( i=0; checklist[i]; ++i ) {
 193                 if ( checklist[i][0] == '?' ) {
 194                         char *insert;
 195                         exists = 1;
 196                         for ( j=checklist[i][1]; exists; ++j ) {
 197                                 sprintf(drive, "/dev/%sc", &checklist[i][3]);
 198                                 insert = strchr(drive, '?');
 199                                 if ( insert != NULL ) {
 200                                         *insert = j;
 201                                 }
 202                                 switch (CheckDrive(drive, &stbuf)) {
 203                                         /* Drive exists and is a CD-ROM */
 204                                         case 1:
 205                                                 AddDrive(drive, &stbuf);
 206                                                 break;
 207                                         /* Drive exists, but isn't a CD-ROM */
 208                                         case 0:
 209                                                 break;
 210                                         /* Drive doesn't exist */
 211                                         case -1:
 212                                                 exists = 0;
 213                                                 break;
 214                                 }
 215                         }
 216                 } else {
 217                         sprintf(drive, "/dev/%s", checklist[i]);
 218                         if ( CheckDrive(drive, &stbuf) > 0 ) {
 219                                 AddDrive(drive, &stbuf);
 220                         }
 221                 }
 222         }
 223         return(0);
 224 }
 225 
 226 /* General ioctl() CD-ROM command function */
 227 static int SDL_SYS_CDioctl(int id, int command, void *arg)
     /* [<][>][^][v][top][bottom][index][help] */
 228 {
 229         int retval;
 230 
 231         retval = ioctl(id, command, arg);
 232         if ( retval < 0 ) {
 233                 SDL_SetError("ioctl() error: %s", strerror(errno));
 234         }
 235         return(retval);
 236 }
 237 
 238 static const char *SDL_SYS_CDName(int drive)
     /* [<][>][^][v][top][bottom][index][help] */
 239 {
 240         return(SDL_cdlist[drive]);
 241 }
 242 
 243 static int SDL_SYS_CDOpen(int drive)
     /* [<][>][^][v][top][bottom][index][help] */
 244 {
 245         return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0));
 246 }
 247 
 248 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 249 {
 250         struct ioc_toc_header toc;
 251         int i, okay;
 252         struct ioc_read_toc_entry entry;
 253         struct cd_toc_entry data;
 254 
 255         okay = 0;
 256         if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0 ) {
 257                 cdrom->numtracks = toc.ending_track-toc.starting_track+1;
 258                 if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
 259                         cdrom->numtracks = SDL_MAX_TRACKS;
 260                 }
 261                 /* Read all the track TOC entries */
 262                 for ( i=0; i<=cdrom->numtracks; ++i ) {
 263                         if ( i == cdrom->numtracks ) {
 264                                 cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */
 265                         } else {
 266                                 cdrom->track[i].id = toc.starting_track+i;
 267                         }
 268                         entry.starting_track = cdrom->track[i].id;
 269                         entry.address_format = CD_MSF_FORMAT;
 270                         entry.data_len = sizeof(data);
 271                         entry.data = &data;
 272                         if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS,
 273                                                                 &entry) < 0 ) {
 274                                 break;
 275                         } else {
 276                                 cdrom->track[i].type = data.control;
 277                                 cdrom->track[i].offset = MSF_TO_FRAMES(
 278                                                 data.addr.msf.minute,
 279                                                 data.addr.msf.second,
 280                                                 data.addr.msf.frame);
 281                                 cdrom->track[i].length = 0;
 282                                 if ( i > 0 ) {
 283                                         cdrom->track[i-1].length =
 284                                                 cdrom->track[i].offset-
 285                                                 cdrom->track[i-1].offset;
 286                                 }
 287                         }
 288                 }
 289                 if ( i == (cdrom->numtracks+1) ) {
 290                         okay = 1;
 291                 }
 292         }
 293         return(okay ? 0 : -1);
 294 }
 295 
 296 /* Get CD-ROM status */
 297 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
     /* [<][>][^][v][top][bottom][index][help] */
 298 {
 299         CDstatus status;
 300         struct ioc_toc_header toc;
 301         struct ioc_read_subchannel info;
 302         struct cd_sub_channel_info data;
 303 
 304         info.address_format = CD_MSF_FORMAT;
 305         info.data_format = CD_CURRENT_POSITION;
 306         info.track = 0;
 307         info.data_len = sizeof(data);
 308         info.data = &data;
 309         if ( ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0 ) {
 310                 if ( ERRNO_TRAYEMPTY(errno) ) {
 311                         status = CD_TRAYEMPTY;
 312                 } else {
 313                         status = CD_ERROR;
 314                 }
 315         } else {
 316                 switch (data.header.audio_status) {
 317                         case CD_AS_AUDIO_INVALID:
 318                         case CD_AS_NO_STATUS:
 319                                 /* Try to determine if there's a CD available */
 320                                 if (ioctl(cdrom->id,CDIOREADTOCHEADER,&toc)==0)
 321                                         status = CD_STOPPED;
 322                                 else
 323                                         status = CD_TRAYEMPTY;
 324                                 break;
 325                         case CD_AS_PLAY_COMPLETED:
 326                                 status = CD_STOPPED;
 327                                 break;
 328                         case CD_AS_PLAY_IN_PROGRESS:
 329                                 status = CD_PLAYING;
 330                                 break;
 331                         case CD_AS_PLAY_PAUSED:
 332                                 status = CD_PAUSED;
 333                                 break;
 334                         default:
 335                                 status = CD_ERROR;
 336                                 break;
 337                 }
 338         }
 339         if ( position ) {
 340                 if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
 341                         *position = MSF_TO_FRAMES(
 342                                         data.what.position.absaddr.msf.minute,
 343                                         data.what.position.absaddr.msf.second,
 344                                         data.what.position.absaddr.msf.frame);
 345                 } else {
 346                         *position = 0;
 347                 }
 348         }
 349         return(status);
 350 }
 351 
 352 /* Start play */
 353 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
     /* [<][>][^][v][top][bottom][index][help] */
 354 {
 355         struct ioc_play_msf playtime;
 356 
 357         FRAMES_TO_MSF(start,
 358                 &playtime.start_m, &playtime.start_s, &playtime.start_f);
 359         FRAMES_TO_MSF(start+length,
 360                 &playtime.end_m, &playtime.end_s, &playtime.end_f);
 361 #ifdef DEBUG_CDROM
 362   fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
 363         playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
 364         playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
 365 #endif
 366         ioctl(cdrom->id, CDIOCSTART, 0);
 367         return(SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime));
 368 }
 369 
 370 /* Pause play */
 371 static int SDL_SYS_CDPause(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 372 {
 373         return(SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0));
 374 }
 375 
 376 /* Resume play */
 377 static int SDL_SYS_CDResume(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 378 {
 379         return(SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0));
 380 }
 381 
 382 /* Stop play */
 383 static int SDL_SYS_CDStop(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 384 {
 385         return(SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0));
 386 }
 387 
 388 /* Eject the CD-ROM */
 389 static int SDL_SYS_CDEject(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 390 {
 391         return(SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0));
 392 }
 393 
 394 /* Close the CD-ROM handle */
 395 static void SDL_SYS_CDClose(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 396 {
 397         close(cdrom->id);
 398 }
 399 
 400 void SDL_SYS_CDQuit(void)
     /* [<][>][^][v][top][bottom][index][help] */
 401 {
 402         int i;
 403 
 404         if ( SDL_numcds > 0 ) {
 405                 for ( i=0; i<SDL_numcds; ++i ) {
 406                         free(SDL_cdlist[i]);
 407                 }
 408                 SDL_numcds = 0;
 409         }
 410 }
 411 

/* [<][>][^][v][top][bottom][index][help] */