src/cdrom/beos/SDL_syscdrom.cc
author Sam Lantinga <slouken@libsdl.org>
Sun, 29 Oct 2006 14:45:46 +0000
changeset 2063 dea73e1d07b0
parent 1895 c121d94672cb
child 2669 e27bdcc80744
permissions -rw-r--r--
Merged Ryan's fix, in case we need it later.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #ifdef SDL_CDROM_BEOS
    25 
    26 /* Functions for system-level CD-ROM audio control on BeOS
    27    (not completely implemented yet)
    28  */
    29 
    30 #include <sys/types.h>
    31 #include <sys/stat.h>
    32 #include <unistd.h>
    33 
    34 #include <scsi.h>
    35 #include <Directory.h>
    36 #include <Entry.h>
    37 #include <Path.h>
    38 
    39 #include "SDL_cdrom.h"
    40 extern "C"
    41 {
    42 #include "../SDL_syscdrom.h"
    43 }
    44 
    45 /* Constants to help us get at the SCSI table-of-contents info */
    46 #define CD_NUMTRACKS(toc)	toc.toc_data[3]
    47 #define CD_TRACK(toc, track)	(&toc.toc_data[6+(track)*8])
    48 #define CD_TRACK_N(toc, track)	CD_TRACK(toc, track)[0]
    49 #define CD_TRACK_M(toc, track)	CD_TRACK(toc, track)[3]
    50 #define CD_TRACK_S(toc, track)	CD_TRACK(toc, track)[4]
    51 #define CD_TRACK_F(toc, track)	CD_TRACK(toc, track)[5]
    52 
    53 /* Constants to help us get at the SCSI position info */
    54 #define POS_TRACK(pos)	pos.position[6]
    55 #define POS_ABS_M(pos)	pos.position[9]
    56 #define POS_ABS_S(pos)	pos.position[10]
    57 #define POS_ABS_F(pos)	pos.position[11]
    58 #define POS_REL_M(pos)	pos.position[13]
    59 #define POS_REL_S(pos)	pos.position[14]
    60 #define POS_REL_F(pos)	pos.position[15]
    61 
    62 /* The maximum number of CD-ROM drives we'll detect */
    63 #define MAX_DRIVES	16
    64 
    65 /* A list of available CD-ROM drives */
    66 static char *SDL_cdlist[MAX_DRIVES];
    67 
    68 /* The system-dependent CD control functions */
    69 static const char *SDL_SYS_CDName(int drive);
    70 static int SDL_SYS_CDOpen(int drive);
    71 static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
    72 static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
    73 static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
    74 static int SDL_SYS_CDPause(SDL_CD * cdrom);
    75 static int SDL_SYS_CDResume(SDL_CD * cdrom);
    76 static int SDL_SYS_CDStop(SDL_CD * cdrom);
    77 static int SDL_SYS_CDEject(SDL_CD * cdrom);
    78 static void SDL_SYS_CDClose(SDL_CD * cdrom);
    79 int try_dir(const char *directory);
    80 
    81 
    82 /* Check a drive to see if it is a CD-ROM */
    83 static int
    84 CheckDrive(char *drive)
    85 {
    86     struct stat stbuf;
    87     int is_cd, cdfd;
    88     device_geometry info;
    89 
    90     /* If it doesn't exist, return -1 */
    91     if (stat(drive, &stbuf) < 0) {
    92         return (-1);
    93     }
    94 
    95     /* If it does exist, verify that it's an available CD-ROM */
    96     is_cd = 0;
    97     cdfd = open(drive, 0);
    98     if (cdfd >= 0) {
    99         if (ioctl(cdfd, B_GET_GEOMETRY, &info) == B_NO_ERROR) {
   100             if (info.device_type == B_CD) {
   101                 is_cd = 1;
   102             }
   103         }
   104         close(cdfd);
   105     } else {
   106         /* This can happen when the drive is open .. (?) */ ;
   107         is_cd = 1;
   108     }
   109     return (is_cd);
   110 }
   111 
   112 /* Add a CD-ROM drive to our list of valid drives */
   113 static void
   114 AddDrive(char *drive)
   115 {
   116     int i;
   117     size_t len;
   118 
   119     if (SDL_numcds < MAX_DRIVES) {
   120         /* Add this drive to our list */
   121         i = SDL_numcds;
   122         len = SDL_strlen(drive) + 1;
   123         SDL_cdlist[i] = (char *) SDL_malloc(len);
   124         if (SDL_cdlist[i] == NULL) {
   125             SDL_OutOfMemory();
   126             return;
   127         }
   128         SDL_strlcpy(SDL_cdlist[i], drive, len);
   129         ++SDL_numcds;
   130 #ifdef CDROM_DEBUG
   131         fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
   132 #endif
   133     }
   134 }
   135 
   136 /* IDE bus scanning magic */
   137 enum
   138 {
   139     IDE_GET_DEVICES_INFO = B_DEVICE_OP_CODES_END + 50,
   140 };
   141 struct ide_ctrl_info
   142 {
   143     bool ide_0_present;
   144     bool ide_0_master_present;
   145     bool ide_0_slave_present;
   146     int ide_0_master_type;
   147     int ide_0_slave_type;
   148     bool ide_1_present;
   149     bool ide_1_master_present;
   150     bool ide_1_slave_present;
   151     int ide_1_master_type;
   152     int ide_1_slave_type;
   153 };
   154 
   155 int
   156 SDL_SYS_CDInit(void)
   157 {
   158     char *SDLcdrom;
   159     int raw_fd;
   160     struct ide_ctrl_info info;
   161 
   162     /* Fill in our driver capabilities */
   163     SDL_CDcaps.Name = SDL_SYS_CDName;
   164     SDL_CDcaps.Open = SDL_SYS_CDOpen;
   165     SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
   166     SDL_CDcaps.Status = SDL_SYS_CDStatus;
   167     SDL_CDcaps.Play = SDL_SYS_CDPlay;
   168     SDL_CDcaps.Pause = SDL_SYS_CDPause;
   169     SDL_CDcaps.Resume = SDL_SYS_CDResume;
   170     SDL_CDcaps.Stop = SDL_SYS_CDStop;
   171     SDL_CDcaps.Eject = SDL_SYS_CDEject;
   172     SDL_CDcaps.Close = SDL_SYS_CDClose;
   173 
   174     /* Look in the environment for our CD-ROM drive list */
   175     SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
   176     if (SDLcdrom != NULL) {
   177         char *cdpath, *delim;
   178         size_t len = SDL_strlen(SDLcdrom) + 1;
   179         cdpath = SDL_stack_alloc(char, len);
   180         if (cdpath != NULL) {
   181             SDL_strlcpy(cdpath, SDLcdrom, len);
   182             SDLcdrom = cdpath;
   183             do {
   184                 delim = SDL_strchr(SDLcdrom, ':');
   185                 if (delim) {
   186                     *delim++ = '\0';
   187                 }
   188                 if (CheckDrive(SDLcdrom) > 0) {
   189                     AddDrive(SDLcdrom);
   190                 }
   191                 if (delim) {
   192                     SDLcdrom = delim;
   193                 } else {
   194                     SDLcdrom = NULL;
   195                 }
   196             }
   197             while (SDLcdrom);
   198             SDL_stack_free(cdpath);
   199         }
   200 
   201         /* If we found our drives, there's nothing left to do */
   202         if (SDL_numcds > 0) {
   203             return (0);
   204         }
   205     }
   206 
   207     /* Scan the system for CD-ROM drives */
   208     try_dir("/dev/disk");
   209     return 0;
   210 }
   211 
   212 
   213 int
   214 try_dir(const char *directory)
   215 {
   216     BDirectory dir;
   217     dir.SetTo(directory);
   218     if (dir.InitCheck() != B_NO_ERROR) {
   219         return false;
   220     }
   221     dir.Rewind();
   222     BEntry entry;
   223     while (dir.GetNextEntry(&entry) >= 0) {
   224         BPath path;
   225         const char *name;
   226         entry_ref e;
   227 
   228         if (entry.GetPath(&path) != B_NO_ERROR)
   229             continue;
   230         name = path.Path();
   231 
   232         if (entry.GetRef(&e) != B_NO_ERROR)
   233             continue;
   234 
   235         if (entry.IsDirectory()) {
   236             if (SDL_strcmp(e.name, "floppy") == 0)
   237                 continue;       /* ignore floppy (it is not silent)  */
   238             int devfd = try_dir(name);
   239             if (devfd >= 0)
   240                 return devfd;
   241         } else {
   242             int devfd;
   243             device_geometry g;
   244 
   245             if (SDL_strcmp(e.name, "raw") != 0)
   246                 continue;       /* ignore partitions */
   247 
   248             devfd = open(name, O_RDONLY);
   249             if (devfd < 0)
   250                 continue;
   251 
   252             if (ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) {
   253                 if (g.device_type == B_CD) {
   254                     AddDrive(strdup(name));
   255                 }
   256             }
   257             close(devfd);
   258         }
   259     }
   260     return B_ERROR;
   261 }
   262 
   263 
   264 /* General ioctl() CD-ROM command function */
   265 static int
   266 SDL_SYS_CDioctl(int index, int command, void *arg)
   267 {
   268     int okay;
   269     int fd;
   270 
   271     okay = 0;
   272     fd = open(SDL_cdlist[index], 0);
   273     if (fd >= 0) {
   274         if (ioctl(fd, command, arg) == B_NO_ERROR) {
   275             okay = 1;
   276         }
   277         close(fd);
   278     }
   279     return (okay ? 0 : -1);
   280 }
   281 
   282 static const char *
   283 SDL_SYS_CDName(int drive)
   284 {
   285     return (SDL_cdlist[drive]);
   286 }
   287 
   288 static int
   289 SDL_SYS_CDOpen(int drive)
   290 {
   291     return (drive);
   292 }
   293 
   294 static int
   295 SDL_SYS_CDGetTOC(SDL_CD * cdrom)
   296 {
   297     int i;
   298     scsi_toc toc;
   299 
   300     if (SDL_SYS_CDioctl(cdrom->id, B_SCSI_GET_TOC, &toc) == 0) {
   301         cdrom->numtracks = CD_NUMTRACKS(toc);
   302         if (cdrom->numtracks > SDL_MAX_TRACKS) {
   303             cdrom->numtracks = SDL_MAX_TRACKS;
   304         }
   305         for (i = 0; i <= cdrom->numtracks; ++i) {
   306             cdrom->track[i].id = CD_TRACK_N(toc, i);
   307             /* FIXME:  How do we tell on BeOS? */
   308             cdrom->track[i].type = SDL_AUDIO_TRACK;
   309             cdrom->track[i].offset = MSF_TO_FRAMES(CD_TRACK_M(toc, i),
   310                                                    CD_TRACK_S(toc, i),
   311                                                    CD_TRACK_F(toc, i));
   312             cdrom->track[i].length = 0;
   313             if (i > 0) {
   314                 cdrom->track[i - 1].length =
   315                     cdrom->track[i].offset - cdrom->track[i - 1].offset;
   316             }
   317         }
   318         return (0);
   319     } else {
   320         return (-1);
   321     }
   322 }
   323 
   324 /* Get CD-ROM status */
   325 static CDstatus
   326 SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
   327 {
   328     CDstatus status;
   329     int fd;
   330     int cur_frame;
   331     scsi_position pos;
   332 
   333     fd = open(SDL_cdlist[cdrom->id], 0);
   334     cur_frame = 0;
   335     if (fd >= 0) {
   336         if (ioctl(fd, B_SCSI_GET_POSITION, &pos) == B_NO_ERROR) {
   337             cur_frame =
   338                 MSF_TO_FRAMES(POS_ABS_M(pos), POS_ABS_S(pos), POS_ABS_F(pos));
   339         }
   340         if (!pos.position[1] || (pos.position[1] >= 0x13) ||
   341             ((pos.position[1] == 0x12) && (!pos.position[6]))) {
   342             status = CD_STOPPED;
   343         } else if (pos.position[1] == 0x11) {
   344             status = CD_PLAYING;
   345         } else {
   346             status = CD_PAUSED;
   347         }
   348         close(fd);
   349     } else {
   350         status = CD_TRAYEMPTY;
   351     }
   352     if (position) {
   353         *position = cur_frame;
   354     }
   355     return (status);
   356 }
   357 
   358 /* Start play */
   359 static int
   360 SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
   361 {
   362     int okay;
   363     int fd;
   364     scsi_play_position pos;
   365 
   366     okay = 0;
   367     fd = open(SDL_cdlist[cdrom->id], 0);
   368     if (fd >= 0) {
   369         FRAMES_TO_MSF(start, &pos.start_m, &pos.start_s, &pos.start_f);
   370         FRAMES_TO_MSF(start + length, &pos.end_m, &pos.end_s, &pos.end_f);
   371         if (ioctl(fd, B_SCSI_PLAY_POSITION, &pos) == B_NO_ERROR) {
   372             okay = 1;
   373         }
   374         close(fd);
   375     }
   376     return (okay ? 0 : -1);
   377 }
   378 
   379 /* Pause play */
   380 static int
   381 SDL_SYS_CDPause(SDL_CD * cdrom)
   382 {
   383     return (SDL_SYS_CDioctl(cdrom->id, B_SCSI_PAUSE_AUDIO, 0));
   384 }
   385 
   386 /* Resume play */
   387 static int
   388 SDL_SYS_CDResume(SDL_CD * cdrom)
   389 {
   390     return (SDL_SYS_CDioctl(cdrom->id, B_SCSI_RESUME_AUDIO, 0));
   391 }
   392 
   393 /* Stop play */
   394 static int
   395 SDL_SYS_CDStop(SDL_CD * cdrom)
   396 {
   397     return (SDL_SYS_CDioctl(cdrom->id, B_SCSI_STOP_AUDIO, 0));
   398 }
   399 
   400 /* Eject the CD-ROM */
   401 static int
   402 SDL_SYS_CDEject(SDL_CD * cdrom)
   403 {
   404     return (SDL_SYS_CDioctl(cdrom->id, B_SCSI_EJECT, 0));
   405 }
   406 
   407 /* Close the CD-ROM handle */
   408 static void
   409 SDL_SYS_CDClose(SDL_CD * cdrom)
   410 {
   411     close(cdrom->id);
   412 }
   413 
   414 void
   415 SDL_SYS_CDQuit(void)
   416 {
   417     int i;
   418 
   419     if (SDL_numcds > 0) {
   420         for (i = 0; i < SDL_numcds; ++i) {
   421             SDL_free(SDL_cdlist[i]);
   422         }
   423         SDL_numcds = 0;
   424     }
   425 }
   426 
   427 #endif /* SDL_CDROM_BEOS */
   428 /* vi: set ts=4 sw=4 expandtab: */