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