1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 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 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 */ 411