Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / devs / AHI / Drivers / SB128 / sb128.c
blobe19061f983388a1267e692e88b10f1781833f018
1 /*
3 The contents of this file are subject to the AROS Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
4 http://www.aros.org/license.html
6 Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
7 ANY KIND, either express or implied. See the License for the specific language governing rights and
8 limitations under the License.
10 The Original Code is (C) Copyright 2004-2011 Ross Vumbaca.
12 The Initial Developer of the Original Code is Ross Vumbaca.
14 All Rights Reserved.
18 #if !defined(__AROS__)
19 #undef __USE_INLINE__
20 #include <proto/expansion.h>
21 extern struct UtilityIFace* IUtility;
22 extern struct AHIsubIFace* IAHIsub;
23 extern struct MMUIFace* IMMU;
24 #endif
26 #include <devices/ahi.h>
27 #include <exec/memory.h>
28 #include <libraries/ahi_sub.h>
30 #include <proto/ahi_sub.h>
31 #include <proto/exec.h>
32 #include <proto/dos.h>
33 #include <proto/utility.h>
35 #ifdef __AROS__
36 #include <aros/debug.h>
37 #endif
38 #include <string.h>
40 #include "library.h"
41 #include "regs.h"
42 #include "misc.h"
43 #include "pci_wrapper.h"
45 extern void rate_set_dac2(struct SB128_DATA *card, unsigned long rate);
46 extern void rate_set_adc(struct SB128_DATA *card, unsigned long rate);
48 /******************************************************************************
49 ** Globals ********************************************************************
50 ******************************************************************************/
52 #define FREQUENCIES 11
54 static const ULONG Frequencies[ FREQUENCIES ] =
56 5500,
57 8000, /* ยต- and A-Law */
58 9600,
59 11025, /* CD/4 */
60 16000, /* DAT/3 */
61 19200,
62 22050, /* CD/2 */
63 32000, /* DAT/1.5 */
64 38400,
65 44100, /* CD */
66 48000 /* DAT */
69 #define INPUTS 6
71 static const STRPTR Inputs[ INPUTS ] =
73 "Line in",
74 "Mic",
75 "CD",
76 "Aux",
77 "Mixer",
78 "Phone"
81 /* Not static since it's used in misc.c too */
82 const UWORD InputBits[ INPUTS ] =
84 AC97_RECMUX_LINE,
85 AC97_RECMUX_MIC,
86 AC97_RECMUX_CD,
87 AC97_RECMUX_AUX,
88 AC97_RECMUX_STEREO_MIX,
89 AC97_RECMUX_PHONE
93 #define OUTPUTS 1
95 static const STRPTR Outputs[ OUTPUTS ] =
97 "Front",
101 /******************************************************************************
102 ** AHIsub_AllocAudio **********************************************************
103 ******************************************************************************/
105 ULONG
106 _AHIsub_AllocAudio( struct TagItem* taglist,
107 struct AHIAudioCtrlDrv* AudioCtrl,
108 struct DriverBase* AHIsubBase )
110 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
112 int card_num;
113 ULONG ret;
114 int i;
116 card_num = ( GetTagData( AHIDB_AudioID, 0, taglist) & 0x0000f000 ) >> 12;
118 if( card_num >= SB128Base->cards_found ||
119 SB128Base->driverdatas[ card_num ] == NULL )
121 Req( "No Card Data for card %ld.", card_num );
122 return AHISF_ERROR;
124 else
126 struct SB128_DATA* card;
127 BOOL in_use;
129 card = SB128Base->driverdatas[ card_num ];
130 AudioCtrl->ahiac_DriverData = card;
132 ObtainSemaphore( &SB128Base->semaphore );
133 in_use = ( card->audioctrl != NULL );
134 if( !in_use )
136 card->audioctrl = AudioCtrl;
138 ReleaseSemaphore( &SB128Base->semaphore );
140 if( in_use )
142 return AHISF_ERROR;
145 card->playback_interrupt_enabled = FALSE;
146 card->record_interrupt_enabled = FALSE;
147 /* Clears playback/record interrupts */
148 pci_outl((pci_inl(SB128_SCON, card)) & SB128_IRQ_MASK, SB128_SCON, card);
151 ret = AHISF_KNOWHIFI | AHISF_KNOWSTEREO | AHISF_MIXING | AHISF_TIMING;
154 for( i = 0; i < FREQUENCIES; ++i )
156 if( AudioCtrl->ahiac_MixFreq == Frequencies[ i ] )
158 ret |= AHISF_CANRECORD;
159 break;
163 return ret;
168 /******************************************************************************
169 ** AHIsub_FreeAudio ***********************************************************
170 ******************************************************************************/
172 void
173 _AHIsub_FreeAudio( struct AHIAudioCtrlDrv* AudioCtrl,
174 struct DriverBase* AHIsubBase )
176 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
177 struct SB128_DATA* card = (struct SB128_DATA*) AudioCtrl->ahiac_DriverData;
179 if( card != NULL )
181 ObtainSemaphore( &SB128Base->semaphore );
182 if( card->audioctrl == AudioCtrl )
184 /* Release it if we own it. */
185 card->audioctrl = NULL;
187 ReleaseSemaphore( &SB128Base->semaphore );
189 AudioCtrl->ahiac_DriverData = NULL;
194 /******************************************************************************
195 ** AHIsub_Disable *************************************************************
196 ******************************************************************************/
198 void
199 _AHIsub_Disable( struct AHIAudioCtrlDrv* AudioCtrl,
200 struct DriverBase* AHIsubBase )
202 /* V6 drivers do not have to preserve all registers */
204 Disable();
208 /******************************************************************************
209 ** AHIsub_Enable **************************************************************
210 ******************************************************************************/
212 void
213 _AHIsub_Enable( struct AHIAudioCtrlDrv* AudioCtrl,
214 struct DriverBase* AHIsubBase )
216 /* V6 drivers do not have to preserve all registers */
218 Enable();
222 /******************************************************************************
223 ** AHIsub_Start ***************************************************************
224 ******************************************************************************/
226 ULONG
227 _AHIsub_Start( ULONG flags,
228 struct AHIAudioCtrlDrv* AudioCtrl,
229 struct DriverBase* AHIsubBase )
231 struct SB128_DATA* card = (struct SB128_DATA*) AudioCtrl->ahiac_DriverData;
232 unsigned long PlayCtrlFlags = 0, RecCtrlFlags = 0;
233 ULONG dma_buffer_size = 0;
234 int i, freqbit = 9;
235 APTR stack;
237 for( i = 0; i < FREQUENCIES; ++i )
239 if( AudioCtrl->ahiac_MixFreq == Frequencies[ i ] )
241 freqbit = i;
242 break;
246 if( flags & AHISF_PLAY )
249 ULONG dma_sample_frame_size;
250 unsigned short ChannelsFlag;
252 ChannelsFlag = 0;
254 /* Update cached/syncronized variables */
256 AHIsub_Update( AHISF_PLAY, AudioCtrl );
258 /* Allocate a new mixing buffer. Note: The buffer must be cleared, since
259 it might not be filled by the mixer software interrupt because of
260 pretimer/posttimer! */
262 card->mix_buffer = AllocVec( AudioCtrl->ahiac_BuffSize,
263 MEMF_PUBLIC | MEMF_CLEAR );
265 if( card->mix_buffer == NULL )
267 Req( "Unable to allocate %ld bytes for mixing buffer.",
268 AudioCtrl->ahiac_BuffSize );
269 return AHIE_NOMEM;
272 /* Allocate a buffer large enough for 16-bit double-buffered
273 playback (mono or stereo) */
275 if( AudioCtrl->ahiac_Flags & AHIACF_STEREO )
277 dma_sample_frame_size = 4;
278 dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size;
279 ChannelsFlag = SB128_STEREO;
281 else
283 dma_sample_frame_size = 2;
284 dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size;
287 card->playback_buffer = pci_alloc_consistent(dma_buffer_size * 2, &card->playback_buffer_nonaligned, 128);
289 if (!card->playback_buffer)
291 Req( "Unable to allocate playback buffer." );
292 return AHIE_NOMEM;
295 /* Enable Playback interrupt */
296 pci_outl((pci_inl(SB128_SCON, card) | SB128_DAC2_INTEN), SB128_SCON, card);
298 card->current_bytesize = dma_buffer_size;
299 card->current_frames = AudioCtrl->ahiac_MaxBuffSamples;
300 card->current_buffer = card->playback_buffer + card->current_bytesize;
301 card->playback_interrupt_enabled = TRUE;
303 card->flip = 0;
305 /* Select the DAC2 Memory Page */
306 pci_outl(SB128_PAGE_DAC, SB128_MEMPAGE, card);
308 /* Buffer address and length (in longwords) is set */
309 stack = SuperState();
310 // card->playback_buffer_phys = IMMU->GetPhysicalAddress(card->playback_buffer);
311 card->playback_buffer_phys = card->playback_buffer;
312 UserState(stack);
314 pci_outl((unsigned long)(card->playback_buffer_phys), SB128_DAC2_FRAME, card);
315 pci_outl((((dma_buffer_size * 2) >> 2) - 1) & 0xFFFF, SB128_DAC2_COUNT, card);
317 /* Playback format is always 16 Bit, Stereo, but checks exist in case of a Mono mode (not possible). */
318 PlayCtrlFlags = (SB128_16BIT | ChannelsFlag) << 2;
320 /* Set frequency */
321 if (card->currentPlayFreq != freqbit)
323 rate_set_dac2(card, Frequencies[freqbit]);
324 card->currentPlayFreq = freqbit;
326 card->is_playing = TRUE;
329 if( flags & AHISF_RECORD )
331 card->current_record_bytesize = RECORD_BUFFER_SAMPLES * 4;
333 /* Allocate a new recording buffer (page aligned!) */
334 card->record_buffer = pci_alloc_consistent(card->current_record_bytesize * 2, &card->record_buffer_nonaligned, 128);
336 if( card->record_buffer == NULL )
338 Req( "Unable to allocate %ld bytes for the recording buffer.", card->current_record_bytesize);
339 return AHIE_NOMEM;
342 SaveMixerState( card );
343 UpdateMonitorMixer( card );
345 /* Enable record interrupt */
346 pci_outl((pci_inl(SB128_SCON, card) | SB128_ADC_INTEN), SB128_SCON, card);
348 card->record_interrupt_enabled = TRUE;
350 card->recflip = 0;
352 /* Select the ADC Memory Page */
353 pci_outl(SB128_PAGE_ADC, SB128_MEMPAGE, card);
355 /* Buffer address and length (in longwords) is set */
356 stack = SuperState();
357 // card->record_buffer_phys = IMMU->GetPhysicalAddress(card->record_buffer);
358 card->record_buffer_phys = card->record_buffer;
359 UserState(stack);
361 pci_outl((unsigned long) card->record_buffer_phys, SB128_ADC_FRAME, card);
362 pci_outl((((card->current_record_bytesize * 2) >> 2) - 1) & 0xFFFF, SB128_ADC_COUNT, card);
364 card->is_recording = TRUE;
365 card->current_record_buffer = card->record_buffer + card->current_record_bytesize;
367 /* Record format is always 16 Bit, Stereo */
368 RecCtrlFlags = (SB128_16BIT | SB128_STEREO) << 4;
370 /* Set frequency */
371 if (card->currentRecFreq != freqbit)
373 rate_set_adc(card, Frequencies[freqbit]);
374 card->currentRecFreq = freqbit;
378 if( flags & AHISF_PLAY )
380 /* Set Sample Count per Interrupt */
381 if (PlayCtrlFlags & 0x04)
383 pci_outl(((dma_buffer_size >> 2) - 1) & 0xFFFF, SB128_DAC2_SCOUNT, card);
385 else
387 pci_outl(((dma_buffer_size >> 1) - 1) & 0xFFFF, SB128_DAC2_SCOUNT, card);
389 /* Set format, ENDINC set to 2 */
390 pci_outl((pci_inl(SB128_SCON, card) | PlayCtrlFlags | 2 << 19), SB128_SCON, card);
391 /* Start playback! */
392 pci_outl((pci_inl(SB128_CONTROL, card) | CTRL_DAC2_EN), SB128_CONTROL, card);
395 if( flags & AHISF_RECORD )
397 /* Set Sample Count per Interrupt */
398 pci_outl(((card->current_record_bytesize >> 2) - 1) & 0xFFFF, SB128_ADC_SCOUNT, card);
399 /* Set format */
400 pci_outl((pci_inl(SB128_SCON, card) | RecCtrlFlags), SB128_SCON, card);
401 /* Start recording! */
402 pci_outl((pci_inl(SB128_CONTROL, card) | CTRL_ADC_EN), SB128_CONTROL, card);
405 return AHIE_OK;
409 /******************************************************************************
410 ** AHIsub_Update **************************************************************
411 ******************************************************************************/
413 void
414 _AHIsub_Update( ULONG flags,
415 struct AHIAudioCtrlDrv* AudioCtrl,
416 struct DriverBase* AHIsubBase )
418 struct SB128_DATA* card = (struct SB128_DATA*) AudioCtrl->ahiac_DriverData;
420 card->current_frames = AudioCtrl->ahiac_BuffSamples;
422 if( AudioCtrl->ahiac_Flags & AHIACF_STEREO )
424 card->current_bytesize = card->current_frames * 4;
426 else
428 card->current_bytesize = card->current_frames * 2;
433 /******************************************************************************
434 ** AHIsub_Stop ****************************************************************
435 ******************************************************************************/
437 void
438 _AHIsub_Stop( ULONG flags,
439 struct AHIAudioCtrlDrv* AudioCtrl,
440 struct DriverBase* AHIsubBase )
442 struct SB128_DATA* card = (struct SB128_DATA*) AudioCtrl->ahiac_DriverData;
444 if( flags & AHISF_PLAY )
446 unsigned long play_ctl;
447 card->is_playing= FALSE;
449 play_ctl = pci_inl(SB128_CONTROL, card);
450 play_ctl &= ~(CTRL_DAC2_EN);
451 /* Stop */
452 pci_outl(play_ctl, SB128_CONTROL, card);
454 /* Clear and mask interrupts */
455 pci_outl((pci_inl(SB128_SCON, card)) & SB128_IRQ_MASK, SB128_SCON, card);
457 if (card->current_bytesize > 0)
458 pci_free_consistent(card->playback_buffer_nonaligned);
460 card->current_bytesize = 0;
461 card->current_frames = 0;
462 card->current_buffer = NULL;
464 if ( card->mix_buffer)
465 FreeVec( card->mix_buffer );
466 card->mix_buffer = NULL;
467 card->playback_interrupt_enabled = FALSE;
468 card->current_bytesize = 0;
471 if( flags & AHISF_RECORD )
473 unsigned long rec_ctl;
475 rec_ctl = pci_inl(SB128_CONTROL, card);
476 rec_ctl &= ~(CTRL_ADC_EN);
477 /* Stop */
478 pci_outl(rec_ctl, SB128_CONTROL, card);
480 /* Clear and mask interrupts */
481 pci_outl((pci_inl(SB128_SCON, card)) & SB128_IRQ_MASK, SB128_SCON, card);
483 if( card->is_recording )
485 /* Do not restore mixer unless they have been saved */
486 RestoreMixerState( card );
489 if( card->record_buffer != NULL )
491 pci_free_consistent( card->record_buffer_nonaligned);
494 card->record_buffer = NULL;
495 card->current_record_bytesize = 0;
497 card->is_recording = FALSE;
498 card->record_interrupt_enabled = FALSE;
505 /******************************************************************************
506 ** AHIsub_GetAttr *************************************************************
507 ******************************************************************************/
509 LONG
510 _AHIsub_GetAttr( ULONG attribute,
511 LONG argument,
512 LONG def,
513 struct TagItem* taglist,
514 struct AHIAudioCtrlDrv* AudioCtrl,
515 struct DriverBase* AHIsubBase )
517 int i;
519 switch( attribute )
521 case AHIDB_Bits:
522 return 16;
524 case AHIDB_Frequencies:
525 return FREQUENCIES;
527 case AHIDB_Frequency: /* Index->Frequency */
528 return (LONG) Frequencies[ argument ];
530 case AHIDB_Index: /* Frequency->Index */
531 if( argument <= (LONG) Frequencies[ 0 ] )
533 return 0;
536 if( argument >= (LONG) Frequencies[ FREQUENCIES - 1 ] )
538 return FREQUENCIES-1;
541 for( i = 1; i < FREQUENCIES; i++ )
543 if( (LONG) Frequencies[ i ] > argument )
545 if( ( argument - (LONG) Frequencies[ i - 1 ] ) < ( (LONG) Frequencies[ i ] - argument ) )
547 return i-1;
549 else
551 return i;
556 return 0; /* Will not happen */
558 case AHIDB_Author:
559 return (LONG) "Ross Vumbaca";
561 case AHIDB_Copyright:
562 return (LONG) "(C) Ross Vumbaca";
564 case AHIDB_Version:
565 return (LONG) LibIDString;
567 case AHIDB_Annotation:
568 return (LONG)
569 "AROS SB128/ES137x Audio driver";
571 case AHIDB_Record:
572 return TRUE;
574 case AHIDB_FullDuplex:
575 return TRUE;
577 case AHIDB_Realtime:
578 return TRUE;
580 case AHIDB_MaxRecordSamples:
581 return RECORD_BUFFER_SAMPLES;
583 /* formula's:
584 #include <math.h>
586 unsigned long res = (unsigned long) (0x10000 * pow (10.0, dB / 20.0));
587 double dB = 20.0 * log10(0xVALUE / 65536.0);
589 printf("dB = %f, res = %lx\n", dB, res);*/
591 case AHIDB_MinMonitorVolume:
592 return 0x004d2;
594 case AHIDB_MaxMonitorVolume:
595 return 0x3fb27;
597 case AHIDB_MinInputGain:
598 return 0x10000; /* 0.0 dB gain */
600 case AHIDB_MaxInputGain:
601 return 0xD55D0; /* 22.5 dB gain */
603 case AHIDB_MinOutputVolume:
604 return 0x004d2; /* -34.5 dB / mute */
606 case AHIDB_MaxOutputVolume:
607 return 0x3fb27; /* 12 dB */
609 case AHIDB_Inputs:
610 return INPUTS;
612 case AHIDB_Input:
613 return (LONG) Inputs[ argument ];
615 case AHIDB_Outputs:
616 return OUTPUTS;
618 case AHIDB_Output:
619 return (LONG) Outputs[ argument ];
621 default:
622 return def;
627 /******************************************************************************
628 ** AHIsub_HardwareControl *****************************************************
629 ******************************************************************************/
631 ULONG
632 _AHIsub_HardwareControl( ULONG attribute,
633 LONG argument,
634 struct AHIAudioCtrlDrv* AudioCtrl,
635 struct DriverBase* AHIsubBase )
637 struct SB128_DATA* card = (struct SB128_DATA*) AudioCtrl->ahiac_DriverData;
639 switch( attribute )
641 case AHIC_MonitorVolume:
642 card->monitor_volume = Linear2MixerGain( (Fixed) argument, &card->monitor_volume_bits );
643 if( card->is_recording )
645 UpdateMonitorMixer( card );
647 return TRUE;
649 case AHIC_MonitorVolume_Query:
650 return card->monitor_volume;
652 case AHIC_InputGain:
653 card->input_gain = Linear2RecordGain( (Fixed) argument, &card->input_gain_bits );
654 if(card->es1370)
656 /* Not supported on ES1370 */
658 else
659 codec_write(card, AC97_RECORD_GAIN, card->input_gain_bits );
660 return TRUE;
662 case AHIC_InputGain_Query:
663 return card->input_gain;
665 case AHIC_OutputVolume:
666 card->output_volume = Linear2MixerGain( (Fixed) argument, &card->output_volume_bits );
667 if(card->es1370)
669 ak4531_ac97_write(card, AC97_PCMOUT_VOL, card->output_volume_bits );
671 else
672 codec_write(card, AC97_PCMOUT_VOL, card->output_volume_bits );
673 return TRUE;
675 case AHIC_OutputVolume_Query:
676 return card->output_volume;
678 case AHIC_Input:
679 card->input = argument;
680 if(card->es1370)
682 ak4531_ac97_write(card, AC97_RECORD_SELECT, InputBits[ card->input ] );
684 else
685 codec_write(card, AC97_RECORD_SELECT, InputBits[ card->input ] );
687 if( card->is_recording )
689 UpdateMonitorMixer( card );
691 return TRUE;
693 case AHIC_Input_Query:
694 return card->input;
696 case AHIC_Output:
697 card->output = argument;
699 if( card->output == 0 )
702 else
705 return TRUE;
707 case AHIC_Output_Query:
708 return card->output;
710 default:
711 return FALSE;