SDL_syscdrom.c revision 46be48730333120a7b939116cef075e61c12c703
1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Tru64 audio module for SDL (Simple DirectMedia Layer) 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Copyright (C) 2003 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This library is free software; you can redistribute it and/or 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown modify it under the terms of the GNU Library General Public 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown License as published by the Free Software Foundation; either 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown version 2 of the License, or (at your option) any later version. 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This library is distributed in the hope that it will be useful, 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown but WITHOUT ANY WARRANTY; without even the implied warranty of 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Library General Public License for more details. 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown You should have received a copy of the GNU Library General Public 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown License along with this library; if not, write to the Free 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 20*/ 21#include "SDL_config.h" 22 23#ifdef SDL_CDROM_OSF 24 25/* Functions for system-level CD-ROM audio control */ 26 27/* #define DEBUG_CDROM 1 */ 28 29#include <sys/types.h> 30#include <dirent.h> 31#include <sys/stat.h> 32#include <fcntl.h> 33#include <io/cam/cdrom.h> 34#include <io/cam/rzdisk.h> 35#include <io/common/devgetinfo.h> 36 37#include "SDL_cdrom.h" 38#include "../SDL_syscdrom.h" 39 40/* The maximum number of CD-ROM drives we'll detect */ 41#define MAX_DRIVES 16 42 43/* A list of available CD-ROM drives */ 44static char *SDL_cdlist[MAX_DRIVES]; 45static dev_t SDL_cdmode[MAX_DRIVES]; 46 47/* The system-dependent CD control functions */ 48static const char *SDL_SYS_CDName(int drive); 49static int SDL_SYS_CDOpen(int drive); 50static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); 51static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); 52static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); 53static int SDL_SYS_CDPause(SDL_CD *cdrom); 54static int SDL_SYS_CDResume(SDL_CD *cdrom); 55static int SDL_SYS_CDStop(SDL_CD *cdrom); 56static int SDL_SYS_CDEject(SDL_CD *cdrom); 57static void SDL_SYS_CDClose(SDL_CD *cdrom); 58 59/* Check a drive to see if it is a CD-ROM */ 60/* Caution!! Not tested. */ 61static int CheckDrive(char *drive, struct stat *stbuf) 62{ 63 int cdfd, is_cd = 0; 64 struct mode_sel_sns_params msp; 65 struct inquiry_info inq; 66 67#ifdef DEBUG_CDROM 68 char *devtype[] = {"Disk", "Tape", "Printer", "Processor", "WORM", 69 "CD-ROM", "Scanner", "Optical", "Changer", "Comm", "Unknown"}; 70#endif 71 72 bzero(&msp, sizeof(msp)); 73 bzero(&inq, sizeof(inq)); 74 75 /* If it doesn't exist, return -1 */ 76 if ( stat(drive, stbuf) < 0 ) { 77 return(-1); 78 } 79 80 if ( (cdfd = open(drive, (O_RDWR|O_NDELAY), 0)) >= 0 ) { 81 msp.msp_addr = (caddr_t) &inq; 82 msp.msp_pgcode = 0; 83 msp.msp_pgctrl = 0; 84 msp.msp_length = sizeof(inq); 85 msp.msp_setps = 0; 86 87 if ( ioctl(cdfd, SCSI_GET_INQUIRY_DATA, &msp) ) 88 return (0); 89 90#ifdef DEBUG_CDROM 91 fprintf(stderr, "Device Type: %s\n", devtype[inq.perfdt]); 92 fprintf(stderr, "Vendor: %.8s\n", inq.vndrid); 93 fprintf(stderr, "Product: %.8s\n", inq.prodid); 94 fprintf(stderr, "Revision: %.8s\n", inq.revlvl); 95#endif 96 if ( inq.perfdt == DTYPE_RODIRECT ) 97 is_cd = 1; 98 } 99 100 return(is_cd); 101} 102 103/* Add a CD-ROM drive to our list of valid drives */ 104static void AddDrive(char *drive, struct stat *stbuf) 105{ 106 int i; 107 108 if ( SDL_numcds < MAX_DRIVES ) { 109 /* Check to make sure it's not already in our list. 110 * This can happen when we see a drive via symbolic link. 111 * 112 */ 113 for ( i=0; i<SDL_numcds; ++i ) { 114 if ( stbuf->st_rdev == SDL_cdmode[i] ) { 115#ifdef DEBUG_CDROM 116 fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); 117#endif 118 return; 119 } 120 } 121 122 /* Add this drive to our list */ 123 i = SDL_numcds; 124 SDL_cdlist[i] = SDL_strdup(drive); 125 if ( SDL_cdlist[i] == NULL ) { 126 SDL_OutOfMemory(); 127 return; 128 } 129 SDL_cdmode[i] = stbuf->st_rdev; 130 ++SDL_numcds; 131#ifdef DEBUG_CDROM 132 fprintf(stderr, "Added CD-ROM drive: %s\n", drive); 133#endif 134 } 135} 136 137int SDL_SYS_CDInit(void) 138{ 139 /* checklist: 140 * 141 * Tru64 5.X (/dev/rdisk/cdrom?c) 142 * dir: /dev/rdisk, name: cdrom 143 * 144 * Digital UNIX 4.0X (/dev/rrz?c) 145 * dir: /dev, name: rrz 146 * 147 */ 148 struct { 149 char *dir; 150 char *name; 151 } checklist[] = { 152 {"/dev/rdisk", "cdrom"}, 153 {"/dev", "rrz"}, 154 {NULL, NULL}}; 155 char drive[32]; 156 char *SDLcdrom; 157 int i, j, exists; 158 struct stat stbuf; 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 173 /* Look in the environment for our CD-ROM drive list */ 174 SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ 175 if ( SDLcdrom != NULL ) { 176 char *cdpath, *delim; 177 size_t len = SDL_strlen(SDLcdrom)+1; 178 cdpath = SDL_stack_alloc(char, len); 179 if ( cdpath != NULL ) { 180 SDL_strlcpy(cdpath, SDLcdrom, len); 181 SDLcdrom = cdpath; 182 do { 183 delim = SDL_strchr(SDLcdrom, ':'); 184 if ( delim ) { 185 *delim++ = '\0'; 186 } 187 if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) { 188 AddDrive(SDLcdrom, &stbuf); 189 } 190 if ( delim ) { 191 SDLcdrom = delim; 192 } else { 193 SDLcdrom = NULL; 194 } 195 } while ( SDLcdrom ); 196 SDL_stack_free(cdpath); 197 } 198 199 /* If we found our drives, there's nothing left to do */ 200 if ( SDL_numcds > 0 ) { 201 return(0); 202 } 203 } 204 /* Scan the system for CD-ROM drives */ 205 for ( i = 0; checklist[i].dir; ++i) { 206 DIR *devdir; 207 struct dirent *devent; 208 int name_len; 209 210 devdir = opendir(checklist[i].dir); 211 if (devdir) { 212 name_len = SDL_strlen(checklist[i].name); 213 while (devent = readdir(devdir)) 214 if (SDL_memcmp(checklist[i].name, devent->d_name, name_len) == 0) 215 if (devent->d_name[devent->d_namlen-1] == 'c') { 216 SDL_snprintf(drive, SDL_arraysize(drive), "%s/%s", checklist[i].dir, devent->d_name); 217#ifdef DEBUG_CDROM 218 fprintf(stderr, "Try to add drive: %s\n", drive); 219#endif 220 if ( CheckDrive(drive, &stbuf) > 0 ) 221 AddDrive(drive, &stbuf); 222 } 223 closedir(devdir); 224 } else { 225#ifdef DEBUG_CDROM 226 fprintf(stderr, "cannot open dir: %s\n", checklist[i].dir); 227#endif 228 } 229 } 230 return (0); 231} 232 233static const char *SDL_SYS_CDName(int drive) 234{ 235 return(SDL_cdlist[drive]); 236} 237 238static int SDL_SYS_CDOpen(int drive) 239{ 240 /* O_RDWR: To use ioctl(fd, SCSI_STOP_UNIT) */ 241 return(open(SDL_cdlist[drive], (O_RDWR|O_NDELAY), 0)); 242} 243 244static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) 245{ 246 struct cd_toc toc; 247 struct cd_toc_header hdr; 248 struct cd_toc_entry *cdte; 249 int i; 250 int okay = 0; 251 if ( ioctl(cdrom->id, CDROM_TOC_HEADER, &hdr) ) { 252 fprintf(stderr,"ioctl error CDROM_TOC_HEADER\n"); 253 return -1; 254 } 255 cdrom->numtracks = hdr.th_ending_track - hdr.th_starting_track + 1; 256 if ( cdrom->numtracks > SDL_MAX_TRACKS ) { 257 cdrom->numtracks = SDL_MAX_TRACKS; 258 } 259#ifdef DEBUG_CDROM 260 fprintf(stderr,"hdr.th_data_len1 = %d\n", hdr.th_data_len1); 261 fprintf(stderr,"hdr.th_data_len0 = %d\n", hdr.th_data_len0); 262 fprintf(stderr,"hdr.th_starting_track = %d\n", hdr.th_starting_track); 263 fprintf(stderr,"hdr.th_ending_track = %d\n", hdr.th_ending_track); 264 fprintf(stderr,"cdrom->numtracks = %d\n", cdrom->numtracks); 265#endif 266 toc.toc_address_format = CDROM_LBA_FORMAT; 267 toc.toc_starting_track = 0; 268 toc.toc_alloc_length = (hdr.th_data_len1 << 8) + 269 hdr.th_data_len0 + sizeof(hdr); 270 if ( (toc.toc_buffer = alloca(toc.toc_alloc_length)) == NULL) { 271 fprintf(stderr,"cannot allocate toc.toc_buffer\n"); 272 return -1; 273 } 274 275 bzero (toc.toc_buffer, toc.toc_alloc_length); 276 if (ioctl(cdrom->id, CDROM_TOC_ENTRYS, &toc)) { 277 fprintf(stderr,"ioctl error CDROM_TOC_ENTRYS\n"); 278 return -1; 279 } 280 281 cdte =(struct cd_toc_entry *) ((char *) toc.toc_buffer + sizeof(hdr)); 282 for (i=0; i <= cdrom->numtracks; ++i) { 283 if (i == cdrom->numtracks ) { 284 cdrom->track[i].id = 0xAA;; 285 } else { 286 cdrom->track[i].id = hdr.th_starting_track + i; 287 } 288 289 cdrom->track[i].type = 290 cdte[i].te_control & CDROM_DATA_TRACK; 291 cdrom->track[i].offset = 292 cdte[i].te_absaddr.lba.addr3 << 24 | 293 cdte[i].te_absaddr.lba.addr2 << 16 | 294 cdte[i].te_absaddr.lba.addr1 << 8 | 295 cdte[i].te_absaddr.lba.addr0; 296 cdrom->track[i].length = 0; 297 if ( i > 0 ) { 298 cdrom->track[i - 1].length = 299 cdrom->track[i].offset - 300 cdrom->track[i - 1].offset; 301 } 302 } 303#ifdef DEBUG_CDROM 304 for (i = 0; i <= cdrom->numtracks; i++) { 305 fprintf(stderr,"toc_entry[%d].te_track_number = %d\n", 306 i,cdte[i].te_track_number); 307 fprintf(stderr,"cdrom->track[%d].id = %d\n", i,cdrom->track[i].id); 308 fprintf(stderr,"cdrom->track[%d].type = %x\n", i,cdrom->track[i].type); 309 fprintf(stderr,"cdrom->track[%d].offset = %d\n", i,cdrom->track[i].offset); 310 fprintf(stderr,"cdrom->track[%d].length = %d\n", i,cdrom->track[i].length); 311 } 312#endif 313 if ( i == (cdrom->numtracks+1) ) { 314 okay = 1; 315 } 316 317 return(okay ? 0 : -1); 318} 319 320/* Get CD-ROM status */ 321static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) 322{ 323 CDstatus status; 324 struct cd_sub_channel sc; 325 struct cd_subc_channel_data scd; 326 327 sc.sch_address_format = CDROM_LBA_FORMAT; 328 sc.sch_data_format = CDROM_CURRENT_POSITION; 329 sc.sch_track_number = 0; 330 sc.sch_alloc_length = sizeof(scd); 331 sc.sch_buffer = (caddr_t)&scd; 332 if ( ioctl(cdrom->id, CDROM_READ_SUBCHANNEL, &sc) ) { 333 status = CD_ERROR; 334 fprintf(stderr,"ioctl error CDROM_READ_SUBCHANNEL \n"); 335 } else { 336 switch (scd.scd_header.sh_audio_status) { 337 case AS_AUDIO_INVALID: 338 status = CD_STOPPED; 339 break; 340 case AS_PLAY_IN_PROGRESS: 341 status = CD_PLAYING; 342 break; 343 case AS_PLAY_PAUSED: 344 status = CD_PAUSED; 345 break; 346 case AS_PLAY_COMPLETED: 347 status = CD_STOPPED; 348 break; 349 case AS_PLAY_ERROR: 350 status = CD_ERROR; 351 break; 352 case AS_NO_STATUS: 353 status = CD_STOPPED; 354 break; 355 default: 356 status = CD_ERROR; 357 break; 358 } 359#ifdef DEBUG_CDROM 360 fprintf(stderr,"scd.scd_header.sh_audio_status = %x\n", 361 scd.scd_header.sh_audio_status); 362#endif 363 } 364 if (position) { 365 if (status == CD_PLAYING || (status == CD_PAUSED) ) { 366 *position = 367 scd.scd_position_data.scp_absaddr.lba.addr3 << 24 | 368 scd.scd_position_data.scp_absaddr.lba.addr2 << 16 | 369 scd.scd_position_data.scp_absaddr.lba.addr1 << 8 | 370 scd.scd_position_data.scp_absaddr.lba.addr0; 371 } else { 372 *position = 0; 373 } 374 } 375 376 return status; 377} 378 379/* Start play */ 380static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) 381{ 382/* 383 * Play MSF 384 */ 385 struct cd_play_audio_msf msf; 386 int end; 387 388 bzero(&msf, sizeof(msf)); 389 end = start +length; 390 FRAMES_TO_MSF(start + 150, /* LBA = 4500*M + 75*S + F - 150 */ 391 &msf.msf_starting_M_unit, 392 &msf.msf_starting_S_unit, 393 &msf.msf_starting_F_unit); 394 FRAMES_TO_MSF(end + 150, /* LBA = 4500*M + 75*S + F - 150 */ 395 &msf.msf_ending_M_unit, 396 &msf.msf_ending_S_unit, 397 &msf.msf_ending_F_unit); 398 399 return(ioctl(cdrom->id, CDROM_PLAY_AUDIO_MSF, &msf)); 400} 401 402/* Pause play */ 403static int SDL_SYS_CDPause(SDL_CD *cdrom) 404{ 405 return(ioctl(cdrom->id, CDROM_PAUSE_PLAY)); 406} 407 408/* Resume play */ 409static int SDL_SYS_CDResume(SDL_CD *cdrom) 410{ 411 return(ioctl(cdrom->id, CDROM_RESUME_PLAY)); 412} 413 414/* Stop play */ 415static int SDL_SYS_CDStop(SDL_CD *cdrom) 416{ 417 return(ioctl(cdrom->id, SCSI_STOP_UNIT)); 418} 419 420/* Eject the CD-ROM */ 421static int SDL_SYS_CDEject(SDL_CD *cdrom) 422{ 423 return(ioctl(cdrom->id, CDROM_EJECT_CADDY)); 424} 425 426/* Close the CD-ROM handle */ 427static void SDL_SYS_CDClose(SDL_CD *cdrom) 428{ 429 close(cdrom->id); 430} 431 432void SDL_SYS_CDQuit(void) 433{ 434 int i; 435 436 if ( SDL_numcds > 0 ) { 437 for ( i=0; i<SDL_numcds; ++i ) { 438 SDL_free(SDL_cdlist[i]); 439 } 440 SDL_numcds = 0; 441 } 442} 443 444#endif /* SDL_CDROM_OSF */ 445