15b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey/* 25b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey SDL - Simple DirectMedia Layer 35b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey Copyright (C) 1997-2012 Sam Lantinga 45b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 55b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey This library is free software; you can redistribute it and/or 65b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey modify it under the terms of the GNU Lesser General Public 75b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey License as published by the Free Software Foundation; either 85b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey version 2.1 of the License, or (at your option) any later version. 95b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 105b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey This library is distributed in the hope that it will be useful, 115b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey but WITHOUT ANY WARRANTY; without even the implied warranty of 125b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 135b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey Lesser General Public License for more details. 145b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 155b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey You should have received a copy of the GNU Lesser General Public 165b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey License along with this library; if not, write to the Free Software 175b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 185b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 195b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey Sam Lantinga 205b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey slouken@libsdl.org 215b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey*/ 225b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#include "SDL_config.h" 235b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 245b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#ifdef SDL_CDROM_BSDI 255b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 265b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey/* 275b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey * Functions for system-level CD-ROM audio control for BSD/OS 4.x 285b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey * This started life out as a copy of the freebsd/SDL_cdrom.c file but was 295b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey * heavily modified. Works for standard (MMC) SCSI and ATAPI CDrom drives. 3073fbfc38792bd96137d5b6ae3016dfc4d9805d46Jeff Sharkey * 3173fbfc38792bd96137d5b6ae3016dfc4d9805d46Jeff Sharkey * Steven Schultz - sms@to.gd-es.com 3273fbfc38792bd96137d5b6ae3016dfc4d9805d46Jeff Sharkey*/ 3373fbfc38792bd96137d5b6ae3016dfc4d9805d46Jeff Sharkey 3473fbfc38792bd96137d5b6ae3016dfc4d9805d46Jeff Sharkey#include <sys/types.h> 355b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#include <sys/stat.h> 365b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#include <fcntl.h> 375b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#include <err.h> 385b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#include <unistd.h> 395b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#include <sys/ioctl.h> 405b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#include </sys/dev/scsi/scsi.h> 415b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#include </sys/dev/scsi/scsi_ioctl.h> 425b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 435b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#include "SDL_cdrom.h" 445b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#include "../SDL_syscdrom.h" 455b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 465b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey/* 475b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey * The msf_to_frame and frame_to_msf were yanked from libcdrom and inlined 485b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey * here so that -lcdrom doesn't have to be dragged in for something so simple. 495b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey*/ 505b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 515b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#define FRAMES_PER_SECOND 75 525b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#define FRAMES_PER_MINUTE (FRAMES_PER_SECOND * 60) 535b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 545b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeyint 555b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeymsf_to_frame(int minute, int second, int frame) 565b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey { 575b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey return(minute * FRAMES_PER_MINUTE + second * FRAMES_PER_SECOND + frame); 585b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey } 595b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 605b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeyvoid 615b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeyframe_to_msf(int frame, int *minp, int *secp, int *framep) 625b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey { 635b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey *minp = frame / FRAMES_PER_MINUTE; 645b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey *secp = (frame % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND; 655b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey *framep = frame % FRAMES_PER_SECOND; 665b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey } 675b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 685b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey/* The maximum number of CD-ROM drives we'll detect */ 695b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#define MAX_DRIVES 16 705b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 715b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey/* A list of available CD-ROM drives */ 725b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic char *SDL_cdlist[MAX_DRIVES]; 735b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic dev_t SDL_cdmode[MAX_DRIVES]; 745b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 755b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey/* The system-dependent CD control functions */ 765b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic const char *SDL_SYS_CDName(int drive); 775b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic int SDL_SYS_CDOpen(int drive); 785b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic int SDL_SYS_CDGetTOC(SDL_CD *cdrom); 795b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); 805b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); 815b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic int SDL_SYS_CDPause(SDL_CD *cdrom); 825b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic int SDL_SYS_CDResume(SDL_CD *cdrom); 835b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic int SDL_SYS_CDStop(SDL_CD *cdrom); 845b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic int SDL_SYS_CDEject(SDL_CD *cdrom); 855b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic void SDL_SYS_CDClose(SDL_CD *cdrom); 865b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 875b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeytypedef struct scsi_cdb cdb_t; 885b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 895b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic int scsi_cmd(int fd, 905b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey struct scsi_cdb *cdb, 915b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey int cdblen, 925b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey int rw, 935b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey caddr_t data, 945b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey int datalen, 9573fbfc38792bd96137d5b6ae3016dfc4d9805d46Jeff Sharkey struct scsi_user_cdb *sus) 9673fbfc38792bd96137d5b6ae3016dfc4d9805d46Jeff Sharkey { 975b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey int scsistatus; 985b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey unsigned char *cp; 9973fbfc38792bd96137d5b6ae3016dfc4d9805d46Jeff Sharkey struct scsi_user_cdb suc; 1005b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 1015b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey /* safety checks */ 1025b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if (!cdb) return(-1); 1035b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if (rw != SUC_READ && rw != SUC_WRITE) return(-1); 1045b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 1055b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey suc.suc_flags = rw; 1065b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey suc.suc_cdblen = cdblen; 1075b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey bcopy(cdb, suc.suc_cdb, cdblen); 1085b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey suc.suc_datalen = datalen; 1095b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey suc.suc_data = data; 1105b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey suc.suc_timeout = 10; /* 10 secs max for TUR or SENSE */ 1115b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if (ioctl(fd, SCSIRAWCDB, &suc) == -1) 1125b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey return(-11); 1135b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey scsistatus = suc.suc_sus.sus_status; 1145b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey cp = suc.suc_sus.sus_sense; 1155b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 1165b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey/* 1175b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey * If a place to copy the sense data back to has been provided then the 1185b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey * caller is responsible for checking the errors and printing any information 1195b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey * out if the status was not successful. 1205b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey*/ 1215b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if (scsistatus != 0 && !sus) 1225b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey { 1235b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey fprintf(stderr,"scsistatus = %x cmd = %x\n", 1245b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey scsistatus, cdb[0]); 1255b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey fprintf(stderr, "sense %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", 1265b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], 1275b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey cp[6], cp[7], cp[8], cp[9], cp[10], cp[11], 1285b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey cp[12], cp[13], cp[14], cp[15]); 1295b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey return(1); 1305b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey } 1315b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if (sus) 1325b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey bcopy(&suc, sus, sizeof (struct scsi_user_cdb)); 1335b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if (scsistatus) 1345b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey return(1); /* Return non-zero for unsuccessful status */ 1355b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey return(0); 1365b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey } 1375b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 1385b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey/* request vendor brand and model */ 1395b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeyunsigned char *Inquiry(int fd) 1405b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey { 1415b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey static struct scsi_cdb6 cdb = 1425b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey { 1435b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 0x12, 1445b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 0, 0, 0, 1455b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 56, 1465b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 0 1475b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey }; 1485b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey static unsigned char Inqbuffer[56]; 1495b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 1505b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if (scsi_cmd(fd, (cdb_t *)&cdb, 6, SUC_READ, Inqbuffer, 1515b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey sizeof(Inqbuffer), 0)) 1525b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey return("\377"); 1535b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey return(Inqbuffer); 1545b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey } 1555b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 1565b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#define ADD_SENSECODE 12 1575b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey#define ADD_SC_QUALIFIER 13 1585b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 1595b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeyint TestForMedium(int fd) 1605b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey { 1615b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey int sts, asc, ascq; 1625b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey struct scsi_user_cdb sus; 1635b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey static struct scsi_cdb6 cdb = 1645b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey { 1655b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey CMD_TEST_UNIT_READY, /* command */ 1665b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 0, /* reserved */ 1675b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 0, /* reserved */ 1685b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 0, /* reserved */ 1695b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 0, /* reserved */ 1705b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 0 /* reserved */ 17173fbfc38792bd96137d5b6ae3016dfc4d9805d46Jeff Sharkey }; 1725b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 1735b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeyagain: sts = scsi_cmd(fd, (cdb_t *)&cdb, 6, SUC_READ, 0, 0, &sus); 1745b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey asc = sus.suc_sus.sus_sense[ADD_SENSECODE]; 1755b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey ascq = sus.suc_sus.sus_sense[ADD_SC_QUALIFIER]; 1765b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if (asc == 0x3a && ascq == 0x0) /* no medium */ 17773fbfc38792bd96137d5b6ae3016dfc4d9805d46Jeff Sharkey return(0); 1785b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if (asc == 0x28 && ascq == 0x0) /* medium changed */ 1795b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey goto again; 1805b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if (asc == 0x4 && ascq == 0x1 ) /* coming ready */ 1815b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey { 1825b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey sleep(2); 1835b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey goto again; 1845b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey } 1855b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey return(1); 1865b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey } 1875b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 1885b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey/* Check a drive to see if it is a CD-ROM */ 1895b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkeystatic int CheckDrive(char *drive, struct stat *stbuf) 1905b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey{ 1915b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey int is_cd = 0, cdfd; 1925b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey char *p; 1935b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey 1945b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey /* If it doesn't exist, return -1 */ 1955b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey if ( stat(drive, stbuf) < 0 ) { 1965b78a3aa7741c3f44b676ccffa765cecee1cbd4cJeff Sharkey return(-1); 197 } 198 199 /* If it does exist, verify that it's an available CD-ROM */ 200 cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); 201 if ( cdfd >= 0 ) { 202 p = Inquiry(cdfd); 203 if (*p == TYPE_ROM) 204 is_cd = 1; 205 close(cdfd); 206 } 207 return(is_cd); 208} 209 210/* Add a CD-ROM drive to our list of valid drives */ 211static void AddDrive(char *drive, struct stat *stbuf) 212{ 213 int i; 214 215 if ( SDL_numcds < MAX_DRIVES ) { 216 /* Check to make sure it's not already in our list. 217 This can happen when we see a drive via symbolic link. 218 */ 219 for ( i=0; i<SDL_numcds; ++i ) { 220 if ( stbuf->st_rdev == SDL_cdmode[i] ) { 221#ifdef DEBUG_CDROM 222 fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); 223#endif 224 return; 225 } 226 } 227 228 /* Add this drive to our list */ 229 i = SDL_numcds; 230 SDL_cdlist[i] = SDL_strdup(drive); 231 if ( SDL_cdlist[i] == NULL ) { 232 SDL_OutOfMemory(); 233 return; 234 } 235 SDL_cdmode[i] = stbuf->st_rdev; 236 ++SDL_numcds; 237#ifdef DEBUG_CDROM 238 fprintf(stderr, "Added CD-ROM drive: %s\n", drive); 239#endif 240 } 241} 242 243int SDL_SYS_CDInit(void) 244{ 245 /* checklist: /dev/rsr?c */ 246 static char *checklist[] = { 247 "?0 rsr?", NULL 248 }; 249 char *SDLcdrom; 250 int i, j, exists; 251 char drive[32]; 252 struct stat stbuf; 253 254 /* Fill in our driver capabilities */ 255 SDL_CDcaps.Name = SDL_SYS_CDName; 256 SDL_CDcaps.Open = SDL_SYS_CDOpen; 257 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; 258 SDL_CDcaps.Status = SDL_SYS_CDStatus; 259 SDL_CDcaps.Play = SDL_SYS_CDPlay; 260 SDL_CDcaps.Pause = SDL_SYS_CDPause; 261 SDL_CDcaps.Resume = SDL_SYS_CDResume; 262 SDL_CDcaps.Stop = SDL_SYS_CDStop; 263 SDL_CDcaps.Eject = SDL_SYS_CDEject; 264 SDL_CDcaps.Close = SDL_SYS_CDClose; 265 266 /* Look in the environment for our CD-ROM drive list */ 267 SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ 268 if ( SDLcdrom != NULL ) { 269 char *cdpath, *delim; 270 size_t len = SDL_strlen(SDLcdrom)+1; 271 cdpath = SDL_stack_alloc(char, len); 272 if ( cdpath != NULL ) { 273 SDL_strlcpy(cdpath, SDLcdrom, len); 274 SDLcdrom = cdpath; 275 do { 276 delim = SDL_strchr(SDLcdrom, ':'); 277 if ( delim ) { 278 *delim++ = '\0'; 279 } 280 if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) { 281 AddDrive(SDLcdrom, &stbuf); 282 } 283 if ( delim ) { 284 SDLcdrom = delim; 285 } else { 286 SDLcdrom = NULL; 287 } 288 } while ( SDLcdrom ); 289 SDL_stack_free(cdpath); 290 } 291 292 /* If we found our drives, there's nothing left to do */ 293 if ( SDL_numcds > 0 ) { 294 return(0); 295 } 296 } 297 298 /* Scan the system for CD-ROM drives */ 299 for ( i=0; checklist[i]; ++i ) { 300 if ( checklist[i][0] == '?' ) { 301 char *insert; 302 exists = 1; 303 for ( j=checklist[i][1]; exists; ++j ) { 304 SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%sc", &checklist[i][3]); 305 insert = SDL_strchr(drive, '?'); 306 if ( insert != NULL ) { 307 *insert = j; 308 } 309 switch (CheckDrive(drive, &stbuf)) { 310 /* Drive exists and is a CD-ROM */ 311 case 1: 312 AddDrive(drive, &stbuf); 313 break; 314 /* Drive exists, but isn't a CD-ROM */ 315 case 0: 316 break; 317 /* Drive doesn't exist */ 318 case -1: 319 exists = 0; 320 break; 321 } 322 } 323 } else { 324 SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]); 325 if ( CheckDrive(drive, &stbuf) > 0 ) { 326 AddDrive(drive, &stbuf); 327 } 328 } 329 } 330 return(0); 331} 332 333static const char *SDL_SYS_CDName(int drive) 334{ 335 return(SDL_cdlist[drive]); 336} 337 338static int SDL_SYS_CDOpen(int drive) 339{ 340 return(open(SDL_cdlist[drive], O_RDONLY | O_NONBLOCK | O_EXCL, 0)); 341} 342 343static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) 344 { 345 u_char cdb[10], buf[4], *p, *toc; 346 struct scsi_user_cdb sus; 347 int i, sts, first_track, last_track, ntracks, toc_size; 348 349 bzero(cdb, sizeof (cdb)); 350 cdb[0] = 0x43; /* Read TOC */ 351 cdb[1] = 0x2; /* MSF */ 352 cdb[8] = 4; /* size TOC header */ 353 sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, buf, 4, &sus); 354 if (sts < 0) 355 return(-1); 356 first_track = buf[2]; 357 last_track = buf[3]; 358 ntracks = last_track - first_track + 1; 359 cdrom->numtracks = ntracks; 360 toc_size = 4 + (ntracks + 1) * 8; 361 toc = (u_char *)SDL_malloc(toc_size); 362 if (toc == NULL) 363 return(-1); 364 bzero(cdb, sizeof (cdb)); 365 cdb[0] = 0x43; 366 cdb[1] = 0x2; 367 cdb[6] = first_track; 368 cdb[7] = toc_size >> 8; 369 cdb[8] = toc_size & 0xff; 370 sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, toc, toc_size, 371 &sus); 372 if (sts < 0) 373 { 374 SDL_free(toc); 375 return(-1); 376 } 377 378 for (i = 0, p = toc+4; i <= ntracks; i++, p+= 8) 379 { 380 if (i == ntracks) 381 cdrom->track[i].id = 0xAA; /* Leadout */ 382 else 383 cdrom->track[i].id = first_track + i; 384 if (p[1] & 0x20) 385 cdrom->track[i].type = SDL_DATA_TRACK; 386 else 387 cdrom->track[i].type = SDL_AUDIO_TRACK; 388 cdrom->track[i].offset = msf_to_frame(p[5], p[6], p[7]); 389 cdrom->track[i].length = 0; 390 if (i > 0) 391 cdrom->track[i-1].length = cdrom->track[i].offset - 392 cdrom->track[i-1].offset; 393 } 394 SDL_free(toc); 395 return(0); 396 } 397 398/* Get CD-ROM status */ 399static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) 400 { 401 CDstatus status; 402 u_char cdb[10], buf[16]; 403 int sts; 404 struct scsi_user_cdb sus; 405 406 bzero(cdb, sizeof (cdb)); 407 cdb[0] = 0x42; /* read subq */ 408 cdb[1] = 0x2; /* MSF */ 409 cdb[2] = 0x40; /* q channel */ 410 cdb[3] = 1; /* current pos */ 411 cdb[7] = sizeof (buf) >> 8; 412 cdb[8] = sizeof (buf) & 0xff; 413 sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, buf, sizeof (buf), 414 &sus); 415 if (sts < 0) 416 return(-1); 417 if (sts) 418 { 419 if (TestForMedium(cdrom->id) == 0) 420 status = CD_TRAYEMPTY; 421 else 422 status = CD_ERROR; 423 } 424 else 425 { 426 switch (buf[1]) 427 { 428 case 0x11: 429 status = CD_PLAYING; 430 break; 431 case 0x12: 432 status = CD_PAUSED; 433 break; 434 case 0x13: 435 case 0x14: 436 case 0x15: 437 status = CD_STOPPED; 438 break; 439 default: 440 status = CD_ERROR; 441 break; 442 } 443 } 444 if (position) 445 { 446 if ( status == CD_PLAYING || (status == CD_PAUSED) ) 447 *position = msf_to_frame(buf[9], buf[10], buf[11]); 448 else 449 *position = 0; 450 } 451 return(status); 452 } 453 454/* Start play */ 455static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) 456 { 457 u_char cdb[10]; 458 int sts, minute, second, frame, eminute, esecond, eframe; 459 struct scsi_user_cdb sus; 460 461 bzero(cdb, sizeof(cdb)); 462 cdb[0] = 0x47; /* Play */ 463 frame_to_msf(start, &minute, &second, &frame); 464 frame_to_msf(start + length, &eminute, &esecond, &eframe); 465 cdb[3] = minute; 466 cdb[4] = second; 467 cdb[5] = frame; 468 cdb[6] = eminute; 469 cdb[7] = esecond; 470 cdb[8] = eframe; 471 sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, 0, 0, &sus); 472 return(sts); 473 } 474 475static int 476pauseresume(SDL_CD *cdrom, int flag) 477 { 478 u_char cdb[10]; 479 struct scsi_user_cdb sus; 480 481 bzero(cdb, sizeof (cdb)); 482 cdb[0] = 0x4b; 483 cdb[8] = flag & 0x1; 484 return(scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, 0, 0, &sus)); 485 } 486 487/* Pause play */ 488static int SDL_SYS_CDPause(SDL_CD *cdrom) 489{ 490 return(pauseresume(cdrom, 0)); 491} 492 493/* Resume play */ 494static int SDL_SYS_CDResume(SDL_CD *cdrom) 495{ 496 return(pauseresume(cdrom, 1)); 497} 498 499/* Stop play */ 500static int SDL_SYS_CDStop(SDL_CD *cdrom) 501{ 502 u_char cdb[6]; 503 struct scsi_user_cdb sus; 504 505 bzero(cdb, sizeof (cdb)); 506 cdb[0] = 0x1b; /* stop */ 507 cdb[1] = 1; /* immediate */ 508 return(scsi_cmd(cdrom->id, (cdb_t *)cdb, 6, SUC_READ, 0, 0, &sus)); 509} 510 511/* Eject the CD-ROM */ 512static int SDL_SYS_CDEject(SDL_CD *cdrom) 513{ 514 u_char cdb[6]; 515 struct scsi_user_cdb sus; 516 517 bzero(cdb, sizeof (cdb)); 518 cdb[0] = 0x1b; /* stop */ 519 cdb[1] = 1; /* immediate */ 520 cdb[4] = 2; /* eject */ 521 return(scsi_cmd(cdrom->id, (cdb_t *)cdb, 6, SUC_READ, 0, 0, &sus)); 522} 523 524/* Close the CD-ROM handle */ 525static void SDL_SYS_CDClose(SDL_CD *cdrom) 526 { 527 close(cdrom->id); 528 } 529 530void SDL_SYS_CDQuit(void) 531{ 532 int i; 533 534 if ( SDL_numcds > 0 ) { 535 for ( i=0; i<SDL_numcds; ++i ) { 536 SDL_free(SDL_cdlist[i]); 537 } 538 } 539 SDL_numcds = 0; 540} 541 542#endif /* SDL_CDROM_BSDI */ 543