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