comparison src/cdrom/beos/SDL_syscdrom.cc @ 153:2839f45bdba0

Fixed IDE and SCSI CD-ROM detection on BeOS (thanks Caz!)
author Sam Lantinga <slouken@libsdl.org>
date Sat, 18 Aug 2001 22:03:11 +0000
parents
children e8157fcb3114
comparison
equal deleted inserted replaced
152:2cf88672fc7f 153:2839f45bdba0
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 on BeOS
29 (not completely implemented yet)
30 */
31
32 #include <sys/types.h>
33 #include <stdlib.h>
34 #include <sys/stat.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include <scsi.h>
40 #include <Directory.h>
41 #include <Entry.h>
42 #include <Path.h>
43
44 #include "SDL_error.h"
45 #include "SDL_cdrom.h"
46 extern "C" {
47 #include "SDL_syscdrom.h"
48 }
49
50 /* Constants to help us get at the SCSI table-of-contents info */
51 #define CD_NUMTRACKS(toc) toc.toc_data[3]
52 #define CD_TRACK(toc, track) (&toc.toc_data[6+(track)*8])
53 #define CD_TRACK_N(toc, track) CD_TRACK(toc, track)[0]
54 #define CD_TRACK_M(toc, track) CD_TRACK(toc, track)[3]
55 #define CD_TRACK_S(toc, track) CD_TRACK(toc, track)[4]
56 #define CD_TRACK_F(toc, track) CD_TRACK(toc, track)[5]
57
58 /* Constants to help us get at the SCSI position info */
59 #define POS_TRACK(pos) pos.position[6]
60 #define POS_ABS_M(pos) pos.position[9]
61 #define POS_ABS_S(pos) pos.position[10]
62 #define POS_ABS_F(pos) pos.position[11]
63 #define POS_REL_M(pos) pos.position[13]
64 #define POS_REL_S(pos) pos.position[14]
65 #define POS_REL_F(pos) pos.position[15]
66
67 /* The maximum number of CD-ROM drives we'll detect */
68 #define MAX_DRIVES 16
69
70 /* A list of available CD-ROM drives */
71 static char *SDL_cdlist[MAX_DRIVES];
72
73 /* The system-dependent CD control functions */
74 static const char *SDL_SYS_CDName(int drive);
75 static int SDL_SYS_CDOpen(int drive);
76 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
77 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
78 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
79 static int SDL_SYS_CDPause(SDL_CD *cdrom);
80 static int SDL_SYS_CDResume(SDL_CD *cdrom);
81 static int SDL_SYS_CDStop(SDL_CD *cdrom);
82 static int SDL_SYS_CDEject(SDL_CD *cdrom);
83 static void SDL_SYS_CDClose(SDL_CD *cdrom);
84 int try_dir(const char *directory);
85
86
87 /* Check a drive to see if it is a CD-ROM */
88 static int CheckDrive(char *drive)
89 {
90 struct stat stbuf;
91 int is_cd, cdfd;
92 device_geometry info;
93
94 /* If it doesn't exist, return -1 */
95 if ( stat(drive, &stbuf) < 0 ) {
96 return(-1);
97 }
98
99 /* If it does exist, verify that it's an available CD-ROM */
100 is_cd = 0;
101 cdfd = open(drive, 0);
102 if ( cdfd >= 0 ) {
103 if ( ioctl(cdfd, B_GET_GEOMETRY, &info) == B_NO_ERROR ) {
104 if ( info.device_type == B_CD ) {
105 is_cd = 1;
106 }
107 }
108 close(cdfd);
109 } else {
110 /* This can happen when the drive is open .. (?) */;
111 is_cd = 1;
112 }
113 return(is_cd);
114 }
115
116 /* Add a CD-ROM drive to our list of valid drives */
117 static void AddDrive(char *drive)
118 {
119 int i;
120
121 if ( SDL_numcds < MAX_DRIVES ) {
122 /* Add this drive to our list */
123 i = SDL_numcds;
124 SDL_cdlist[i] = (char *)malloc(strlen(drive)+1);
125 if ( SDL_cdlist[i] == NULL ) {
126 SDL_OutOfMemory();
127 return;
128 }
129 strcpy(SDL_cdlist[i], drive);
130 ++SDL_numcds;
131 #ifdef CDROM_DEBUG
132 fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
133 #endif
134 }
135 }
136
137 /* IDE bus scanning magic */
138 enum {
139 IDE_GET_DEVICES_INFO = B_DEVICE_OP_CODES_END + 50,
140 };
141 struct ide_ctrl_info {
142 bool ide_0_present;
143 bool ide_0_master_present;
144 bool ide_0_slave_present;
145 int ide_0_master_type;
146 int ide_0_slave_type;
147 bool ide_1_present;
148 bool ide_1_master_present;
149 bool ide_1_slave_present;
150 int ide_1_master_type;
151 int ide_1_slave_type;
152 };
153
154 int SDL_SYS_CDInit(void)
155 {
156 char *SDLcdrom;
157 int raw_fd;
158 struct ide_ctrl_info info;
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 /* Look in the environment for our CD-ROM drive list */
173 SDLcdrom = getenv("SDL_CDROM"); /* ':' separated list of devices */
174 if ( SDLcdrom != NULL ) {
175 char *cdpath, *delim;
176 cdpath = (char *)malloc(strlen(SDLcdrom)+1);
177 if ( cdpath != NULL ) {
178 strcpy(cdpath, SDLcdrom);
179 SDLcdrom = cdpath;
180 do {
181 delim = strchr(SDLcdrom, ':');
182 if ( delim ) {
183 *delim++ = '\0';
184 }
185 if ( CheckDrive(SDLcdrom) > 0 ) {
186 AddDrive(SDLcdrom);
187 }
188 if ( delim ) {
189 SDLcdrom = delim;
190 } else {
191 SDLcdrom = NULL;
192 }
193 } while ( SDLcdrom );
194 free(cdpath);
195 }
196
197 /* If we found our drives, there's nothing left to do */
198 if ( SDL_numcds > 0 ) {
199 return(0);
200 }
201 }
202
203 /* Scan the system for CD-ROM drives */
204 try_dir("/dev/disk");
205 return 0;
206 }
207
208
209 int try_dir(const char *directory)
210 {
211 BDirectory dir;
212 dir.SetTo(directory);
213 if(dir.InitCheck() != B_NO_ERROR) {
214 return false;
215 }
216 dir.Rewind();
217 BEntry entry;
218 while(dir.GetNextEntry(&entry) >= 0) {
219 BPath path;
220 const char *name;
221 entry_ref e;
222
223 if(entry.GetPath(&path) != B_NO_ERROR)
224 continue;
225 name = path.Path();
226
227 if(entry.GetRef(&e) != B_NO_ERROR)
228 continue;
229
230 if(entry.IsDirectory()) {
231 if(strcmp(e.name, "floppy") == 0)
232 continue; /* ignore floppy (it is not silent) */
233 int devfd = try_dir(name);
234 if(devfd >= 0)
235 return devfd;
236 }
237 else {
238 int devfd;
239 device_geometry g;
240
241 if(strcmp(e.name, "raw") != 0)
242 continue; /* ignore partitions */
243
244 devfd = open(name, O_RDONLY);
245 if(devfd < 0)
246 continue;
247
248 if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) {
249 if(g.device_type == B_CD)
250 {
251 AddDrive(strdup(name));
252 }
253 }
254 close(devfd);
255 }
256 }
257 return B_ERROR;
258 }
259
260
261 /* General ioctl() CD-ROM command function */
262 static int SDL_SYS_CDioctl(int index, int command, void *arg)
263 {
264 int okay;
265 int fd;
266
267 okay = 0;
268 fd = open(SDL_cdlist[index], 0);
269 if ( fd >= 0 ) {
270 if ( ioctl(fd, command, arg) == B_NO_ERROR ) {
271 okay = 1;
272 }
273 close(fd);
274 }
275 return(okay ? 0 : -1);
276 }
277
278 static const char *SDL_SYS_CDName(int drive)
279 {
280 return(SDL_cdlist[drive]);
281 }
282
283 static int SDL_SYS_CDOpen(int drive)
284 {
285 return(drive);
286 }
287
288 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
289 {
290 int i;
291 scsi_toc toc;
292
293 if ( SDL_SYS_CDioctl(cdrom->id, B_SCSI_GET_TOC, &toc) == 0 ) {
294 cdrom->numtracks = CD_NUMTRACKS(toc);
295 if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
296 cdrom->numtracks = SDL_MAX_TRACKS;
297 }
298 for ( i=0; i<=cdrom->numtracks; ++i ) {
299 cdrom->track[i].id = CD_TRACK_N(toc, i);
300 /* FIXME: How do we tell on BeOS? */
301 cdrom->track[i].type = SDL_AUDIO_TRACK;
302 cdrom->track[i].offset = MSF_TO_FRAMES(
303 CD_TRACK_M(toc, i),
304 CD_TRACK_S(toc, i),
305 CD_TRACK_F(toc, i));
306 cdrom->track[i].length = 0;
307 if ( i > 0 ) {
308 cdrom->track[i-1].length =
309 cdrom->track[i].offset-
310 cdrom->track[i-1].offset;
311 }
312 }
313 return(0);
314 } else {
315 return(-1);
316 }
317 }
318
319 /* Get CD-ROM status */
320 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
321 {
322 CDstatus status;
323 int fd;
324 int cur_frame;
325 scsi_position pos;
326
327 fd = open(SDL_cdlist[cdrom->id], 0);
328 cur_frame = 0;
329 if ( fd >= 0 ) {
330 if ( ioctl(fd, B_SCSI_GET_POSITION, &pos) == B_NO_ERROR ) {
331 cur_frame = MSF_TO_FRAMES(
332 POS_ABS_M(pos), POS_ABS_S(pos), POS_ABS_F(pos));
333 }
334 if ( ! pos.position[1] || (pos.position[1] >= 0x13) ||
335 ((pos.position[1] == 0x12) && (!pos.position[6])) ) {
336 status = CD_STOPPED;
337 } else
338 if ( pos.position[1] == 0x11 ) {
339 status = CD_PLAYING;
340 } else {
341 status = CD_PAUSED;
342 }
343 close(fd);
344 } else {
345 status = CD_TRAYEMPTY;
346 }
347 if ( position ) {
348 *position = cur_frame;
349 }
350 return(status);
351 }
352
353 /* Start play */
354 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
355 {
356 int okay;
357 int fd;
358 scsi_play_position pos;
359
360 okay = 0;
361 fd = open(SDL_cdlist[cdrom->id], 0);
362 if ( fd >= 0 ) {
363 FRAMES_TO_MSF(start, &pos.start_m, &pos.start_s, &pos.start_f);
364 FRAMES_TO_MSF(start+length, &pos.end_m, &pos.end_s, &pos.end_f);
365 if ( ioctl(fd, B_SCSI_PLAY_POSITION, &pos) == B_NO_ERROR ) {
366 okay = 1;
367 }
368 close(fd);
369 }
370 return(okay ? 0 : -1);
371 }
372
373 /* Pause play */
374 static int SDL_SYS_CDPause(SDL_CD *cdrom)
375 {
376 return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_PAUSE_AUDIO, 0));
377 }
378
379 /* Resume play */
380 static int SDL_SYS_CDResume(SDL_CD *cdrom)
381 {
382 return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_RESUME_AUDIO, 0));
383 }
384
385 /* Stop play */
386 static int SDL_SYS_CDStop(SDL_CD *cdrom)
387 {
388 return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_STOP_AUDIO, 0));
389 }
390
391 /* Eject the CD-ROM */
392 static int SDL_SYS_CDEject(SDL_CD *cdrom)
393 {
394 return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_EJECT, 0));
395 }
396
397 /* Close the CD-ROM handle */
398 static void SDL_SYS_CDClose(SDL_CD *cdrom)
399 {
400 close(cdrom->id);
401 }
402
403 void SDL_SYS_CDQuit(void)
404 {
405 int i;
406
407 if ( SDL_numcds > 0 ) {
408 for ( i=0; i<SDL_numcds; ++i ) {
409 free(SDL_cdlist[i]);
410 }
411 SDL_numcds = 0;
412 }
413 }
414