symbian-qemu-0.9.1-12/libsdl-trunk/src/audio/mint/SDL_mintaudio_xbios.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2     SDL - Simple DirectMedia Layer
       
     3     Copyright (C) 1997-2004 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 /*
       
    25 	MiNT audio driver
       
    26 	using XBIOS functions (Falcon)
       
    27 
       
    28 	Patrice Mandin, Didier Méquignon
       
    29 */
       
    30 
       
    31 #include <unistd.h>
       
    32 #include <support.h>
       
    33 
       
    34 /* Mint includes */
       
    35 #include <mint/osbind.h>
       
    36 #include <mint/falcon.h>
       
    37 #include <mint/cookie.h>
       
    38 
       
    39 #include "SDL_audio.h"
       
    40 #include "../SDL_audio_c.h"
       
    41 #include "../SDL_sysaudio.h"
       
    42 
       
    43 #include "../../video/ataricommon/SDL_atarimxalloc_c.h"
       
    44 
       
    45 #include "SDL_mintaudio.h"
       
    46 #include "SDL_mintaudio_dma8.h"
       
    47 
       
    48 /*--- Defines ---*/
       
    49 
       
    50 #define MINT_AUDIO_DRIVER_NAME "mint_xbios"
       
    51 
       
    52 /* Debug print info */
       
    53 #define DEBUG_NAME "audio:xbios: "
       
    54 #if 0
       
    55 #define DEBUG_PRINT(what) \
       
    56 	{ \
       
    57 		printf what; \
       
    58 	}
       
    59 #else
       
    60 #define DEBUG_PRINT(what)
       
    61 #endif
       
    62 
       
    63 /*--- Static variables ---*/
       
    64 
       
    65 static unsigned long cookie_snd;
       
    66 
       
    67 /*--- Audio driver functions ---*/
       
    68 
       
    69 static void Mint_CloseAudio(_THIS);
       
    70 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
       
    71 static void Mint_LockAudio(_THIS);
       
    72 static void Mint_UnlockAudio(_THIS);
       
    73 
       
    74 /* To check/init hardware audio */
       
    75 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
       
    76 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
       
    77 
       
    78 /*--- Audio driver bootstrap functions ---*/
       
    79 
       
    80 static int Audio_Available(void)
       
    81 {
       
    82 	unsigned long dummy;
       
    83 	const char *envr = SDL_getenv("SDL_AUDIODRIVER");
       
    84 
       
    85 	/*SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND);*/
       
    86 	SDL_MintAudio_mint_present = SDL_FALSE;
       
    87 
       
    88 	/* We can't use XBIOS in interrupt with Magic, don't know about thread */
       
    89 	if (Getcookie(C_MagX, &dummy) == C_FOUND) {
       
    90 		return(0);
       
    91 	}
       
    92 
       
    93 	/* Check if user asked a different audio driver */
       
    94 	if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
       
    95 		DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
       
    96 		return(0);
       
    97 	}
       
    98 
       
    99 	/* Cookie _SND present ? if not, assume ST machine */
       
   100 	if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
       
   101 		cookie_snd = SND_PSG;
       
   102 	}
       
   103 
       
   104 	/* Check if we have 16 bits audio */
       
   105 	if ((cookie_snd & SND_16BIT)==0) {
       
   106 		DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
       
   107 	    return(0);
       
   108 	}
       
   109 
       
   110 	/* Check if audio is lockable */
       
   111 	if (Locksnd()!=1) {
       
   112 		DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
       
   113 		return(0);
       
   114 	}
       
   115 
       
   116 	Unlocksnd();
       
   117 
       
   118 	DEBUG_PRINT((DEBUG_NAME "XBIOS audio available!\n"));
       
   119 	return(1);
       
   120 }
       
   121 
       
   122 static void Audio_DeleteDevice(SDL_AudioDevice *device)
       
   123 {
       
   124     SDL_free(device->hidden);
       
   125     SDL_free(device);
       
   126 }
       
   127 
       
   128 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
       
   129 {
       
   130 	SDL_AudioDevice *this;
       
   131 
       
   132 	/* Initialize all variables that we clean on shutdown */
       
   133 	this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
       
   134     if ( this ) {
       
   135         SDL_memset(this, 0, (sizeof *this));
       
   136         this->hidden = (struct SDL_PrivateAudioData *)
       
   137                 SDL_malloc((sizeof *this->hidden));
       
   138     }
       
   139     if ( (this == NULL) || (this->hidden == NULL) ) {
       
   140         SDL_OutOfMemory();
       
   141         if ( this ) {
       
   142             SDL_free(this);
       
   143         }
       
   144         return(0);
       
   145     }
       
   146     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
       
   147 
       
   148     /* Set the function pointers */
       
   149     this->OpenAudio   = Mint_OpenAudio;
       
   150     this->CloseAudio  = Mint_CloseAudio;
       
   151     this->LockAudio   = Mint_LockAudio;
       
   152     this->UnlockAudio = Mint_UnlockAudio;
       
   153     this->free        = Audio_DeleteDevice;
       
   154 
       
   155     return this;
       
   156 }
       
   157 
       
   158 AudioBootStrap MINTAUDIO_XBIOS_bootstrap = {
       
   159 	MINT_AUDIO_DRIVER_NAME, "MiNT XBIOS audio driver",
       
   160 	Audio_Available, Audio_CreateDevice
       
   161 };
       
   162 
       
   163 static void Mint_LockAudio(_THIS)
       
   164 {
       
   165 	/* Stop replay */
       
   166 	Buffoper(0);
       
   167 }
       
   168 
       
   169 static void Mint_UnlockAudio(_THIS)
       
   170 {
       
   171 	/* Restart replay */
       
   172 	Buffoper(SB_PLA_ENA|SB_PLA_RPT);
       
   173 }
       
   174 
       
   175 static void Mint_CloseAudio(_THIS)
       
   176 {
       
   177 	/* Stop replay */
       
   178 	SDL_MintAudio_WaitThread();
       
   179 	Buffoper(0);
       
   180 
       
   181 	if (!SDL_MintAudio_mint_present) {
       
   182 		/* Uninstall interrupt */
       
   183 		Jdisint(MFP_DMASOUND);
       
   184 	}
       
   185 
       
   186 	/* Wait if currently playing sound */
       
   187 	while (SDL_MintAudio_mutex != 0) {
       
   188 	}
       
   189 
       
   190 	/* Clear buffers */
       
   191 	if (SDL_MintAudio_audiobuf[0]) {
       
   192 		Mfree(SDL_MintAudio_audiobuf[0]);
       
   193 		SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
       
   194 	}
       
   195 
       
   196 	/* Unlock sound system */
       
   197 	Unlocksnd();
       
   198 }
       
   199 
       
   200 /* Falcon XBIOS implementation of Devconnect() is buggy with external clock */
       
   201 static void Devconnect2(int src, int dst, int sclk, int pre)
       
   202 {		
       
   203 	static const unsigned short MASK1[3] = { 0, 0x6000, 0 };
       
   204 	static const unsigned short MASK2[4] = { 0xFFF0, 0xFF8F, 0xF0FF, 0x0FFF };
       
   205 	static const unsigned short INDEX1[4] = {  1, 3, 5, 7 };
       
   206 	static const unsigned short INDEX2[4] = {  0, 2, 4, 6 };
       
   207 	unsigned short sync_div,dev_ctrl,dest_ctrl;
       
   208 	void *oldstack;
       
   209 
       
   210 	if (dst==0) {
       
   211 		return;
       
   212 	}
       
   213 
       
   214 	oldstack=(void *)Super(0);
       
   215 
       
   216 	dev_ctrl = DMAAUDIO_IO.dev_ctrl;
       
   217 	dest_ctrl = DMAAUDIO_IO.dest_ctrl;
       
   218 	dev_ctrl &= MASK2[src];
       
   219 
       
   220 	if (src==ADC) {
       
   221 		dev_ctrl |= MASK1[sclk];
       
   222 	} else {
       
   223 		dev_ctrl |= (INDEX1[sclk] << (src<<4));
       
   224 	}
       
   225 
       
   226 	if (dst & DMAREC) {		
       
   227 		dest_ctrl &= 0xFFF0;
       
   228 		dest_ctrl |= INDEX1[src];
       
   229 	}
       
   230 
       
   231 	if (dst & DSPRECV) {		
       
   232 		dest_ctrl &= 0xFF8F;
       
   233 		dest_ctrl |= (INDEX1[src]<<4); 
       
   234 	}
       
   235 
       
   236 	if (dst & EXTOUT) {		
       
   237 		dest_ctrl &= 0xF0FF;
       
   238 		dest_ctrl |= (INDEX1[src]<<8); 
       
   239 	}
       
   240 
       
   241 	if (dst & DAC) {		
       
   242 		dev_ctrl &= 0x0FFF;
       
   243 		dev_ctrl |= MASK1[sclk]; 
       
   244 		dest_ctrl &=  0x0FFF;
       
   245 		dest_ctrl |= (INDEX2[src]<<12); 
       
   246 	}
       
   247 
       
   248 	sync_div = DMAAUDIO_IO.sync_div;
       
   249 	if (sclk==CLKEXT) {
       
   250 		pre<<=8;
       
   251 		sync_div &= 0xF0FF;
       
   252 	} else {
       
   253 		sync_div &= 0xFFF0;
       
   254 	}
       
   255 	sync_div |= pre;
       
   256 
       
   257 	DMAAUDIO_IO.dev_ctrl = dev_ctrl;
       
   258 	DMAAUDIO_IO.dest_ctrl = dest_ctrl;
       
   259 	DMAAUDIO_IO.sync_div = sync_div;
       
   260 
       
   261 	Super(oldstack);
       
   262 }
       
   263 
       
   264 static void Mint_CheckExternalClock(_THIS)
       
   265 {
       
   266 #define SIZE_BUF_CLOCK_MEASURE (44100/10)
       
   267 
       
   268 	unsigned long cookie_snd;
       
   269 	char *buffer;
       
   270 	int i, j;
       
   271 
       
   272 	/* DSP present with its GPIO port ? */
       
   273 	if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
       
   274 		return;
       
   275 	}
       
   276 	if ((cookie_snd & SND_DSP)==0) {
       
   277 		return;
       
   278 	}
       
   279 
       
   280 	buffer = Atari_SysMalloc(SIZE_BUF_CLOCK_MEASURE, MX_STRAM);
       
   281 	if (buffer==NULL) {
       
   282 		DEBUG_PRINT((DEBUG_NAME "Not enough memory for the measure\n"));
       
   283 		return;
       
   284 	}
       
   285 	SDL_memset(buffer, 0, SIZE_BUF_CLOCK_MEASURE);
       
   286 
       
   287 	Buffoper(0);
       
   288 	Settracks(0,0);
       
   289 	Setmontracks(0);
       
   290 	Setmode(MONO8);
       
   291 	Jdisint(MFP_TIMERA);
       
   292 
       
   293 	for (i=0; i<2; i++) {
       
   294 		Gpio(GPIO_SET,7);      /* DSP port gpio outputs */
       
   295 		Gpio(GPIO_WRITE,2+i);  /* 22.5792/24.576 MHz for 44.1/48KHz */
       
   296 		Devconnect2(DMAPLAY, DAC, CLKEXT, CLK50K);  /* Matrix and clock source */
       
   297 		Setbuffer(0, buffer, buffer + SIZE_BUF_CLOCK_MEASURE);		           /* Set buffer */
       
   298 		Xbtimer(XB_TIMERA, 5, 38, SDL_MintAudio_XbiosInterruptMeasureClock); /* delay mode timer A, prediv /64, 1KHz */
       
   299 		Jenabint(MFP_TIMERA);
       
   300 		SDL_MintAudio_clocktics = 0;
       
   301 		Buffoper(SB_PLA_ENA);
       
   302 		usleep(110000);
       
   303 
       
   304 		if((Buffoper(-1) & 1)==0) {
       
   305 			if (SDL_MintAudio_clocktics) {
       
   306 				unsigned long khz;
       
   307 
       
   308 				khz = ((SIZE_BUF_CLOCK_MEASURE/SDL_MintAudio_clocktics) +1) & 0xFFFFFFFE;
       
   309 				DEBUG_PRINT((DEBUG_NAME "measure %d: freq=%lu KHz\n", i+1, khz));
       
   310 
       
   311 				if(khz==44) {
       
   312 					for (j=1; j<4; j++) {
       
   313 						SDL_MintAudio_AddFrequency(this, MASTERCLOCK_44K/(MASTERPREDIV_FALCON*(1<<j)), MASTERCLOCK_44K, (1<<j)-1, 2+i);
       
   314 					}
       
   315 				} else if (khz==48) {
       
   316 					for (j=1; j<4; j++) {
       
   317 						SDL_MintAudio_AddFrequency(this, MASTERCLOCK_48K/(MASTERPREDIV_FALCON*(1<<j)), MASTERCLOCK_48K, (1<<j)-1, 2+i);
       
   318 					}
       
   319 				}
       
   320 			} else {
       
   321 				DEBUG_PRINT((DEBUG_NAME "No measure\n"));
       
   322 			}
       
   323 		} else {
       
   324 			DEBUG_PRINT((DEBUG_NAME "No SDMA clock\n"));
       
   325 		}
       
   326 
       
   327 		Buffoper(0);             /* stop */
       
   328 		Jdisint(MFP_TIMERA);     /* Uninstall interrupt */
       
   329 	}
       
   330 
       
   331 	Mfree(buffer);
       
   332 }
       
   333 
       
   334 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
       
   335 {
       
   336 	int i;
       
   337 	Uint32 extclock;
       
   338 
       
   339 	DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
       
   340 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
       
   341 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
       
   342 	DEBUG_PRINT(("channels=%d, ", spec->channels));
       
   343 	DEBUG_PRINT(("freq=%d\n", spec->freq));
       
   344 
       
   345     if (spec->channels > 2) {
       
   346         spec->channels = 2;  /* no more than stereo! */
       
   347     }
       
   348 
       
   349 	spec->format |= 0x8000;	/* Audio is always signed */
       
   350 	if ((spec->format & 0x00ff)==16) {
       
   351 		spec->format |= 0x1000;	/* Audio is always big endian */
       
   352 		spec->channels=2;	/* 16 bits always stereo */
       
   353 	}
       
   354 
       
   355 	MINTAUDIO_freqcount=0;
       
   356 
       
   357 	/* Add external clocks if present */
       
   358 	Mint_CheckExternalClock(this);
       
   359 
       
   360 	/* Standard clocks */
       
   361 	for (i=1;i<12;i++) {
       
   362 		/* Remove unusable Falcon codec predivisors */
       
   363 		if ((i==6) || (i==8) || (i==10)) {
       
   364 			continue;
       
   365 		}
       
   366 		SDL_MintAudio_AddFrequency(this, MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1)), MASTERCLOCK_FALCON1, i, -1);
       
   367 	}
       
   368 
       
   369 #if 1
       
   370 	for (i=0; i<MINTAUDIO_freqcount; i++) {
       
   371 		DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
       
   372 			i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
       
   373 			MINTAUDIO_frequencies[i].predivisor
       
   374 		));
       
   375 	}
       
   376 #endif
       
   377 
       
   378 	MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
       
   379 	spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
       
   380 
       
   381 	DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
       
   382 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
       
   383 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
       
   384 	DEBUG_PRINT(("channels=%d, ", spec->channels));
       
   385 	DEBUG_PRINT(("freq=%d\n", spec->freq));
       
   386 
       
   387 	return 0;
       
   388 }
       
   389 
       
   390 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
       
   391 {
       
   392 	int channels_mode, dmaclock, prediv;
       
   393 	void *buffer;
       
   394 
       
   395 	/* Stop currently playing sound */
       
   396 	SDL_MintAudio_quit_thread = SDL_FALSE;
       
   397 	SDL_MintAudio_thread_finished = SDL_TRUE;
       
   398 	SDL_MintAudio_WaitThread();
       
   399 	Buffoper(0);
       
   400 
       
   401 	/* Set replay tracks */
       
   402 	Settracks(0,0);
       
   403 	Setmontracks(0);
       
   404 
       
   405 	/* Select replay format */
       
   406 	channels_mode=STEREO16;
       
   407 	switch (spec->format & 0xff) {
       
   408 		case 8:
       
   409 			if (spec->channels==2) {
       
   410 				channels_mode=STEREO8;
       
   411 			} else {
       
   412 				channels_mode=MONO8;
       
   413 			}
       
   414 			break;
       
   415 	}
       
   416 	if (Setmode(channels_mode)<0) {
       
   417 		DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
       
   418 	}
       
   419 
       
   420 	dmaclock = MINTAUDIO_frequencies[MINTAUDIO_numfreq].masterclock;
       
   421 	prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
       
   422 	if (MINTAUDIO_frequencies[MINTAUDIO_numfreq].gpio_bits != -1) {
       
   423 		Gpio(GPIO_SET,7);		/* DSP port gpio outputs */
       
   424 		Gpio(GPIO_WRITE, MINTAUDIO_frequencies[MINTAUDIO_numfreq].gpio_bits);
       
   425 		Devconnect2(DMAPLAY, DAC|EXTOUT, CLKEXT, prediv);
       
   426 	} else {
       
   427 		Devconnect2(DMAPLAY, DAC, CLK25M, prediv);
       
   428 	}
       
   429 
       
   430 	/* Set buffer */
       
   431 	buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
       
   432 	if (Setbuffer(0, buffer, buffer + spec->size)<0) {
       
   433 		DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
       
   434 	}
       
   435 	
       
   436 	if (SDL_MintAudio_mint_present) {
       
   437 		SDL_MintAudio_thread_pid = tfork(SDL_MintAudio_Thread, 0);
       
   438 	} else {
       
   439 		/* Install interrupt */
       
   440 		Jdisint(MFP_DMASOUND);
       
   441 		/*Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt);*/
       
   442 		Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt);
       
   443 		Jenabint(MFP_DMASOUND);
       
   444 
       
   445 		if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
       
   446 			DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
       
   447 		}
       
   448 	}
       
   449 
       
   450 	/* Go */
       
   451 	Buffoper(SB_PLA_ENA|SB_PLA_RPT);
       
   452 	DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
       
   453 }
       
   454 
       
   455 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
       
   456 {
       
   457 	/* Lock sound system */
       
   458 	if (Locksnd()!=1) {
       
   459    	    SDL_SetError("Mint_OpenAudio: Audio system already in use");
       
   460         return(-1);
       
   461 	}
       
   462 
       
   463 	SDL_MintAudio_device = this;
       
   464 
       
   465 	/* Check audio capabilities */
       
   466 	if (Mint_CheckAudio(this, spec)==-1) {
       
   467 		return -1;
       
   468 	}
       
   469 
       
   470 	SDL_CalculateAudioSpec(spec);
       
   471 
       
   472 	/* Allocate memory for audio buffers in DMA-able RAM */
       
   473 	DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
       
   474 
       
   475 	SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
       
   476 	if (SDL_MintAudio_audiobuf[0]==NULL) {
       
   477 		SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
       
   478 		return (-1);
       
   479 	}
       
   480 	SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
       
   481 	SDL_MintAudio_numbuf=0;
       
   482 	SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
       
   483 	SDL_MintAudio_audiosize = spec->size;
       
   484 	SDL_MintAudio_mutex = 0;
       
   485 
       
   486 	DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
       
   487 	DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
       
   488 
       
   489 	SDL_MintAudio_CheckFpu();
       
   490 
       
   491 	/* Setup audio hardware */
       
   492 	Mint_InitAudio(this, spec);
       
   493 
       
   494     return(1);	/* We don't use SDL threaded audio */
       
   495 }