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