comparison src/cdrom/qnx/SDL_syscdrom.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children e8157fcb3114
comparison
equal deleted inserted replaced
-1:000000000000 0:74212992fb08
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
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 Sam Lantinga
20 slouken@devolution.com
21 */
22
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
27
28 /* Functions for system-level CD-ROM audio control */
29
30 #include <sys/types.h>
31 #include <stdlib.h>
32 #include <sys/stat.h>
33 #include <sys/ioctl.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <sys/cdrom.h>
40 #include <sys/dcmd_cam.h>
41
42
43 #include "SDL_error.h"
44 #include "SDL_cdrom.h"
45 #include "SDL_syscdrom.h"
46
47
48 /* The maximum number of CD-ROM drives we'll detect */
49 #define MAX_DRIVES 16
50
51 /* A list of available CD-ROM drives */
52 static char *SDL_cdlist[MAX_DRIVES];
53 static dev_t SDL_cdmode[MAX_DRIVES];
54
55 /* The system-dependent CD control functions */
56 static const char *SDL_SYS_CDName(int drive);
57 static int SDL_SYS_CDOpen(int drive);
58 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
59 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
60 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
61 static int SDL_SYS_CDPause(SDL_CD *cdrom);
62 static int SDL_SYS_CDResume(SDL_CD *cdrom);
63 static int SDL_SYS_CDStop(SDL_CD *cdrom);
64 static int SDL_SYS_CDEject(SDL_CD *cdrom);
65 static void SDL_SYS_CDClose(SDL_CD *cdrom);
66
67 /* Some ioctl() errno values which occur when the tray is empty */
68 #define ERRNO_TRAYEMPTY(errno) \
69 ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL))
70
71 /* Check a drive to see if it is a CD-ROM */
72 static int CheckDrive(char *drive, char *mnttype, struct stat *stbuf)
73 {
74 int is_cd, cdfd;
75 cdrom_subch_data_t info;
76
77 /* If it doesn't exist, return -1 */
78 if ( stat(drive, stbuf) < 0 ) {
79 return(-1);
80 }
81
82 /* If it does exist, verify that it's an available CD-ROM */
83 is_cd = 0;
84 if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
85 cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
86 if ( cdfd >= 0 ) {
87 info.subch_command.data_format = CDROM_MSF;
88 /* Under Linux, EIO occurs when a disk is not present.
89 */
90 if ((devctl(cdfd,DCMD_CAM_CDROMSUBCHNL,&info,sizeof(info),0) == 0) ||
91 ERRNO_TRAYEMPTY(errno) )
92 {
93 is_cd = 1;
94 }
95 close(cdfd);
96 }
97 }
98 return(is_cd);
99 }
100
101 /* Add a CD-ROM drive to our list of valid drives */
102 static void AddDrive(char *drive, struct stat *stbuf)
103 {
104 int i;
105
106 if ( SDL_numcds < MAX_DRIVES ) {
107 /* Check to make sure it's not already in our list.
108 This can happen when we see a drive via symbolic link.
109 */
110 for ( i=0; i<SDL_numcds; ++i ) {
111 if ( stbuf->st_rdev == SDL_cdmode[i] ) {
112 #ifdef DEBUG_CDROM
113 fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
114 #endif
115 return;
116 }
117 }
118
119 /* Add this drive to our list */
120 i = SDL_numcds;
121 SDL_cdlist[i] = (char *)malloc(strlen(drive)+1);
122 if ( SDL_cdlist[i] == NULL ) {
123 SDL_OutOfMemory();
124 return;
125 }
126 strcpy(SDL_cdlist[i], drive);
127 SDL_cdmode[i] = stbuf->st_rdev;
128 ++SDL_numcds;
129 #ifdef DEBUG_CDROM
130 fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
131 #endif
132 }
133 }
134
135 int SDL_SYS_CDInit(void)
136 {
137 /* checklist: /dev/cdrom, /dev/hd?, /dev/scd? /dev/sr? */
138 static char *checklist[] = {
139 "cdrom", "?0 cd?", "?1 cd?", "?a hd?", "?0 scd?", "?0 sr?", NULL
140 };
141 char *SDLcdrom;
142 int i, j, exists;
143 char drive[32];
144 struct stat stbuf;
145
146 /* Fill in our driver capabilities */
147 SDL_CDcaps.Name = SDL_SYS_CDName;
148 SDL_CDcaps.Open = SDL_SYS_CDOpen;
149 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
150 SDL_CDcaps.Status = SDL_SYS_CDStatus;
151 SDL_CDcaps.Play = SDL_SYS_CDPlay;
152 SDL_CDcaps.Pause = SDL_SYS_CDPause;
153 SDL_CDcaps.Resume = SDL_SYS_CDResume;
154 SDL_CDcaps.Stop = SDL_SYS_CDStop;
155 SDL_CDcaps.Eject = SDL_SYS_CDEject;
156 SDL_CDcaps.Close = SDL_SYS_CDClose;
157
158 /* Look in the environment for our CD-ROM drive list */
159 SDLcdrom = getenv("SDL_CDROM"); /* ':' separated list of devices */
160 if ( SDLcdrom != NULL ) {
161 char *cdpath, *delim;
162 cdpath = malloc(strlen(SDLcdrom)+1);
163 if ( cdpath != NULL ) {
164 strcpy(cdpath, SDLcdrom);
165 SDLcdrom = cdpath;
166 do {
167 delim = strchr(SDLcdrom, ':');
168 if ( delim ) {
169 *delim++ = '\0';
170 }
171 #ifdef DEBUG_CDROM
172 fprintf(stderr, "Checking CD-ROM drive from SDL_CDROM: %s\n", SDLcdrom);
173 #endif
174 if ( CheckDrive(SDLcdrom, NULL, &stbuf) > 0 ) {
175 AddDrive(SDLcdrom, &stbuf);
176 }
177 if ( delim ) {
178 SDLcdrom = delim;
179 } else {
180 SDLcdrom = NULL;
181 }
182 } while ( SDLcdrom );
183 free(cdpath);
184 }
185
186 /* If we found our drives, there's nothing left to do */
187 if ( SDL_numcds > 0 ) {
188 return(0);
189 }
190 }
191
192 /* Scan the system for CD-ROM drives */
193 for ( i=0; checklist[i]; ++i ) {
194 if ( checklist[i][0] == '?' ) {
195 char *insert;
196 exists = 1;
197 for ( j=checklist[i][1]; exists; ++j ) {
198 sprintf(drive, "/dev/%s", &checklist[i][3]);
199 insert = strchr(drive, '?');
200 if ( insert != NULL ) {
201 *insert = j;
202 }
203 #ifdef DEBUG_CDROM
204 fprintf(stderr, "Checking possible CD-ROM drive: %s\n", drive);
205 #endif
206 switch (CheckDrive(drive, NULL, &stbuf)) {
207 /* Drive exists and is a CD-ROM */
208 case 1:
209 AddDrive(drive, &stbuf);
210 break;
211 /* Drive exists, but isn't a CD-ROM */
212 case 0:
213 break;
214 /* Drive doesn't exist */
215 case -1:
216 exists = 0;
217 break;
218 }
219 }
220 } else {
221 sprintf(drive, "/dev/%s", checklist[i]);
222 #ifdef DEBUG_CDROM
223 fprintf(stderr, "Checking possible CD-ROM drive: %s\n", drive);
224 #endif
225 if ( CheckDrive(drive, NULL, &stbuf) > 0 ) {
226 AddDrive(drive, &stbuf);
227 }
228 }
229 }
230 return(0);
231 }
232
233 static const char *SDL_SYS_CDName(int drive)
234 {
235 return(SDL_cdlist[drive]);
236 }
237
238 static int SDL_SYS_CDOpen(int drive)
239 {
240 return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0));
241 }
242
243 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
244 {
245 cdrom_read_toc_t toc;
246 int i, okay;
247
248 okay = 0;
249 if (devctl(cdrom->id, DCMD_CAM_CDROMREADTOC, &toc, sizeof(toc), 0) == 0) {
250 cdrom->numtracks = toc.last_track - toc.first_track + 1;
251 if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
252 cdrom->numtracks = SDL_MAX_TRACKS;
253 }
254 /* Read all the track TOC entries */
255 for ( i=0; i<=cdrom->numtracks; ++i ) {
256 if ( i == cdrom->numtracks ) {
257 cdrom->track[i].id = CDROM_LEADOUT;
258 } else {
259 #if 0 /* Sam 11/6/00 - an obsolete field? */
260 cdrom->track[i].id = toc.cdth_trk0+i;
261 #else
262 cdrom->track[i].id = toc.first_track+i;
263 #endif
264 }
265 cdrom->track[i].type = toc.toc_entry[i].control_adr;
266 cdrom->track[i].offset = MSF_TO_FRAMES(
267 toc.toc_entry[i].addr.msf.minute,
268 toc.toc_entry[i].addr.msf.second,
269 toc.toc_entry[i].addr.msf.frame);
270 cdrom->track[i].length = 0;
271 if ( i > 0 ) {
272 cdrom->track[i-1].length =
273 cdrom->track[i].offset-
274 cdrom->track[i-1].offset;
275 }
276 }
277 if ( i == (cdrom->numtracks+1) ) {
278 okay = 1;
279 }
280 }
281 return(okay ? 0 : -1);
282 }
283
284 /* Get CD-ROM status */
285 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
286 {
287 CDstatus status;
288 cdrom_read_toc_t toc;
289 subch_current_position_t info;
290
291 #if 0 /* Sam 11/6/00 - an obsolete field? */
292 info.subch_command.data_format = CDROM_SUBCH_CURRENT_POSITION;
293 info.subch_command.track_number = 0;
294 #else
295 info.data_format = CDROM_SUBCH_CURRENT_POSITION;
296 info.track_number = 0;
297 #endif
298 if (devctl(cdrom->id, DCMD_CAM_CDROMSUBCHNL, &info, sizeof(info), 0) != 0) {
299 if ( ERRNO_TRAYEMPTY(errno) ) {
300 status = CD_TRAYEMPTY;
301 } else {
302 status = CD_ERROR;
303 }
304 } else {
305 switch (info.header.audio_status) {
306 case CDROM_AUDIO_INVALID:
307 case CDROM_AUDIO_NO_STATUS:
308 /* Try to determine if there's a CD available */
309 if (devctl(cdrom->id, DCMD_CAM_CDROMREADTOC, &toc, sizeof(toc), 0)==0)
310 status = CD_STOPPED;
311 else
312 status = CD_TRAYEMPTY;
313 break;
314 case CDROM_AUDIO_COMPLETED:
315 status = CD_STOPPED;
316 break;
317 case CDROM_AUDIO_PLAY:
318 status = CD_PLAYING;
319 break;
320 case CDROM_AUDIO_PAUSED:
321 /* Workaround buggy CD-ROM drive */
322 if ( info.data_format == CDROM_LEADOUT ) {
323 status = CD_STOPPED;
324 } else {
325 status = CD_PAUSED;
326 }
327 break;
328 default:
329 status = CD_ERROR;
330 break;
331 }
332 }
333 if ( position ) {
334 if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
335 *position = MSF_TO_FRAMES(
336 info.addr.msf.minute,
337 info.addr.msf.second,
338 info.addr.msf.frame);
339 } else {
340 *position = 0;
341 }
342 }
343 return(status);
344 }
345
346 /* Start play */
347 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
348 {
349 cdrom_playmsf_t playtime;
350
351 FRAMES_TO_MSF(start,
352 &playtime.start_minute, &playtime.start_second, &playtime.start_frame);
353 FRAMES_TO_MSF(start+length,
354 &playtime.end_minute, &playtime.end_second, &playtime.end_frame);
355 #ifdef DEBUG_CDROM
356 fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
357 playtime.start_minute, playtime.start_second, playtime.start_frame,
358 playtime.end_minute, playtime.end_second, playtime.end_frame);
359 #endif
360 return(devctl(cdrom->id, DCMD_CAM_CDROMPLAYMSF, &playtime, sizeof(playtime), 0));
361 }
362
363 /* Pause play */
364 static int SDL_SYS_CDPause(SDL_CD *cdrom)
365 {
366 return(devctl(cdrom->id, DCMD_CAM_CDROMPAUSE, NULL, 0, 0));
367 }
368
369 /* Resume play */
370 static int SDL_SYS_CDResume(SDL_CD *cdrom)
371 {
372 return(devctl(cdrom->id, DCMD_CAM_CDROMRESUME, NULL, 0, 0));
373 }
374
375 /* Stop play */
376 static int SDL_SYS_CDStop(SDL_CD *cdrom)
377 {
378 return(devctl(cdrom->id, DCMD_CAM_CDROMSTOP, NULL, 0, 0));
379 }
380
381 /* Eject the CD-ROM */
382 static int SDL_SYS_CDEject(SDL_CD *cdrom)
383 {
384 return(devctl(cdrom->id, DCMD_CAM_EJECT_MEDIA, NULL, 0, 0));
385 }
386
387 /* Close the CD-ROM handle */
388 static void SDL_SYS_CDClose(SDL_CD *cdrom)
389 {
390 close(cdrom->id);
391 }
392
393 void SDL_SYS_CDQuit(void)
394 {
395 int i;
396
397 if ( SDL_numcds > 0 ) {
398 for ( i=0; i<SDL_numcds; ++i ) {
399 free(SDL_cdlist[i]);
400 }
401 SDL_numcds = 0;
402 }
403 }
404