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