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