e14743d1 |
1 | /* |
2 | SDL - Simple DirectMedia Layer |
3 | Copyright (C) 1997-2009 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 | #include "SDL_config.h" |
23 | |
24 | #ifdef SDL_CDROM_MINT |
25 | |
26 | /* |
27 | Atari MetaDOS CD-ROM functions |
28 | |
29 | Patrice Mandin |
30 | */ |
31 | |
32 | #include <errno.h> |
33 | |
34 | #include <cdromio.h> |
35 | #include <metados.h> |
36 | |
37 | #include "SDL_cdrom.h" |
38 | #include "../SDL_syscdrom.h" |
39 | |
40 | /* Some ioctl() errno values which occur when the tray is empty */ |
41 | #ifndef ENOMEDIUM |
42 | #define ENOMEDIUM ENOENT |
43 | #endif |
44 | #define ERRNO_TRAYEMPTY(errno) \ |
45 | ((errno == EIO) || (errno == ENOENT) || \ |
46 | (errno == EINVAL) || (errno == ENOMEDIUM)) |
47 | |
48 | /* The maximum number of CD-ROM drives we'll detect */ |
49 | #define MAX_DRIVES 32 |
50 | |
51 | typedef struct { |
52 | unsigned char device[3]; /* Physical device letter + ':' + '\0' */ |
53 | metaopen_t metaopen; /* Infos on opened drive */ |
54 | } metados_drive_t; |
55 | |
56 | static metados_drive_t metados_drives[MAX_DRIVES]; |
57 | |
58 | /* The system-dependent CD control functions */ |
59 | static const char *SDL_SYS_CDName(int drive); |
60 | static int SDL_SYS_CDOpen(int drive); |
61 | static void SDL_SYS_CDClose(SDL_CD *cdrom); |
62 | static int SDL_SYS_CDioctl(int id, int command, void *arg); |
63 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); |
64 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); |
65 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); |
66 | static int SDL_SYS_CDPause(SDL_CD *cdrom); |
67 | static int SDL_SYS_CDResume(SDL_CD *cdrom); |
68 | static int SDL_SYS_CDStop(SDL_CD *cdrom); |
69 | static int SDL_SYS_CDEject(SDL_CD *cdrom); |
70 | |
71 | int SDL_SYS_CDInit(void) |
72 | { |
73 | metainit_t metainit={0,0,0,0}; |
74 | metaopen_t metaopen; |
75 | int i, handle; |
76 | struct cdrom_subchnl info; |
77 | |
78 | Metainit(&metainit); |
79 | if (metainit.version == NULL) { |
80 | #ifdef DEBUG_CDROM |
81 | fprintf(stderr, "MetaDOS not installed\n"); |
82 | #endif |
83 | return -1; |
84 | } |
85 | |
86 | if (metainit.drives_map == 0) { |
87 | #ifdef DEBUG_CDROM |
88 | fprintf(stderr, "No MetaDOS devices present\n"); |
89 | #endif |
90 | return -1; |
91 | } |
92 | |
93 | SDL_numcds = 0; |
94 | |
95 | for (i='A'; i<='Z'; i++) { |
96 | metados_drives[SDL_numcds].device[0] = 0; |
97 | metados_drives[SDL_numcds].device[1] = ':'; |
98 | metados_drives[SDL_numcds].device[2] = 0; |
99 | |
100 | if (metainit.drives_map & (1<<(i-'A'))) { |
101 | handle = Metaopen(i, &metaopen); |
102 | if (handle == 0) { |
103 | |
104 | info.cdsc_format = CDROM_MSF; |
105 | if ( (Metaioctl(i, METADOS_IOCTL_MAGIC, CDROMSUBCHNL, &info) == 0) || ERRNO_TRAYEMPTY(errno) ) { |
106 | metados_drives[SDL_numcds].device[0] = i; |
107 | ++SDL_numcds; |
108 | } |
109 | |
110 | Metaclose(i); |
111 | } |
112 | } |
113 | } |
114 | |
115 | /* Fill in our driver capabilities */ |
116 | SDL_CDcaps.Name = SDL_SYS_CDName; |
117 | SDL_CDcaps.Open = SDL_SYS_CDOpen; |
118 | SDL_CDcaps.Close = SDL_SYS_CDClose; |
119 | |
120 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; |
121 | SDL_CDcaps.Status = SDL_SYS_CDStatus; |
122 | SDL_CDcaps.Play = SDL_SYS_CDPlay; |
123 | SDL_CDcaps.Pause = SDL_SYS_CDPause; |
124 | SDL_CDcaps.Resume = SDL_SYS_CDResume; |
125 | SDL_CDcaps.Stop = SDL_SYS_CDStop; |
126 | SDL_CDcaps.Eject = SDL_SYS_CDEject; |
127 | |
128 | return 0; |
129 | } |
130 | |
131 | void SDL_SYS_CDQuit(void) |
132 | { |
133 | SDL_numcds = 0; |
134 | } |
135 | |
136 | static const char *SDL_SYS_CDName(int drive) |
137 | { |
138 | return(metados_drives[drive].device); |
139 | } |
140 | |
141 | static int SDL_SYS_CDOpen(int drive) |
142 | { |
143 | int handle; |
144 | |
145 | handle = Metaopen(metados_drives[drive].device[0], &(metados_drives[drive].metaopen)); |
146 | if (handle == 0) { |
147 | return drive; |
148 | } |
149 | |
150 | return -1; |
151 | } |
152 | |
153 | static void SDL_SYS_CDClose(SDL_CD *cdrom) |
154 | { |
155 | Metaclose(metados_drives[cdrom->id].device[0]); |
156 | } |
157 | |
158 | static int SDL_SYS_CDioctl(int id, int command, void *arg) |
159 | { |
160 | int retval; |
161 | |
162 | retval = Metaioctl(metados_drives[id].device[0], METADOS_IOCTL_MAGIC, command, arg); |
163 | if ( retval < 0 ) { |
164 | SDL_SetError("ioctl() error: %s", strerror(errno)); |
165 | } |
166 | return(retval); |
167 | } |
168 | |
169 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) |
170 | { |
171 | int i,okay; |
172 | struct cdrom_tochdr toc; |
173 | struct cdrom_tocentry entry; |
174 | |
175 | /* Use standard ioctl() */ |
176 | if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc)<0) { |
177 | return -1; |
178 | } |
179 | |
180 | cdrom->numtracks = toc.cdth_trk1-toc.cdth_trk0+1; |
181 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) { |
182 | cdrom->numtracks = SDL_MAX_TRACKS; |
183 | } |
184 | |
185 | /* Read all the track TOC entries */ |
186 | okay=1; |
187 | for ( i=0; i<=cdrom->numtracks; ++i ) { |
188 | if ( i == cdrom->numtracks ) { |
189 | cdrom->track[i].id = CDROM_LEADOUT; |
190 | } else { |
191 | cdrom->track[i].id = toc.cdth_trk0+i; |
192 | } |
193 | entry.cdte_track = cdrom->track[i].id; |
194 | entry.cdte_format = CDROM_MSF; |
195 | if ( SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCENTRY, &entry) < 0 ) { |
196 | okay=0; |
197 | break; |
198 | } else { |
199 | if ( entry.cdte_ctrl & CDROM_DATA_TRACK ) { |
200 | cdrom->track[i].type = SDL_DATA_TRACK; |
201 | } else { |
202 | cdrom->track[i].type = SDL_AUDIO_TRACK; |
203 | } |
204 | cdrom->track[i].offset = MSF_TO_FRAMES( |
205 | entry.cdte_addr.msf.minute, |
206 | entry.cdte_addr.msf.second, |
207 | entry.cdte_addr.msf.frame); |
208 | cdrom->track[i].length = 0; |
209 | if ( i > 0 ) { |
210 | cdrom->track[i-1].length = cdrom->track[i].offset-cdrom->track[i-1].offset; |
211 | } |
212 | } |
213 | } |
214 | |
215 | return(okay ? 0 : -1); |
216 | } |
217 | |
218 | /* Get CD-ROM status */ |
219 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) |
220 | { |
221 | CDstatus status; |
222 | struct cdrom_tochdr toc; |
223 | struct cdrom_subchnl info; |
224 | |
225 | info.cdsc_format = CDROM_MSF; |
226 | if ( SDL_SYS_CDioctl(cdrom->id, CDROMSUBCHNL, &info) < 0 ) { |
227 | if ( ERRNO_TRAYEMPTY(errno) ) { |
228 | status = CD_TRAYEMPTY; |
229 | } else { |
230 | status = CD_ERROR; |
231 | } |
232 | } else { |
233 | switch (info.cdsc_audiostatus) { |
234 | case CDROM_AUDIO_INVALID: |
235 | case CDROM_AUDIO_NO_STATUS: |
236 | /* Try to determine if there's a CD available */ |
237 | if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc)==0) { |
238 | status = CD_STOPPED; |
239 | } else { |
240 | status = CD_TRAYEMPTY; |
241 | } |
242 | break; |
243 | case CDROM_AUDIO_COMPLETED: |
244 | status = CD_STOPPED; |
245 | break; |
246 | case CDROM_AUDIO_PLAY: |
247 | status = CD_PLAYING; |
248 | break; |
249 | case CDROM_AUDIO_PAUSED: |
250 | /* Workaround buggy CD-ROM drive */ |
251 | if ( info.cdsc_trk == CDROM_LEADOUT ) { |
252 | status = CD_STOPPED; |
253 | } else { |
254 | status = CD_PAUSED; |
255 | } |
256 | break; |
257 | default: |
258 | status = CD_ERROR; |
259 | break; |
260 | } |
261 | } |
262 | if ( position ) { |
263 | if ( status == CD_PLAYING || (status == CD_PAUSED) ) { |
264 | *position = MSF_TO_FRAMES( |
265 | info.cdsc_absaddr.msf.minute, |
266 | info.cdsc_absaddr.msf.second, |
267 | info.cdsc_absaddr.msf.frame); |
268 | } else { |
269 | *position = 0; |
270 | } |
271 | } |
272 | return(status); |
273 | } |
274 | |
275 | /* Start play */ |
276 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) |
277 | { |
278 | struct cdrom_msf playtime; |
279 | |
280 | FRAMES_TO_MSF(start, |
281 | &playtime.cdmsf_min0, &playtime.cdmsf_sec0, &playtime.cdmsf_frame0); |
282 | FRAMES_TO_MSF(start+length, |
283 | &playtime.cdmsf_min1, &playtime.cdmsf_sec1, &playtime.cdmsf_frame1); |
284 | #ifdef DEBUG_CDROM |
285 | fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", |
286 | playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, |
287 | playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); |
288 | #endif |
289 | |
290 | return SDL_SYS_CDioctl(cdrom->id, CDROMPLAYMSF, &playtime); |
291 | } |
292 | |
293 | /* Pause play */ |
294 | static int SDL_SYS_CDPause(SDL_CD *cdrom) |
295 | { |
296 | return SDL_SYS_CDioctl(cdrom->id, CDROMPAUSE, 0); |
297 | } |
298 | |
299 | /* Resume play */ |
300 | static int SDL_SYS_CDResume(SDL_CD *cdrom) |
301 | { |
302 | return SDL_SYS_CDioctl(cdrom->id, CDROMRESUME, 0); |
303 | } |
304 | |
305 | /* Stop play */ |
306 | static int SDL_SYS_CDStop(SDL_CD *cdrom) |
307 | { |
308 | return SDL_SYS_CDioctl(cdrom->id, CDROMSTOP, 0); |
309 | } |
310 | |
311 | /* Eject the CD-ROM */ |
312 | static int SDL_SYS_CDEject(SDL_CD *cdrom) |
313 | { |
314 | return SDL_SYS_CDioctl(cdrom->id, CDROMEJECT, 0); |
315 | } |
316 | |
317 | #endif /* SDL_CDROM_MINT */ |