Home | History | Annotate | Download | only in os2
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 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 (at) 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 */
    394