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

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