view src/cdrom/beos/SDL_syscdrom.cc @ 1662:782fd950bd46 SDL-1.3

Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API. WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid. The code is now run through a consistent indent format: indent -i4 -nut -nsc -br -ce The headers are being converted to automatically generate doxygen documentation.
author Sam Lantinga <slouken@libsdl.org>
date Sun, 28 May 2006 13:04:16 +0000
parents 92947e3a18db
children 4da1ee79c9af
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2006 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org
*/
#include "SDL_config.h"

#ifdef SDL_CDROM_BEOS

/* Functions for system-level CD-ROM audio control on BeOS
   (not completely implemented yet)
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <scsi.h>
#include <Directory.h>
#include <Entry.h>
#include <Path.h>

#include "SDL_cdrom.h"
extern "C"
{
#include "../SDL_syscdrom.h"
}

/* Constants to help us get at the SCSI table-of-contents info */
#define CD_NUMTRACKS(toc)	toc.toc_data[3]
#define CD_TRACK(toc, track)	(&toc.toc_data[6+(track)*8])
#define CD_TRACK_N(toc, track)	CD_TRACK(toc, track)[0]
#define CD_TRACK_M(toc, track)	CD_TRACK(toc, track)[3]
#define CD_TRACK_S(toc, track)	CD_TRACK(toc, track)[4]
#define CD_TRACK_F(toc, track)	CD_TRACK(toc, track)[5]

/* Constants to help us get at the SCSI position info */
#define POS_TRACK(pos)	pos.position[6]
#define POS_ABS_M(pos)	pos.position[9]
#define POS_ABS_S(pos)	pos.position[10]
#define POS_ABS_F(pos)	pos.position[11]
#define POS_REL_M(pos)	pos.position[13]
#define POS_REL_S(pos)	pos.position[14]
#define POS_REL_F(pos)	pos.position[15]

/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES	16

/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];

/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName (int drive);
static int SDL_SYS_CDOpen (int drive);
static int SDL_SYS_CDGetTOC (SDL_CD * cdrom);
static CDstatus SDL_SYS_CDStatus (SDL_CD * cdrom, int *position);
static int SDL_SYS_CDPlay (SDL_CD * cdrom, int start, int length);
static int SDL_SYS_CDPause (SDL_CD * cdrom);
static int SDL_SYS_CDResume (SDL_CD * cdrom);
static int SDL_SYS_CDStop (SDL_CD * cdrom);
static int SDL_SYS_CDEject (SDL_CD * cdrom);
static void SDL_SYS_CDClose (SDL_CD * cdrom);
int try_dir (const char *directory);


/* Check a drive to see if it is a CD-ROM */
static int
CheckDrive (char *drive)
{
    struct stat stbuf;
    int is_cd, cdfd;
    device_geometry info;

    /* If it doesn't exist, return -1 */
    if (stat (drive, &stbuf) < 0) {
        return (-1);
    }

    /* If it does exist, verify that it's an available CD-ROM */
    is_cd = 0;
    cdfd = open (drive, 0);
    if (cdfd >= 0) {
        if (ioctl (cdfd, B_GET_GEOMETRY, &info) == B_NO_ERROR) {
            if (info.device_type == B_CD) {
                is_cd = 1;
            }
        }
        close (cdfd);
    } else {
        /* This can happen when the drive is open .. (?) */ ;
        is_cd = 1;
    }
    return (is_cd);
}

/* Add a CD-ROM drive to our list of valid drives */
static void
AddDrive (char *drive)
{
    int i;
    size_t len;

    if (SDL_numcds < MAX_DRIVES) {
        /* Add this drive to our list */
        i = SDL_numcds;
        len = SDL_strlen (drive) + 1;
        SDL_cdlist[i] = (char *) SDL_malloc (len);
        if (SDL_cdlist[i] == NULL) {
            SDL_OutOfMemory ();
            return;
        }
        SDL_strlcpy (SDL_cdlist[i], drive, len);
        ++SDL_numcds;
#ifdef CDROM_DEBUG
        fprintf (stderr, "Added CD-ROM drive: %s\n", drive);
#endif
    }
}

/* IDE bus scanning magic */
enum
{
    IDE_GET_DEVICES_INFO = B_DEVICE_OP_CODES_END + 50,
};
struct ide_ctrl_info
{
    bool ide_0_present;
    bool ide_0_master_present;
    bool ide_0_slave_present;
    int ide_0_master_type;
    int ide_0_slave_type;
    bool ide_1_present;
    bool ide_1_master_present;
    bool ide_1_slave_present;
    int ide_1_master_type;
    int ide_1_slave_type;
};

int
SDL_SYS_CDInit (void)
{
    char *SDLcdrom;
    int raw_fd;
    struct ide_ctrl_info info;

    /* Fill in our driver capabilities */
    SDL_CDcaps.Name = SDL_SYS_CDName;
    SDL_CDcaps.Open = SDL_SYS_CDOpen;
    SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
    SDL_CDcaps.Status = SDL_SYS_CDStatus;
    SDL_CDcaps.Play = SDL_SYS_CDPlay;
    SDL_CDcaps.Pause = SDL_SYS_CDPause;
    SDL_CDcaps.Resume = SDL_SYS_CDResume;
    SDL_CDcaps.Stop = SDL_SYS_CDStop;
    SDL_CDcaps.Eject = SDL_SYS_CDEject;
    SDL_CDcaps.Close = SDL_SYS_CDClose;

    /* Look in the environment for our CD-ROM drive list */
    SDLcdrom = SDL_getenv ("SDL_CDROM");        /* ':' separated list of devices */
    if (SDLcdrom != NULL) {
        char *cdpath, *delim;
        size_t len = SDL_strlen (SDLcdrom) + 1;
        cdpath = SDL_stack_alloc (char, len);
        if (cdpath != NULL) {
            SDL_strlcpy (cdpath, SDLcdrom, len);
            SDLcdrom = cdpath;
            do {
                delim = SDL_strchr (SDLcdrom, ':');
                if (delim) {
                    *delim++ = '\0';
                }
                if (CheckDrive (SDLcdrom) > 0) {
                    AddDrive (SDLcdrom);
                }
                if (delim) {
                    SDLcdrom = delim;
                } else {
                    SDLcdrom = NULL;
                }
            }
            while (SDLcdrom);
            SDL_stack_free (cdpath);
        }

        /* If we found our drives, there's nothing left to do */
        if (SDL_numcds > 0) {
            return (0);
        }
    }

    /* Scan the system for CD-ROM drives */
    try_dir ("/dev/disk");
    return 0;
}


int
try_dir (const char *directory)
{
    BDirectory dir;
    dir.SetTo (directory);
    if (dir.InitCheck () != B_NO_ERROR) {
        return false;
    }
    dir.Rewind ();
    BEntry entry;
    while (dir.GetNextEntry (&entry) >= 0) {
        BPath path;
        const char *name;
        entry_ref e;

        if (entry.GetPath (&path) != B_NO_ERROR)
            continue;
        name = path.Path ();

        if (entry.GetRef (&e) != B_NO_ERROR)
            continue;

        if (entry.IsDirectory ()) {
            if (SDL_strcmp (e.name, "floppy") == 0)
                continue;       /* ignore floppy (it is not silent)  */
            int devfd = try_dir (name);
            if (devfd >= 0)
                return devfd;
        } else {
            int devfd;
            device_geometry g;

            if (SDL_strcmp (e.name, "raw") != 0)
                continue;       /* ignore partitions */

            devfd = open (name, O_RDONLY);
            if (devfd < 0)
                continue;

            if (ioctl (devfd, B_GET_GEOMETRY, &g, sizeof (g)) >= 0) {
                if (g.device_type == B_CD) {
                    AddDrive (strdup (name));
                }
            }
            close (devfd);
        }
    }
    return B_ERROR;
}


/* General ioctl() CD-ROM command function */
static int
SDL_SYS_CDioctl (int index, int command, void *arg)
{
    int okay;
    int fd;

    okay = 0;
    fd = open (SDL_cdlist[index], 0);
    if (fd >= 0) {
        if (ioctl (fd, command, arg) == B_NO_ERROR) {
            okay = 1;
        }
        close (fd);
    }
    return (okay ? 0 : -1);
}

static const char *
SDL_SYS_CDName (int drive)
{
    return (SDL_cdlist[drive]);
}

static int
SDL_SYS_CDOpen (int drive)
{
    return (drive);
}

static int
SDL_SYS_CDGetTOC (SDL_CD * cdrom)
{
    int i;
    scsi_toc toc;

    if (SDL_SYS_CDioctl (cdrom->id, B_SCSI_GET_TOC, &toc) == 0) {
        cdrom->numtracks = CD_NUMTRACKS (toc);
        if (cdrom->numtracks > SDL_MAX_TRACKS) {
            cdrom->numtracks = SDL_MAX_TRACKS;
        }
        for (i = 0; i <= cdrom->numtracks; ++i) {
            cdrom->track[i].id = CD_TRACK_N (toc, i);
            /* FIXME:  How do we tell on BeOS? */
            cdrom->track[i].type = SDL_AUDIO_TRACK;
            cdrom->track[i].offset = MSF_TO_FRAMES (CD_TRACK_M (toc, i),
                                                    CD_TRACK_S (toc, i),
                                                    CD_TRACK_F (toc, i));
            cdrom->track[i].length = 0;
            if (i > 0) {
                cdrom->track[i - 1].length =
                    cdrom->track[i].offset - cdrom->track[i - 1].offset;
            }
        }
        return (0);
    } else {
        return (-1);
    }
}

/* Get CD-ROM status */
static CDstatus
SDL_SYS_CDStatus (SDL_CD * cdrom, int *position)
{
    CDstatus status;
    int fd;
    int cur_frame;
    scsi_position pos;

    fd = open (SDL_cdlist[cdrom->id], 0);
    cur_frame = 0;
    if (fd >= 0) {
        if (ioctl (fd, B_SCSI_GET_POSITION, &pos) == B_NO_ERROR) {
            cur_frame =
                MSF_TO_FRAMES (POS_ABS_M (pos), POS_ABS_S (pos),
                               POS_ABS_F (pos));
        }
        if (!pos.position[1] || (pos.position[1] >= 0x13) ||
            ((pos.position[1] == 0x12) && (!pos.position[6]))) {
            status = CD_STOPPED;
        } else if (pos.position[1] == 0x11) {
            status = CD_PLAYING;
        } else {
            status = CD_PAUSED;
        }
        close (fd);
    } else {
        status = CD_TRAYEMPTY;
    }
    if (position) {
        *position = cur_frame;
    }
    return (status);
}

/* Start play */
static int
SDL_SYS_CDPlay (SDL_CD * cdrom, int start, int length)
{
    int okay;
    int fd;
    scsi_play_position pos;

    okay = 0;
    fd = open (SDL_cdlist[cdrom->id], 0);
    if (fd >= 0) {
        FRAMES_TO_MSF (start, &pos.start_m, &pos.start_s, &pos.start_f);
        FRAMES_TO_MSF (start + length, &pos.end_m, &pos.end_s, &pos.end_f);
        if (ioctl (fd, B_SCSI_PLAY_POSITION, &pos) == B_NO_ERROR) {
            okay = 1;
        }
        close (fd);
    }
    return (okay ? 0 : -1);
}

/* Pause play */
static int
SDL_SYS_CDPause (SDL_CD * cdrom)
{
    return (SDL_SYS_CDioctl (cdrom->id, B_SCSI_PAUSE_AUDIO, 0));
}

/* Resume play */
static int
SDL_SYS_CDResume (SDL_CD * cdrom)
{
    return (SDL_SYS_CDioctl (cdrom->id, B_SCSI_RESUME_AUDIO, 0));
}

/* Stop play */
static int
SDL_SYS_CDStop (SDL_CD * cdrom)
{
    return (SDL_SYS_CDioctl (cdrom->id, B_SCSI_STOP_AUDIO, 0));
}

/* Eject the CD-ROM */
static int
SDL_SYS_CDEject (SDL_CD * cdrom)
{
    return (SDL_SYS_CDioctl (cdrom->id, B_SCSI_EJECT, 0));
}

/* Close the CD-ROM handle */
static void
SDL_SYS_CDClose (SDL_CD * cdrom)
{
    close (cdrom->id);
}

void
SDL_SYS_CDQuit (void)
{
    int i;

    if (SDL_numcds > 0) {
        for (i = 0; i < SDL_numcds; ++i) {
            SDL_free (SDL_cdlist[i]);
        }
        SDL_numcds = 0;
    }
}

#endif /* SDL_CDROM_BEOS */
/* vi: set ts=4 sw=4 expandtab: */