comparison src/cdrom/osf/SDL_syscdrom.c @ 654:e92bcf2573cb

Added audio and CD-ROM support for OSF/Tru64 (thanks Hayashi!)
author Sam Lantinga <slouken@libsdl.org>
date Tue, 22 Jul 2003 14:01:21 +0000
parents
children 89666943c598
comparison
equal deleted inserted replaced
653:1bd056de5d1b 654:e92bcf2573cb
1 /*
2 Tru64 audio module for SDL (Simple DirectMedia Layer)
3 Copyright (C) 2003
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
20 */
21
22
23 /* Functions for system-level CD-ROM audio control */
24
25 //#define DEBUG_CDROM 1
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <io/cam/cdrom.h>
31 #include <io/cam/rzdisk.h>
32 #include <io/common/devgetinfo.h>
33 #include <alloca.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38
39 #include "SDL_error.h"
40 #include "SDL_cdrom.h"
41 #include "SDL_syscdrom.h"
42
43 /* The maximum number of CD-ROM drives we'll detect */
44 #define MAX_DRIVES 16
45
46 /* A list of available CD-ROM drives */
47 static char *SDL_cdlist[MAX_DRIVES];
48 static dev_t SDL_cdmode[MAX_DRIVES];
49
50 /* The system-dependent CD control functions */
51 static const char *SDL_SYS_CDName(int drive);
52 static int SDL_SYS_CDOpen(int drive);
53 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
54 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
55 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
56 static int SDL_SYS_CDPause(SDL_CD *cdrom);
57 static int SDL_SYS_CDResume(SDL_CD *cdrom);
58 static int SDL_SYS_CDStop(SDL_CD *cdrom);
59 static int SDL_SYS_CDEject(SDL_CD *cdrom);
60 static void SDL_SYS_CDClose(SDL_CD *cdrom);
61
62 /* Some ioctl() errno values which occur when the tray is empty */
63 #define ERRNO_TRAYEMPTY(errno) \
64 ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL))
65
66 /* Check a drive to see if it is a CD-ROM */
67 /* Caution!! Not tested. */
68 static int CheckDrive(char *drive, struct stat *stbuf)
69 {
70 int is_cd, cdfd;
71 struct cd_sub_channel info;
72
73 /* If it doesn't exist, return -1 */
74 if ( stat(drive, stbuf) < 0 ) {
75 return(-1);
76 }
77
78 /* If it does exist, verify that it's an available CD-ROM */
79 is_cd = 0;
80 if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
81 cdfd = open(drive, (O_RDWR|O_NDELAY), 0);
82 if ( cdfd >= 0 ) {
83 info.sch_address_format = CDROM_MSF_FORMAT;
84 info.sch_data_format = CDROM_CURRENT_POSITION;
85 info.sch_alloc_length = 0;
86 info.sch_track_number = 0;
87 info.sch_buffer = NULL;
88 /*
89 *
90 * Under Linux, EIO occurs when a disk is not present.
91 * This isn't 100% reliable, so we use the USE_MNTENT
92 * code above instead.
93 *
94 */
95 if ( (ioctl(cdfd, CDROM_READ_SUBCHANNEL, &info) == 0) ||
96 ERRNO_TRAYEMPTY(errno) ) {
97 is_cd = 1;
98 }
99
100 close(cdfd);
101 }
102 }
103
104 return(is_cd);
105 }
106
107 /* Add a CD-ROM drive to our list of valid drives */
108 static void AddDrive(char *drive, struct stat *stbuf)
109 {
110 int i;
111
112 if ( SDL_numcds < MAX_DRIVES ) {
113 /* Check to make sure it's not already in our list.
114 * This can happen when we see a drive via symbolic link.
115 *
116 * /
117 for ( i=0; i<SDL_numcds; ++i ) {
118 if ( stbuf->st_rdev == SDL_cdmode[i] ) {
119 #ifdef DEBUG_CDROM
120 fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
121 #endif
122 return;
123 }
124 }
125
126 /* Add this drive to our list */
127 i = SDL_numcds;
128 SDL_cdlist[i] = (char *)malloc(strlen(drive)+1);
129 if ( SDL_cdlist[i] == NULL ) {
130 SDL_OutOfMemory();
131 return;
132 }
133
134 strcpy(SDL_cdlist[i], drive);
135 SDL_cdmode[i] = stbuf->st_rdev;
136 ++SDL_numcds;
137 #ifdef DEBUG_CDROM
138 fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
139 #endif
140 }
141 }
142
143 int SDL_SYS_CDInit(void)
144 {
145 /* checklist: /dev/cdrom,/dev/cd?c /dev/acd?c
146 * /dev/matcd?c /dev/mcd?c /dev/scd?c
147 *
148 */
149 static char *checklist[] = {
150 "?0 rdisk/cdrom?",NULL};
151 char drive[32];
152 char *SDLcdrom;
153 int i, j, exists;
154 struct stat stbuf;
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
169 /* Look in the environment for our CD-ROM drive list */
170 SDLcdrom = getenv("SDL_CDROM"); /* ':' separated list of devices */
171 if ( SDLcdrom != NULL ) {
172 char *cdpath, *delim;
173 cdpath = malloc(strlen(SDLcdrom)+1);
174 if ( cdpath != NULL ) {
175 strcpy(cdpath, SDLcdrom);
176 SDLcdrom = cdpath;
177 do {
178 delim = strchr(SDLcdrom, ':');
179 if ( delim ) {
180 *delim++ = '\0';
181 }
182 if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) {
183 AddDrive(SDLcdrom, &stbuf);
184 }
185 if ( delim ) {
186 SDLcdrom = delim;
187 } else {
188 SDLcdrom = NULL;
189 }
190 } while ( SDLcdrom );
191 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 /* Scan the system for CD-ROM drives */
200 for ( i=0; checklist[i]; ++i ) {
201 if ( checklist[i][0] == '?' ) {
202 char *insert;
203 exists = 1;
204 for ( j=checklist[i][1]; exists; ++j ) {
205 sprintf(drive, "/dev/%sc", &checklist[i][3]);
206 insert = strchr(drive, '?');
207 if ( insert != NULL ) {
208 *insert = j;
209 }
210 switch (CheckDrive(drive, &stbuf)) {
211 /* Drive exists and is a CD-ROM */
212 case 1:
213 AddDrive(drive, &stbuf);
214 break;
215 /* Drive exists, but isn't a CD-ROM */
216 case 0:
217 break;
218 /* Drive doesn't exist */
219 case -1:
220 exists = 0;
221 break;
222 }
223 }
224 } else {
225 sprintf(drive, "/dev/%s", checklist[i]);
226 if ( CheckDrive(drive, &stbuf) > 0 ) {
227 AddDrive(drive, &stbuf);
228 }
229 }
230 }
231 /*
232 SDLcdrom=malloc(sizeof(char) * 32);
233 strcpy(SDLcdrom,"/dev/rdisk/cdrom0c");
234 SDL_cdlist[0] = SDLcdrom;
235 stat(SDLcdrom, &stbuf);
236 SDL_cdmode[0] = stbuf.st_rdev;
237 SDL_numcds = 1;
238 */
239 return (0);
240 }
241
242 static const char *SDL_SYS_CDName(int drive)
243 {
244 return(SDL_cdlist[drive]);
245 }
246
247 static int SDL_SYS_CDOpen(int drive)
248 {
249 /* O_RDWR: To use ioctl(fd, SCSI_STOP_UNIT) */
250 return(open(SDL_cdlist[drive], (O_RDWR|O_NDELAY), 0));
251 }
252
253 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
254 {
255 struct cd_toc toc;
256 struct cd_toc_header hdr;
257 struct cd_toc_entry *cdte;
258 int i;
259 int okay = 0;
260 if ( ioctl(cdrom->id, CDROM_TOC_HEADER, &hdr) ) {
261 fprintf(stderr,"ioctl error CDROM_TOC_HEADER\n");
262 return -1;
263 }
264 cdrom->numtracks = hdr.th_ending_track - hdr.th_starting_track + 1;
265 if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
266 cdrom->numtracks = SDL_MAX_TRACKS;
267 }
268 #ifdef DEBUG_CDROM
269 fprintf(stderr,"hdr.th_data_len1 = %d\n", hdr.th_data_len1);
270 fprintf(stderr,"hdr.th_data_len0 = %d\n", hdr.th_data_len0);
271 fprintf(stderr,"hdr.th_starting_track = %d\n", hdr.th_starting_track);
272 fprintf(stderr,"hdr.th_ending_track = %d\n", hdr.th_ending_track);
273 fprintf(stderr,"cdrom->numtracks = %d\n", cdrom->numtracks);
274 #endif
275 toc.toc_address_format = CDROM_LBA_FORMAT;
276 toc.toc_starting_track = 0;
277 toc.toc_alloc_length = (hdr.th_data_len1 << 8) +
278 hdr.th_data_len0 + sizeof(hdr);
279 if ( (toc.toc_buffer = alloca(toc.toc_alloc_length)) == NULL) {
280 fprintf(stderr,"cannot allocate toc.toc_buffer\n");
281 return -1;
282 }
283
284 bzero (toc.toc_buffer, toc.toc_alloc_length);
285 if (ioctl(cdrom->id, CDROM_TOC_ENTRYS, &toc)) {
286 fprintf(stderr,"ioctl error CDROM_TOC_ENTRYS\n");
287 return -1;
288 }
289
290 (char *)cdte = toc.toc_buffer + sizeof(hdr);
291 for (i=0; i <= cdrom->numtracks; ++i) {
292 if (i == cdrom->numtracks ) {
293 cdrom->track[i].id = 0xAA;;
294 } else {
295 cdrom->track[i].id = hdr.th_starting_track + i;
296 }
297
298 cdrom->track[i].type =
299 cdte[i].te_control & CDROM_DATA_TRACK;
300 cdrom->track[i].offset =
301 cdte[i].te_absaddr.lba.addr3 << 24 |
302 cdte[i].te_absaddr.lba.addr2 << 16 |
303 cdte[i].te_absaddr.lba.addr1 << 8 |
304 cdte[i].te_absaddr.lba.addr0;
305 cdrom->track[i].length = 0;
306 if ( i > 0 ) {
307 cdrom->track[i - 1].length =
308 cdrom->track[i].offset -
309 cdrom->track[i - 1].offset;
310 }
311 }
312 #ifdef DEBUG_CDROM
313 for (i = 0; i <= cdrom->numtracks; i++) {
314 fprintf(stderr,"toc_entry[%d].te_track_number = %d\n",
315 i,cdte[i].te_track_number);
316 fprintf(stderr,"cdrom->track[%d].id = %d\n", i,cdrom->track[i].id);
317 fprintf(stderr,"cdrom->track[%d].type = %x\n", i,cdrom->track[i].type);
318 fprintf(stderr,"cdrom->track[%d].offset = %d\n", i,cdrom->track[i].offset);
319 fprintf(stderr,"cdrom->track[%d].length = %d\n", i,cdrom->track[i].length);
320 }
321 #endif
322 if ( i == (cdrom->numtracks+1) ) {
323 okay = 1;
324 }
325
326 return(okay ? 0 : -1);
327 }
328
329 /* Get CD-ROM status */
330 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
331 {
332 CDstatus status;
333 struct cd_sub_channel sc;
334 struct cd_subc_channel_data scd;
335
336 sc.sch_address_format = CDROM_LBA_FORMAT;
337 sc.sch_data_format = CDROM_CURRENT_POSITION;
338 sc.sch_track_number = 0;
339 sc.sch_alloc_length = sizeof(scd);
340 sc.sch_buffer = (caddr_t)&scd;
341 if ( ioctl(cdrom->id, CDROM_READ_SUBCHANNEL, &sc) ) {
342 status = CD_ERROR;
343 fprintf(stderr,"ioctl error CDROM_READ_SUBCHANNEL \n");
344 } else {
345 switch (scd.scd_header.sh_audio_status) {
346 case AS_AUDIO_INVALID:
347 status = CD_STOPPED;
348 break;
349 case AS_PLAY_IN_PROGRESS:
350 status = CD_PLAYING;
351 break;
352 case AS_PLAY_PAUSED:
353 status = CD_PAUSED;
354 break;
355 case AS_PLAY_COMPLETED:
356 status = CD_STOPPED;
357 break;
358 case AS_PLAY_ERROR:
359 status = CD_ERROR;
360 break;
361 case AS_NO_STATUS:
362 status = CD_STOPPED;
363 break;
364 default:
365 status = CD_ERROR;
366 break;
367 }
368 #ifdef DEBUG_CDROM
369 fprintf(stderr,"scd.scd_header.sh_audio_status = %x\n",
370 scd.scd_header.sh_audio_status);
371 #endif
372 }
373 if (position) {
374 if (status == CD_PLAYING || (status == CD_PAUSED) ) {
375 *position =
376 scd.scd_position_data.scp_absaddr.lba.addr3 << 24 |
377 scd.scd_position_data.scp_absaddr.lba.addr2 << 16 |
378 scd.scd_position_data.scp_absaddr.lba.addr1 << 8 |
379 scd.scd_position_data.scp_absaddr.lba.addr0;
380 } else {
381 *position = 0;
382 }
383 }
384
385 return status;
386 }
387
388 /* Start play */
389 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
390 {
391 /* Play MSF
392 *
393 */
394 struct cd_play_audio_msf msf;
395 int end;
396
397 bzero(&msf, sizeof(msf));
398 end = start +length;
399 FRAMES_TO_MSF(start,
400 &msf.msf_starting_M_unit,
401 &msf.msf_starting_S_unit,
402 &msf.msf_starting_F_unit);
403 FRAMES_TO_MSF(end,
404 &msf.msf_ending_M_unit,
405 &msf.msf_ending_S_unit,
406 &msf.msf_ending_F_unit);
407
408 return(ioctl(cdrom->id, CDROM_PLAY_AUDIO_MSF, &msf));
409 }
410
411 /* Pause play */
412 static int SDL_SYS_CDPause(SDL_CD *cdrom)
413 {
414 return(ioctl(cdrom->id, CDROM_PAUSE_PLAY));
415 }
416
417 /* Resume play */
418 static int SDL_SYS_CDResume(SDL_CD *cdrom)
419 {
420 return(ioctl(cdrom->id, CDROM_RESUME_PLAY));
421 }
422
423 /* Stop play */
424 static int SDL_SYS_CDStop(SDL_CD *cdrom)
425 {
426 return(ioctl(cdrom->id, SCSI_STOP_UNIT));
427 }
428
429 /* Eject the CD-ROM */
430 static int SDL_SYS_CDEject(SDL_CD *cdrom)
431 {
432 return(ioctl(cdrom->id, CDROM_EJECT_CADDY));
433 }
434
435 /* Close the CD-ROM handle */
436 static void SDL_SYS_CDClose(SDL_CD *cdrom)
437 {
438 close(cdrom->id);
439 }
440
441 void SDL_SYS_CDQuit(void)
442 {
443 int i;
444
445 if ( SDL_numcds > 0 ) {
446 for ( i=0; i<SDL_numcds; ++i ) {
447 free(SDL_cdlist[i]);
448 }
449 SDL_numcds = 0;
450 }
451 }
452
453