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