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