|
1 /* |
|
2 SDL - Simple DirectMedia Layer |
|
3 Copyright (C) 1997-2006 Sam Lantinga |
|
4 |
|
5 This library is free software; you can redistribute it and/or |
|
6 modify it under the terms of the GNU Lesser General Public |
|
7 License as published by the Free Software Foundation; either |
|
8 version 2.1 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 Lesser General Public License for more details. |
|
14 |
|
15 You should have received a copy of the GNU Lesser General Public |
|
16 License along with this library; if not, write to the Free Software |
|
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
|
19 Sam Lantinga |
|
20 slouken@libsdl.org |
|
21 */ |
|
22 #include "SDL_config.h" |
|
23 |
|
24 #ifdef SDL_CDROM_OS2 |
|
25 |
|
26 /* Functions for system-level CD-ROM audio control */ |
|
27 |
|
28 #define INCL_MCIOS2 |
|
29 #include <os2.h> |
|
30 #include <os2me.h> |
|
31 |
|
32 #include "SDL_cdrom.h" |
|
33 #include "../SDL_syscdrom.h" |
|
34 |
|
35 /* Size of MCI result buffer (in bytes) */ |
|
36 #define MCI_CMDRETBUFSIZE 128 |
|
37 |
|
38 /* The maximum number of CD-ROM drives we'll detect */ |
|
39 #define MAX_DRIVES 16 |
|
40 |
|
41 /* A list of available CD-ROM drives */ |
|
42 static char *SDL_cdlist[MAX_DRIVES]; |
|
43 //static dev_t SDL_cdmode[MAX_DRIVES]; |
|
44 |
|
45 /* The system-dependent CD control functions */ |
|
46 static const char *SDL_SYS_CDName(int drive); |
|
47 static int SDL_SYS_CDOpen(int drive); |
|
48 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); |
|
49 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); |
|
50 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); |
|
51 static int SDL_SYS_CDPause(SDL_CD *cdrom); |
|
52 static int SDL_SYS_CDResume(SDL_CD *cdrom); |
|
53 static int SDL_SYS_CDStop(SDL_CD *cdrom); |
|
54 static int SDL_SYS_CDEject(SDL_CD *cdrom); |
|
55 static void SDL_SYS_CDClose(SDL_CD *cdrom); |
|
56 |
|
57 /* MCI Timing Functions */ |
|
58 #define MCI_MMTIMEPERSECOND 3000 |
|
59 #define FRAMESFROMMM(mmtime) (((mmtime)*CD_FPS)/MCI_MMTIMEPERSECOND) |
|
60 |
|
61 |
|
62 /* Ready for MCI CDAudio Devices */ |
|
63 int SDL_SYS_CDInit(void) |
|
64 { |
|
65 int i; /* generig counter */ |
|
66 MCI_SYSINFO_PARMS msp; /* Structure to MCI SysInfo parameters */ |
|
67 CHAR SysInfoRet[MCI_CMDRETBUFSIZE]; /* Buffer for MCI Command result */ |
|
68 |
|
69 /* Fill in our driver capabilities */ |
|
70 SDL_CDcaps.Name = SDL_SYS_CDName; |
|
71 SDL_CDcaps.Open = SDL_SYS_CDOpen; |
|
72 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; |
|
73 SDL_CDcaps.Status = SDL_SYS_CDStatus; |
|
74 SDL_CDcaps.Play = SDL_SYS_CDPlay; |
|
75 SDL_CDcaps.Pause = SDL_SYS_CDPause; |
|
76 SDL_CDcaps.Resume = SDL_SYS_CDResume; |
|
77 SDL_CDcaps.Stop = SDL_SYS_CDStop; |
|
78 SDL_CDcaps.Eject = SDL_SYS_CDEject; |
|
79 SDL_CDcaps.Close = SDL_SYS_CDClose; |
|
80 |
|
81 /* Get the number of CD ROMs in the System */ |
|
82 /* Clean SysInfo structure */ |
|
83 SDL_memset(&msp, 0x00, sizeof(MCI_SYSINFO_PARMS)); |
|
84 /* Prepare structure to Ask Numer of Audio CDs */ |
|
85 msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ |
|
86 msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ |
|
87 msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ |
|
88 if (LOUSHORT(mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_QUANTITY | MCI_WAIT, (PVOID)&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); |
|
89 SDL_numcds = atoi(SysInfoRet); |
|
90 if (SDL_numcds > MAX_DRIVES) SDL_numcds = MAX_DRIVES; /* Limit maximum CD number */ |
|
91 |
|
92 /* Get and Add their system name to the SDL_cdlist */ |
|
93 msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ |
|
94 msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ |
|
95 msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ |
|
96 for (i=0; i<SDL_numcds; i++) |
|
97 { |
|
98 msp.ulNumber = i+1; |
|
99 mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_NAME | MCI_WAIT,&msp, 0); |
|
100 SDL_cdlist[i] = SDL_strdup(SysInfoRet); |
|
101 if ( SDL_cdlist[i] == NULL ) |
|
102 { |
|
103 SDL_OutOfMemory(); |
|
104 return(-1); |
|
105 } |
|
106 } |
|
107 return(0); |
|
108 } |
|
109 |
|
110 /* Return CDAudio System Dependent Device Name - Ready for MCI*/ |
|
111 static const char *SDL_SYS_CDName(int drive) |
|
112 { |
|
113 return(SDL_cdlist[drive]); |
|
114 } |
|
115 |
|
116 /* Open CDAudio Device - Ready for MCI */ |
|
117 static int SDL_SYS_CDOpen(int drive) |
|
118 { |
|
119 MCI_OPEN_PARMS mop; |
|
120 MCI_SET_PARMS msp; |
|
121 MCI_GENERIC_PARMS mgp; |
|
122 |
|
123 /* Open the device */ |
|
124 mop.hwndCallback = (HWND)NULL; // None |
|
125 mop.usDeviceID = (USHORT)NULL; // Will be returned. |
|
126 mop.pszDeviceType = (PSZ)SDL_cdlist[drive]; // CDAudio Device |
|
127 if (LOUSHORT(mciSendCommand(0,MCI_OPEN,MCI_WAIT,&mop, 0)) != MCIERR_SUCCESS) return(CD_ERROR); |
|
128 /* Set time format */ |
|
129 msp.hwndCallback = (HWND)NULL; // None |
|
130 msp.ulTimeFormat = MCI_FORMAT_MSF; // Minute : Second : Frame structure |
|
131 msp.ulSpeedFormat = (ULONG)NULL; // No change |
|
132 msp.ulAudio = (ULONG)NULL; // No Channel |
|
133 msp.ulLevel = (ULONG)NULL; // No Volume |
|
134 msp.ulOver = (ULONG)NULL; // No Delay |
|
135 msp.ulItem = (ULONG)NULL; // No item |
|
136 msp.ulValue = (ULONG)NULL; // No value for item flag |
|
137 if (LOUSHORT(mciSendCommand(mop.usDeviceID,MCI_SET,MCI_WAIT | MCI_SET_TIME_FORMAT,&msp, 0)) == MCIERR_SUCCESS) return (mop.usDeviceID); |
|
138 /* Error setting time format? - Close opened device */ |
|
139 mgp.hwndCallback = (HWND)NULL; // None |
|
140 mciSendCommand(mop.usDeviceID,MCI_CLOSE,MCI_WAIT,&mgp, 0); |
|
141 return(CD_ERROR); |
|
142 } |
|
143 |
|
144 /* Get CD Table Of Contents - Ready for MCI */ |
|
145 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) |
|
146 { |
|
147 MCI_TOC_PARMS mtp; |
|
148 MCI_STATUS_PARMS msp; |
|
149 MCI_TOC_REC * mtr; |
|
150 INT i; |
|
151 |
|
152 /* Correction because MCI cannot read TOC while CD is playing (it'll stop!) */ |
|
153 if (cdrom->status == CD_PLAYING || cdrom->status == CD_PAUSED) return 0; |
|
154 |
|
155 /* Get Number of Tracks */ |
|
156 msp.hwndCallback = (HWND)NULL; /* None */ |
|
157 msp.ulReturn = (ULONG)NULL; /* We want this information */ |
|
158 msp.ulItem = MCI_STATUS_NUMBER_OF_TRACKS; |
|
159 msp.ulValue = (ULONG)NULL; /* No additional information */ |
|
160 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); |
|
161 cdrom->numtracks = msp.ulReturn; |
|
162 if ( cdrom->numtracks > SDL_MAX_TRACKS ) |
|
163 { |
|
164 cdrom->numtracks = SDL_MAX_TRACKS; |
|
165 } |
|
166 /* Alocate space for TOC data */ |
|
167 mtr = (MCI_TOC_REC *)SDL_malloc(cdrom->numtracks*sizeof(MCI_TOC_REC)); |
|
168 if ( mtr == NULL ) |
|
169 { |
|
170 SDL_OutOfMemory(); |
|
171 return(-1); |
|
172 } |
|
173 /* Get TOC from CD */ |
|
174 mtp.pBuf = mtr; |
|
175 mtp.ulBufSize = cdrom->numtracks*sizeof(MCI_TOC_REC); |
|
176 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_GETTOC,MCI_WAIT,&mtp, 0)) != MCIERR_SUCCESS) |
|
177 { |
|
178 SDL_OutOfMemory(); |
|
179 SDL_free(mtr); |
|
180 return(CD_ERROR); |
|
181 } |
|
182 /* Fill SDL Tracks Structure */ |
|
183 for (i=0; i<cdrom->numtracks; i++) |
|
184 { |
|
185 /* Set Track ID */ |
|
186 cdrom->track[i].id = (mtr+i)->TrackNum; |
|
187 /* Set Track Type */ |
|
188 msp.hwndCallback = (HWND)NULL; /* None */ |
|
189 msp.ulReturn = (ULONG)NULL; /* We want this information */ |
|
190 msp.ulItem = MCI_CD_STATUS_TRACK_TYPE; |
|
191 msp.ulValue = (ULONG)((mtr+i)->TrackNum); /* Track Number? */ |
|
192 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_TRACK | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) |
|
193 { |
|
194 SDL_free(mtr); |
|
195 return (CD_ERROR); |
|
196 } |
|
197 if (msp.ulReturn==MCI_CD_TRACK_AUDIO) cdrom->track[i].type = SDL_AUDIO_TRACK; |
|
198 else cdrom->track[i].type = SDL_DATA_TRACK; |
|
199 /* Set Track Length - values from MCI are in MMTIMEs - 3000 MMTIME = 1 second */ |
|
200 cdrom->track[i].length = FRAMESFROMMM((mtr+i)->ulEndAddr - (mtr+i)->ulStartAddr); |
|
201 /* Set Track Offset */ |
|
202 cdrom->track[i].offset = FRAMESFROMMM((mtr+i)->ulStartAddr); |
|
203 } |
|
204 SDL_free(mtr); |
|
205 return(0); |
|
206 } |
|
207 |
|
208 |
|
209 /* Get CD-ROM status - Ready for MCI */ |
|
210 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) |
|
211 { |
|
212 CDstatus status; |
|
213 MCI_STATUS_PARMS msp; |
|
214 |
|
215 /* Get Status from MCI */ |
|
216 msp.hwndCallback = (HWND)NULL; /* None */ |
|
217 msp.ulReturn = (ULONG)NULL; /* We want this information */ |
|
218 msp.ulItem = MCI_STATUS_MODE; |
|
219 msp.ulValue = (ULONG)NULL; /* No additional information */ |
|
220 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) status = CD_ERROR; |
|
221 else |
|
222 { |
|
223 switch(msp.ulReturn) |
|
224 { |
|
225 case MCI_MODE_NOT_READY: |
|
226 status = CD_TRAYEMPTY; |
|
227 break; |
|
228 case MCI_MODE_PAUSE: |
|
229 status = CD_PAUSED; |
|
230 break; |
|
231 case MCI_MODE_PLAY: |
|
232 status = CD_PLAYING; |
|
233 break; |
|
234 case MCI_MODE_STOP: |
|
235 status = CD_STOPPED; |
|
236 break; |
|
237 /* These cases should not occour */ |
|
238 case MCI_MODE_RECORD: |
|
239 case MCI_MODE_SEEK: |
|
240 default: |
|
241 status = CD_ERROR; |
|
242 break; |
|
243 } |
|
244 } |
|
245 |
|
246 /* Determine position */ |
|
247 if (position != NULL) /* The SDL $&$&%# CDROM call sends NULL pointer here! */ |
|
248 { |
|
249 if ((status == CD_PLAYING) || (status == CD_PAUSED)) |
|
250 { |
|
251 /* Get Position */ |
|
252 msp.hwndCallback = (HWND)NULL; /* None */ |
|
253 msp.ulReturn = (ULONG)NULL; /* We want this information */ |
|
254 msp.ulItem = MCI_STATUS_POSITION; |
|
255 msp.ulValue = (ULONG)NULL; /* No additiona info */ |
|
256 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return (CD_ERROR); |
|
257 /* Convert from MSF (format selected in the Open process) to Frames (format that will be returned) */ |
|
258 *position = MSF_TO_FRAMES(MSF_MINUTE(msp.ulReturn),MSF_SECOND(msp.ulReturn),MSF_FRAME(msp.ulReturn)); |
|
259 } |
|
260 else *position = 0; |
|
261 } |
|
262 return(status); |
|
263 } |
|
264 |
|
265 /* Start play - Ready for MCI */ |
|
266 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) |
|
267 { |
|
268 MCI_GENERIC_PARMS mgp; |
|
269 MCI_STATUS_PARMS msp; |
|
270 MCI_PLAY_PARMS mpp; |
|
271 ULONG min,sec,frm; |
|
272 |
|
273 /* Start MSF */ |
|
274 FRAMES_TO_MSF(start, &min, &sec, &frm); |
|
275 MSF_MINUTE(mpp.ulFrom) = min; |
|
276 MSF_SECOND(mpp.ulFrom) = sec; |
|
277 MSF_FRAME(mpp.ulFrom) = frm; |
|
278 /* End MSF */ |
|
279 FRAMES_TO_MSF(start+length, &min, &sec, &frm); |
|
280 MSF_MINUTE(mpp.ulTo) = min; |
|
281 MSF_SECOND(mpp.ulTo) = sec; |
|
282 MSF_FRAME(mpp.ulTo) = frm; |
|
283 #ifdef DEBUG_CDROM |
|
284 fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", |
|
285 playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, |
|
286 playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); |
|
287 #endif |
|
288 /* Verifies if it is paused first... and if it is, unpause before stopping it. */ |
|
289 msp.hwndCallback = (HWND)NULL; /* None */ |
|
290 msp.ulReturn = (ULONG)NULL; /* We want this information */ |
|
291 msp.ulItem = MCI_STATUS_MODE; |
|
292 msp.ulValue = (ULONG)NULL; /* No additional information */ |
|
293 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS) |
|
294 { |
|
295 if (msp.ulReturn == MCI_MODE_PAUSE) |
|
296 { |
|
297 mgp.hwndCallback = (HWND)NULL; // None |
|
298 mciSendCommand(cdrom->id,MCI_RESUME,0,&mgp, 0); |
|
299 } |
|
300 } |
|
301 /* Now play it. */ |
|
302 mpp.hwndCallback = (HWND)NULL; // We do not want the info. temp |
|
303 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PLAY,MCI_FROM | MCI_TO,&mpp, 0)) == MCIERR_SUCCESS) return 0; |
|
304 return (CD_ERROR); |
|
305 } |
|
306 |
|
307 /* Pause play - Ready for MCI */ |
|
308 static int SDL_SYS_CDPause(SDL_CD *cdrom) |
|
309 { |
|
310 MCI_GENERIC_PARMS mgp; |
|
311 |
|
312 mgp.hwndCallback = (HWND)NULL; // None |
|
313 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PAUSE,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; |
|
314 return(CD_ERROR); |
|
315 } |
|
316 |
|
317 /* Resume play - Ready for MCI */ |
|
318 static int SDL_SYS_CDResume(SDL_CD *cdrom) |
|
319 { |
|
320 MCI_GENERIC_PARMS mgp; |
|
321 |
|
322 mgp.hwndCallback = (HWND)NULL; // None |
|
323 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_RESUME,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; |
|
324 return(CD_ERROR); |
|
325 } |
|
326 |
|
327 /* Stop play - Ready for MCI */ |
|
328 static int SDL_SYS_CDStop(SDL_CD *cdrom) |
|
329 { |
|
330 MCI_GENERIC_PARMS mgp; |
|
331 MCI_STATUS_PARMS msp; |
|
332 |
|
333 /* Verifies if it is paused first... and if it is, unpause before stopping it. */ |
|
334 msp.hwndCallback = (HWND)NULL; /* None */ |
|
335 msp.ulReturn = (ULONG)NULL; /* We want this information */ |
|
336 msp.ulItem = MCI_STATUS_MODE; |
|
337 msp.ulValue = (ULONG)NULL; /* No additional information */ |
|
338 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS) |
|
339 { |
|
340 if (msp.ulReturn == MCI_MODE_PAUSE) |
|
341 { |
|
342 mgp.hwndCallback = (HWND)NULL; // None |
|
343 mciSendCommand(cdrom->id,MCI_RESUME,0,&mgp, 0); |
|
344 } |
|
345 } |
|
346 /* Now stops the media */ |
|
347 mgp.hwndCallback = (HWND)NULL; // None |
|
348 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STOP,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; |
|
349 return(CD_ERROR); |
|
350 } |
|
351 |
|
352 /* Eject the CD-ROM - Ready for MCI */ |
|
353 static int SDL_SYS_CDEject(SDL_CD *cdrom) |
|
354 { |
|
355 MCI_SET_PARMS msp; |
|
356 |
|
357 msp.hwndCallback = (HWND)NULL; // None |
|
358 msp.ulTimeFormat = (ULONG)NULL; // No change |
|
359 msp.ulSpeedFormat = (ULONG)NULL; // No change |
|
360 msp.ulAudio = (ULONG)NULL; // No Channel |
|
361 msp.ulLevel = (ULONG)NULL; // No Volume |
|
362 msp.ulOver = (ULONG)NULL; // No Delay |
|
363 msp.ulItem = (ULONG)NULL; // No item |
|
364 msp.ulValue = (ULONG)NULL; // No value for item flag |
|
365 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_SET,MCI_WAIT | MCI_SET_DOOR_OPEN,&msp, 0)) == MCIERR_SUCCESS) return 0; |
|
366 return(CD_ERROR); |
|
367 } |
|
368 |
|
369 /* Close the CD-ROM handle - Ready for MCI */ |
|
370 static void SDL_SYS_CDClose(SDL_CD *cdrom) |
|
371 { |
|
372 MCI_GENERIC_PARMS mgp; |
|
373 |
|
374 mgp.hwndCallback = (HWND)NULL; // None |
|
375 mciSendCommand(cdrom->id,MCI_CLOSE,MCI_WAIT,&mgp, 0); |
|
376 } |
|
377 |
|
378 /* Finalize CDROM Subsystem - Ready for MCI */ |
|
379 void SDL_SYS_CDQuit(void) |
|
380 { |
|
381 int i; |
|
382 |
|
383 if ( SDL_numcds > 0 ) |
|
384 { |
|
385 for ( i=0; i<SDL_numcds; ++i ) |
|
386 { |
|
387 SDL_free(SDL_cdlist[i]); |
|
388 } |
|
389 SDL_numcds = 0; |
|
390 } |
|
391 } |
|
392 |
|
393 #endif /* SDL_CDROM_OS2 */ |