Home | History | Annotate | Download | only in mint
      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 (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 /*
     25 	MiNT audio driver
     26 	using XBIOS functions (Falcon)
     27 
     28 	Patrice Mandin, Didier Mquignon
     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 }
    496