1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 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 (at) 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 int raw_fd; 154 struct ide_ctrl_info info; 155 156 /* Fill in our driver capabilities */ 157 SDL_CDcaps.Name = SDL_SYS_CDName; 158 SDL_CDcaps.Open = SDL_SYS_CDOpen; 159 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; 160 SDL_CDcaps.Status = SDL_SYS_CDStatus; 161 SDL_CDcaps.Play = SDL_SYS_CDPlay; 162 SDL_CDcaps.Pause = SDL_SYS_CDPause; 163 SDL_CDcaps.Resume = SDL_SYS_CDResume; 164 SDL_CDcaps.Stop = SDL_SYS_CDStop; 165 SDL_CDcaps.Eject = SDL_SYS_CDEject; 166 SDL_CDcaps.Close = SDL_SYS_CDClose; 167 168 /* Look in the environment for our CD-ROM drive list */ 169 SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ 170 if ( SDLcdrom != NULL ) { 171 char *cdpath, *delim; 172 size_t len = SDL_strlen(SDLcdrom)+1; 173 cdpath = SDL_stack_alloc(char, len); 174 if ( cdpath != NULL ) { 175 SDL_strlcpy(cdpath, SDLcdrom, len); 176 SDLcdrom = cdpath; 177 do { 178 delim = SDL_strchr(SDLcdrom, ':'); 179 if ( delim ) { 180 *delim++ = '\0'; 181 } 182 if ( CheckDrive(SDLcdrom) > 0 ) { 183 AddDrive(SDLcdrom); 184 } 185 if ( delim ) { 186 SDLcdrom = delim; 187 } else { 188 SDLcdrom = NULL; 189 } 190 } while ( SDLcdrom ); 191 SDL_stack_free(cdpath); 192 } 193 194 /* If we found our drives, there's nothing left to do */ 195 if ( SDL_numcds > 0 ) { 196 return(0); 197 } 198 } 199 200 /* Scan the system for CD-ROM drives */ 201 try_dir("/dev/disk"); 202 return 0; 203 } 204 205 206 int try_dir(const char *directory) 207 { 208 BDirectory dir; 209 dir.SetTo(directory); 210 if(dir.InitCheck() != B_NO_ERROR) { 211 return false; 212 } 213 dir.Rewind(); 214 BEntry entry; 215 while(dir.GetNextEntry(&entry) >= 0) { 216 BPath path; 217 const char *name; 218 entry_ref e; 219 220 if(entry.GetPath(&path) != B_NO_ERROR) 221 continue; 222 name = path.Path(); 223 224 if(entry.GetRef(&e) != B_NO_ERROR) 225 continue; 226 227 if(entry.IsDirectory()) { 228 if(SDL_strcmp(e.name, "floppy") == 0) 229 continue; /* ignore floppy (it is not silent) */ 230 int devfd = try_dir(name); 231 if(devfd >= 0) 232 return devfd; 233 } 234 else { 235 int devfd; 236 device_geometry g; 237 238 if(SDL_strcmp(e.name, "raw") != 0) 239 continue; /* ignore partitions */ 240 241 devfd = open(name, O_RDONLY); 242 if(devfd < 0) 243 continue; 244 245 if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) { 246 if(g.device_type == B_CD) 247 { 248 AddDrive(strdup(name)); 249 } 250 } 251 close(devfd); 252 } 253 } 254 return B_ERROR; 255 } 256 257 258 /* General ioctl() CD-ROM command function */ 259 static int SDL_SYS_CDioctl(int index, int command, void *arg) 260 { 261 int okay; 262 int fd; 263 264 okay = 0; 265 fd = open(SDL_cdlist[index], 0); 266 if ( fd >= 0 ) { 267 if ( ioctl(fd, command, arg) == B_NO_ERROR ) { 268 okay = 1; 269 } 270 close(fd); 271 } 272 return(okay ? 0 : -1); 273 } 274 275 static const char *SDL_SYS_CDName(int drive) 276 { 277 return(SDL_cdlist[drive]); 278 } 279 280 static int SDL_SYS_CDOpen(int drive) 281 { 282 return(drive); 283 } 284 285 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) 286 { 287 int i; 288 scsi_toc toc; 289 290 if ( SDL_SYS_CDioctl(cdrom->id, B_SCSI_GET_TOC, &toc) == 0 ) { 291 cdrom->numtracks = CD_NUMTRACKS(toc); 292 if ( cdrom->numtracks > SDL_MAX_TRACKS ) { 293 cdrom->numtracks = SDL_MAX_TRACKS; 294 } 295 for ( i=0; i<=cdrom->numtracks; ++i ) { 296 cdrom->track[i].id = CD_TRACK_N(toc, i); 297 /* FIXME: How do we tell on BeOS? */ 298 cdrom->track[i].type = SDL_AUDIO_TRACK; 299 cdrom->track[i].offset = MSF_TO_FRAMES( 300 CD_TRACK_M(toc, i), 301 CD_TRACK_S(toc, i), 302 CD_TRACK_F(toc, i)); 303 cdrom->track[i].length = 0; 304 if ( i > 0 ) { 305 cdrom->track[i-1].length = 306 cdrom->track[i].offset- 307 cdrom->track[i-1].offset; 308 } 309 } 310 return(0); 311 } else { 312 return(-1); 313 } 314 } 315 316 /* Get CD-ROM status */ 317 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) 318 { 319 CDstatus status; 320 int fd; 321 int cur_frame; 322 scsi_position pos; 323 324 fd = open(SDL_cdlist[cdrom->id], 0); 325 cur_frame = 0; 326 if ( fd >= 0 ) { 327 if ( ioctl(fd, B_SCSI_GET_POSITION, &pos) == B_NO_ERROR ) { 328 cur_frame = MSF_TO_FRAMES( 329 POS_ABS_M(pos), POS_ABS_S(pos), POS_ABS_F(pos)); 330 } 331 if ( ! pos.position[1] || (pos.position[1] >= 0x13) || 332 ((pos.position[1] == 0x12) && (!pos.position[6])) ) { 333 status = CD_STOPPED; 334 } else 335 if ( pos.position[1] == 0x11 ) { 336 status = CD_PLAYING; 337 } else { 338 status = CD_PAUSED; 339 } 340 close(fd); 341 } else { 342 status = CD_TRAYEMPTY; 343 } 344 if ( position ) { 345 *position = cur_frame; 346 } 347 return(status); 348 } 349 350 /* Start play */ 351 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) 352 { 353 int okay; 354 int fd; 355 scsi_play_position pos; 356 357 okay = 0; 358 fd = open(SDL_cdlist[cdrom->id], 0); 359 if ( fd >= 0 ) { 360 FRAMES_TO_MSF(start, &pos.start_m, &pos.start_s, &pos.start_f); 361 FRAMES_TO_MSF(start+length, &pos.end_m, &pos.end_s, &pos.end_f); 362 if ( ioctl(fd, B_SCSI_PLAY_POSITION, &pos) == B_NO_ERROR ) { 363 okay = 1; 364 } 365 close(fd); 366 } 367 return(okay ? 0 : -1); 368 } 369 370 /* Pause play */ 371 static int SDL_SYS_CDPause(SDL_CD *cdrom) 372 { 373 return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_PAUSE_AUDIO, 0)); 374 } 375 376 /* Resume play */ 377 static int SDL_SYS_CDResume(SDL_CD *cdrom) 378 { 379 return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_RESUME_AUDIO, 0)); 380 } 381 382 /* Stop play */ 383 static int SDL_SYS_CDStop(SDL_CD *cdrom) 384 { 385 return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_STOP_AUDIO, 0)); 386 } 387 388 /* Eject the CD-ROM */ 389 static int SDL_SYS_CDEject(SDL_CD *cdrom) 390 { 391 return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_EJECT, 0)); 392 } 393 394 /* Close the CD-ROM handle */ 395 static void SDL_SYS_CDClose(SDL_CD *cdrom) 396 { 397 close(cdrom->id); 398 } 399 400 void SDL_SYS_CDQuit(void) 401 { 402 int i; 403 404 if ( SDL_numcds > 0 ) { 405 for ( i=0; i<SDL_numcds; ++i ) { 406 SDL_free(SDL_cdlist[i]); 407 } 408 SDL_numcds = 0; 409 } 410 } 411 412 #endif /* SDL_CDROM_BEOS */ 413