Mercurial > sdl-ios-xcode
comparison src/cdrom/mint/SDL_syscdrom.c @ 724:6b3dfe0198bb
Atari CD-ROM support
author | Patrice Mandin <patmandin@gmail.com> |
---|---|
date | Sat, 27 Sep 2003 08:20:26 +0000 |
parents | |
children | cb1208fcd946 |
comparison
equal
deleted
inserted
replaced
723:1e8865a3e127 | 724:6b3dfe0198bb |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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@libsdl.org | |
21 */ | |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 /* | |
29 Atari MetaDOS CD-ROM functions | |
30 | |
31 Patrice Mandin | |
32 */ | |
33 | |
34 #include <errno.h> | |
35 #include <stdio.h> | |
36 #include <stdlib.h> | |
37 #include <string.h> | |
38 | |
39 #include <cdromio.h> | |
40 #include <metados.h> | |
41 | |
42 #include "SDL_error.h" | |
43 #include "SDL_cdrom.h" | |
44 #include "SDL_syscdrom.h" | |
45 | |
46 | |
47 /* The maximum number of CD-ROM drives we'll detect */ | |
48 #define MAX_DRIVES 32 | |
49 | |
50 /* Type of CD-ROM drive */ | |
51 #define DRIVE_TYPE_NOCD -1 | |
52 #define DRIVE_TYPE_STANDARD 0 | |
53 #define DRIVE_TYPE_CDAR 1 | |
54 | |
55 typedef struct { | |
56 int type; /* Standard, or old CDAR-type CD drive ? */ | |
57 unsigned char device[3]; /* Physical device letter + ':' + '\0' */ | |
58 metaopen_t metaopen; /* Infos on opened drive */ | |
59 } metados_drive_t; | |
60 | |
61 static metados_drive_t metados_drives[MAX_DRIVES]; | |
62 | |
63 /* The system-dependent CD control functions */ | |
64 static const char *SDL_SYS_CDName(int drive); | |
65 static int SDL_SYS_CDOpen(int drive); | |
66 static void SDL_SYS_CDClose(SDL_CD *cdrom); | |
67 static int SDL_SYS_CDioctl(int id, int command, void *arg); | |
68 | |
69 /* Commands using ioctl() */ | |
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 | |
78 /* Commands using Meta*() CDAR functions */ | |
79 static int SDL_SYS_CD_BcdToBinary(int value); | |
80 static int SDL_SYS_CDGetTOC_CDAR(SDL_CD *cdrom); | |
81 static CDstatus SDL_SYS_CDStatus_CDAR(SDL_CD *cdrom, int *position); | |
82 | |
83 int SDL_SYS_CDInit(void) | |
84 { | |
85 metainit_t metainit={0,0,0,0}; | |
86 metaopen_t metaopen; | |
87 int i, handle; | |
88 | |
89 Metainit(&metainit); | |
90 if (metainit.version == NULL) { | |
91 #ifdef DEBUG_CDROM | |
92 fprintf(stderr, "MetaDOS not installed\n"); | |
93 #endif | |
94 return -1; | |
95 } | |
96 | |
97 if (metainit.drives_map == 0) { | |
98 #ifdef DEBUG_CDROM | |
99 fprintf(stderr, "No MetaDOS devices present\n"); | |
100 #endif | |
101 return -1; | |
102 } | |
103 | |
104 SDL_numcds = 0; | |
105 | |
106 for (i='A'; i<='Z'; i++) { | |
107 metados_drives[SDL_numcds].type = DRIVE_TYPE_NOCD; | |
108 metados_drives[SDL_numcds].device[0] = 0; | |
109 metados_drives[SDL_numcds].device[1] = ':'; | |
110 metados_drives[SDL_numcds].device[2] = 0; | |
111 | |
112 if (metainit.drives_map & (1<<(i-'A'))) { | |
113 handle = Metaopen(i, &metaopen); | |
114 if (handle == 0) { | |
115 | |
116 if ( (metaopen.name[0]=='C') && (metaopen.name[1]=='D') && | |
117 (metaopen.name[2]=='A') && (metaopen.name[3]=='R')) { | |
118 /* Drive compatible with CDAR */ | |
119 metados_drives[SDL_numcds].type = DRIVE_TYPE_CDAR; | |
120 metados_drives[SDL_numcds].device[0] = i; | |
121 ++SDL_numcds; | |
122 } else { | |
123 /* Check for a CD-ROM device */ | |
124 if ((Metastatus(i, NULL) & 0x7fff) >= 0) { | |
125 /* Drive compatible with new ioctl functions */ | |
126 metados_drives[SDL_numcds].type = DRIVE_TYPE_STANDARD; | |
127 metados_drives[SDL_numcds].device[0] = i; | |
128 ++SDL_numcds; | |
129 } | |
130 } | |
131 | |
132 Metaclose(i); | |
133 } | |
134 } | |
135 } | |
136 | |
137 /* Fill in our driver capabilities */ | |
138 SDL_CDcaps.Name = SDL_SYS_CDName; | |
139 SDL_CDcaps.Open = SDL_SYS_CDOpen; | |
140 SDL_CDcaps.Close = SDL_SYS_CDClose; | |
141 | |
142 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | |
143 SDL_CDcaps.Status = SDL_SYS_CDStatus; | |
144 SDL_CDcaps.Play = SDL_SYS_CDPlay; | |
145 SDL_CDcaps.Pause = SDL_SYS_CDPause; | |
146 SDL_CDcaps.Resume = SDL_SYS_CDResume; | |
147 SDL_CDcaps.Stop = SDL_SYS_CDStop; | |
148 SDL_CDcaps.Eject = SDL_SYS_CDEject; | |
149 | |
150 return 0; | |
151 } | |
152 | |
153 void SDL_SYS_CDQuit(void) | |
154 { | |
155 SDL_numcds = 0; | |
156 } | |
157 | |
158 static const char *SDL_SYS_CDName(int drive) | |
159 { | |
160 return(metados_drives[drive].device); | |
161 } | |
162 | |
163 static int SDL_SYS_CDOpen(int drive) | |
164 { | |
165 int handle; | |
166 | |
167 handle = Metaopen(metados_drives[drive].device[0], &(metados_drives[drive].metaopen)); | |
168 if (handle == 0) { | |
169 return drive; | |
170 } | |
171 | |
172 return -1; | |
173 } | |
174 | |
175 static void SDL_SYS_CDClose(SDL_CD *cdrom) | |
176 { | |
177 Metaclose(metados_drives[cdrom->id].device[0]); | |
178 } | |
179 | |
180 static int SDL_SYS_CDioctl(int id, int command, void *arg) | |
181 { | |
182 int retval; | |
183 | |
184 retval = Metaioctl(metados_drives[id].device[0], METADOS_IOCTL_MAGIC, command, arg); | |
185 if ( retval < 0 ) { | |
186 SDL_SetError("ioctl() error: %s", strerror(errno)); | |
187 } | |
188 return(retval); | |
189 } | |
190 | |
191 static int SDL_SYS_CD_BcdToBinary(int value) | |
192 { | |
193 int tmp; | |
194 | |
195 tmp = (value>>4) & 0xf; | |
196 return (tmp*10)+(value & 0xf); | |
197 } | |
198 | |
199 static int SDL_SYS_CDGetTOC_CDAR(SDL_CD *cdrom) | |
200 { | |
201 int errorcode, i, minute, second, frame; | |
202 metatocentry_t *toc_entries; | |
203 metadiscinfo_t disc_info; | |
204 | |
205 /* First, read disc info */ | |
206 errorcode = Metadiscinfo(metados_drives[cdrom->id].device[0], &disc_info); | |
207 if (errorcode<0) { | |
208 #ifdef DEBUG_CDROM | |
209 fprintf(stderr, "Can not read disc info\n"); | |
210 #endif | |
211 return -1; | |
212 } | |
213 | |
214 cdrom->numtracks = disc_info.last - disc_info.first + 1; | |
215 | |
216 /* Then read toc entries for tracks */ | |
217 toc_entries = (metatocentry_t *)malloc(100*sizeof(metatocentry_t)); | |
218 if (toc_entries == NULL) { | |
219 #ifdef DEBUG_CDROM | |
220 fprintf(stderr, "Can not allocate memory for TOC entries\n"); | |
221 #endif | |
222 return -1; | |
223 } | |
224 | |
225 errorcode = Metagettoc(metados_drives[cdrom->id].device[0], 0, toc_entries); | |
226 if (errorcode<0) { | |
227 #ifdef DEBUG_CDROM | |
228 fprintf(stderr, "Can not read TOC\n"); | |
229 #endif | |
230 free(toc_entries); | |
231 return -1; | |
232 } | |
233 | |
234 i=0; | |
235 for (;;) { | |
236 if ((toc_entries[i].track==0) && (toc_entries[i].minute==0) && | |
237 (toc_entries[i].second==0) && (toc_entries[i].frame==0) | |
238 ) { | |
239 break; | |
240 } | |
241 | |
242 if (toc_entries[i].track == CDROM_LEADOUT_CDAR) { | |
243 cdrom->track[i].id = CDROM_LEADOUT; | |
244 } else { | |
245 cdrom->track[i].id = toc_entries[i].track; | |
246 } | |
247 if (disc_info.disctype == 0) { | |
248 cdrom->track[i].type = SDL_AUDIO_TRACK; | |
249 } else { | |
250 cdrom->track[i].type = SDL_DATA_TRACK; | |
251 } | |
252 minute = SDL_SYS_CD_BcdToBinary(toc_entries[i].minute); | |
253 second = SDL_SYS_CD_BcdToBinary(toc_entries[i].second); | |
254 frame = SDL_SYS_CD_BcdToBinary(toc_entries[i].frame); | |
255 cdrom->track[i].offset = MSF_TO_FRAMES(minute, second, frame); | |
256 | |
257 if ( i > 0 ) { | |
258 cdrom->track[i-1].length = cdrom->track[i].offset - cdrom->track[i-1].offset; | |
259 } | |
260 | |
261 ++i; | |
262 } | |
263 | |
264 free(toc_entries); | |
265 return 0; | |
266 } | |
267 | |
268 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | |
269 { | |
270 int i,okay; | |
271 struct cdrom_tochdr toc; | |
272 struct cdrom_tocentry entry; | |
273 | |
274 /* CDAR compatible drive ? */ | |
275 if (metados_drives[cdrom->id].type == DRIVE_TYPE_CDAR) { | |
276 return SDL_SYS_CDGetTOC_CDAR(cdrom); | |
277 } | |
278 | |
279 /* Use standard ioctl() */ | |
280 if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc)<0) { | |
281 return -1; | |
282 } | |
283 | |
284 cdrom->numtracks = toc.cdth_trk1-toc.cdth_trk0+1; | |
285 if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | |
286 cdrom->numtracks = SDL_MAX_TRACKS; | |
287 } | |
288 | |
289 /* Read all the track TOC entries */ | |
290 okay=1; | |
291 for ( i=0; i<=cdrom->numtracks; ++i ) { | |
292 if ( i == cdrom->numtracks ) { | |
293 cdrom->track[i].id = CDROM_LEADOUT; | |
294 } else { | |
295 cdrom->track[i].id = toc.cdth_trk0+i; | |
296 } | |
297 entry.cdte_track = cdrom->track[i].id; | |
298 entry.cdte_format = CDROM_MSF; | |
299 if ( SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCENTRY, &entry) < 0 ) { | |
300 okay=0; | |
301 break; | |
302 } else { | |
303 if ( entry.cdte_ctrl & CDROM_DATA_TRACK ) { | |
304 cdrom->track[i].type = SDL_DATA_TRACK; | |
305 } else { | |
306 cdrom->track[i].type = SDL_AUDIO_TRACK; | |
307 } | |
308 cdrom->track[i].offset = MSF_TO_FRAMES( | |
309 entry.cdte_addr.msf.minute, | |
310 entry.cdte_addr.msf.second, | |
311 entry.cdte_addr.msf.frame); | |
312 cdrom->track[i].length = 0; | |
313 if ( i > 0 ) { | |
314 cdrom->track[i-1].length = cdrom->track[i].offset-cdrom->track[i-1].offset; | |
315 } | |
316 } | |
317 } | |
318 | |
319 return(okay ? 0 : -1); | |
320 } | |
321 | |
322 /* Get CD-ROM status */ | |
323 static CDstatus SDL_SYS_CDStatus_CDAR(SDL_CD *cdrom, int *position) | |
324 { | |
325 return CD_ERROR; | |
326 } | |
327 | |
328 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | |
329 { | |
330 CDstatus status; | |
331 struct cdrom_tochdr toc; | |
332 struct cdrom_subchnl info; | |
333 | |
334 /* CDAR compatible drive ? */ | |
335 if (metados_drives[cdrom->id].type == DRIVE_TYPE_CDAR) { | |
336 return SDL_SYS_CDStatus_CDAR(cdrom, position); | |
337 } | |
338 | |
339 /* Standard ioctl */ | |
340 info.cdsc_format = CDROM_MSF; | |
341 if ( SDL_SYS_CDioctl(cdrom->id, CDROMSUBCHNL, &info) < 0 ) { | |
342 status = CD_TRAYEMPTY; | |
343 } else { | |
344 switch (info.cdsc_audiostatus) { | |
345 case CDROM_AUDIO_INVALID: | |
346 case CDROM_AUDIO_NO_STATUS: | |
347 /* Try to determine if there's a CD available */ | |
348 if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc)==0) { | |
349 status = CD_STOPPED; | |
350 } else { | |
351 status = CD_TRAYEMPTY; | |
352 } | |
353 break; | |
354 case CDROM_AUDIO_COMPLETED: | |
355 status = CD_STOPPED; | |
356 break; | |
357 case CDROM_AUDIO_PLAY: | |
358 status = CD_PLAYING; | |
359 break; | |
360 case CDROM_AUDIO_PAUSED: | |
361 /* Workaround buggy CD-ROM drive */ | |
362 if ( info.cdsc_trk == CDROM_LEADOUT ) { | |
363 status = CD_STOPPED; | |
364 } else { | |
365 status = CD_PAUSED; | |
366 } | |
367 break; | |
368 default: | |
369 status = CD_ERROR; | |
370 break; | |
371 } | |
372 } | |
373 if ( position ) { | |
374 if ( status == CD_PLAYING || (status == CD_PAUSED) ) { | |
375 *position = MSF_TO_FRAMES( | |
376 info.cdsc_absaddr.msf.minute, | |
377 info.cdsc_absaddr.msf.second, | |
378 info.cdsc_absaddr.msf.frame); | |
379 } else { | |
380 *position = 0; | |
381 } | |
382 } | |
383 return(status); | |
384 } | |
385 | |
386 /* Start play */ | |
387 static int SDL_SYS_CDPlay_CDAR(SDL_CD *cdrom, int start, int length) | |
388 { | |
389 struct cdrom_msf playtime; | |
390 | |
391 FRAMES_TO_MSF(start, | |
392 &playtime.cdmsf_min0, &playtime.cdmsf_sec0, &playtime.cdmsf_frame0); | |
393 FRAMES_TO_MSF(start+length, | |
394 &playtime.cdmsf_min1, &playtime.cdmsf_sec1, &playtime.cdmsf_frame1); | |
395 | |
396 return Metasetsongtime(metados_drives[cdrom->id].device[0], 0, | |
397 (playtime.cdmsf_min0<<16)|(playtime.cdmsf_sec0<<8)|(playtime.cdmsf_frame0), | |
398 (playtime.cdmsf_min1<<16)|(playtime.cdmsf_sec1<<8)|(playtime.cdmsf_frame1) | |
399 ); | |
400 } | |
401 | |
402 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | |
403 { | |
404 struct cdrom_msf playtime; | |
405 | |
406 /* CDAR compatible drive ? */ | |
407 if (metados_drives[cdrom->id].type == DRIVE_TYPE_CDAR) { | |
408 return SDL_SYS_CDPlay_CDAR(cdrom, start, length); | |
409 } | |
410 | |
411 FRAMES_TO_MSF(start, | |
412 &playtime.cdmsf_min0, &playtime.cdmsf_sec0, &playtime.cdmsf_frame0); | |
413 FRAMES_TO_MSF(start+length, | |
414 &playtime.cdmsf_min1, &playtime.cdmsf_sec1, &playtime.cdmsf_frame1); | |
415 #ifdef DEBUG_CDROM | |
416 fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", | |
417 playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, | |
418 playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); | |
419 #endif | |
420 return(SDL_SYS_CDioctl(cdrom->id, CDROMPLAYMSF, &playtime)); | |
421 } | |
422 | |
423 /* Pause play */ | |
424 static int SDL_SYS_CDPause(SDL_CD *cdrom) | |
425 { | |
426 /* CDAR compatible drive ? */ | |
427 if (metados_drives[cdrom->id].type == DRIVE_TYPE_CDAR) { | |
428 return -1; | |
429 } | |
430 | |
431 return(SDL_SYS_CDioctl(cdrom->id, CDROMPAUSE, 0)); | |
432 } | |
433 | |
434 /* Resume play */ | |
435 static int SDL_SYS_CDResume(SDL_CD *cdrom) | |
436 { | |
437 /* CDAR compatible drive ? */ | |
438 if (metados_drives[cdrom->id].type == DRIVE_TYPE_CDAR) { | |
439 return -1; | |
440 } | |
441 | |
442 return(SDL_SYS_CDioctl(cdrom->id, CDROMRESUME, 0)); | |
443 } | |
444 | |
445 /* Stop play */ | |
446 static int SDL_SYS_CDStop(SDL_CD *cdrom) | |
447 { | |
448 /* CDAR compatible drive ? */ | |
449 if (metados_drives[cdrom->id].type == DRIVE_TYPE_CDAR) { | |
450 return Metastopaudio(metados_drives[cdrom->id].device[0]); | |
451 } | |
452 | |
453 return(SDL_SYS_CDioctl(cdrom->id, CDROMSTOP, 0)); | |
454 } | |
455 | |
456 /* Eject the CD-ROM */ | |
457 static int SDL_SYS_CDEject(SDL_CD *cdrom) | |
458 { | |
459 /* CDAR compatible drive ? */ | |
460 if (metados_drives[cdrom->id].type == DRIVE_TYPE_CDAR) { | |
461 return -1; | |
462 } | |
463 | |
464 return(SDL_SYS_CDioctl(cdrom->id, CDROMEJECT, 0)); | |
465 } |