Port the SB128 code to AROS.
[AROS.git] / workbench / devs / AHI / Drivers / SB128 / sb128.c
blob8a379f7ca47d9a50deb411adb383cd7770c76e43
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 //#include <config.h>
20 #if !defined(__AROS__)
21 #undef __USE_INLINE__
22 #include <proto/expansion.h>
23 extern struct UtilityIFace* IUtility;
24 extern struct AHIsubIFace* IAHIsub;
25 extern struct MMUIFace* IMMU;
26 #endif
28 #include <devices/ahi.h>
29 #include <exec/memory.h>
30 #include <libraries/ahi_sub.h>
32 #include <proto/ahi_sub.h>
33 #include <proto/exec.h>
34 #include <proto/dos.h>
35 #include <proto/utility.h>
37 #ifdef __AROS__
38 #define DEBUG 1
39 #include <aros/debug.h>
40 #define DebugPrintF bug
41 #endif
42 #include <string.h>
44 #include "library.h"
45 #include "regs.h"
46 #include "misc.h"
47 #include "pci_wrapper.h"
48 //#include "DriverData.h"
50 extern void rate_set_dac2(struct SB128_DATA *card, unsigned long rate);
51 extern void rate_set_adc(struct SB128_DATA *card, unsigned long rate);
53 /******************************************************************************
54 ** Globals ********************************************************************
55 ******************************************************************************/
57 #define FREQUENCIES 11
59 static const ULONG Frequencies[ FREQUENCIES ] =
61 5500,
62 8000, /* ยต- and A-Law */
63 9600,
64 11025, /* CD/4 */
65 16000, /* DAT/3 */
66 19200,
67 22050, /* CD/2 */
68 32000, /* DAT/1.5 */
69 38400,
70 44100, /* CD */
71 48000 /* DAT */
74 #define INPUTS 6
76 static const STRPTR Inputs[ INPUTS ] =
78 "Line in",
79 "Mic",
80 "CD",
81 "Aux",
82 "Mixer",
83 "Phone"
86 /* Not static since it's used in misc.c too */
87 const UWORD InputBits[ INPUTS ] =
89 AC97_RECMUX_LINE,
90 AC97_RECMUX_MIC,
91 AC97_RECMUX_CD,
92 AC97_RECMUX_AUX,
93 AC97_RECMUX_STEREO_MIX,
94 AC97_RECMUX_PHONE
98 #define OUTPUTS 1
100 static const STRPTR Outputs[ OUTPUTS ] =
102 "Front",
106 /******************************************************************************
107 ** AHIsub_AllocAudio **********************************************************
108 ******************************************************************************/
110 ULONG
111 _AHIsub_AllocAudio( struct TagItem* taglist,
112 struct AHIAudioCtrlDrv* AudioCtrl,
113 struct DriverBase* AHIsubBase )
115 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
117 int card_num;
118 ULONG ret;
119 int i, freq = 9;
121 card_num = ( GetTagData( AHIDB_AudioID, 0, taglist) & 0x0000f000 ) >> 12;
123 if( card_num >= SB128Base->cards_found ||
124 SB128Base->driverdatas[ card_num ] == NULL )
126 DebugPrintF("no data for card = %ld\n", card_num);
127 Req( "No Card Data for card %ld.", card_num );
128 return AHISF_ERROR;
130 else
132 struct SB128_DATA* card;
133 BOOL in_use;
134 struct PCIDevice *dev;
136 card = SB128Base->driverdatas[ card_num ];
137 AudioCtrl->ahiac_DriverData = card;
139 ObtainSemaphore( &SB128Base->semaphore );
140 in_use = ( card->audioctrl != NULL );
141 if( !in_use )
143 card->audioctrl = AudioCtrl;
145 ReleaseSemaphore( &SB128Base->semaphore );
147 if( in_use )
149 return AHISF_ERROR;
152 dev = card->pci_dev;
153 card->playback_interrupt_enabled = FALSE;
154 card->record_interrupt_enabled = FALSE;
155 /* Clears playback/record interrupts */
156 pci_outl((pci_inl(SB128_SCON, card)) & SB128_IRQ_MASK, SB128_SCON, card);
158 for( i = 1; i < FREQUENCIES; i++ )
160 if( (ULONG) Frequencies[ i ] > AudioCtrl->ahiac_MixFreq )
162 if ( ( AudioCtrl->ahiac_MixFreq - (LONG) Frequencies[ i - 1 ] ) < ( (LONG) Frequencies[ i ] - AudioCtrl->ahiac_MixFreq ) )
164 freq = i-1;
165 break;
167 else
169 freq = i;
170 break;
177 ret = AHISF_KNOWHIFI | AHISF_KNOWSTEREO | AHISF_MIXING | AHISF_TIMING;
180 for( i = 0; i < FREQUENCIES; ++i )
182 if( AudioCtrl->ahiac_MixFreq == Frequencies[ i ] )
184 ret |= AHISF_CANRECORD;
185 break;
189 return ret;
194 /******************************************************************************
195 ** AHIsub_FreeAudio ***********************************************************
196 ******************************************************************************/
198 void
199 _AHIsub_FreeAudio( struct AHIAudioCtrlDrv* AudioCtrl,
200 struct DriverBase* AHIsubBase )
202 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
203 struct SB128_DATA* card = (struct SB128_DATA*) AudioCtrl->ahiac_DriverData;
205 if( card != NULL )
207 ObtainSemaphore( &SB128Base->semaphore );
208 if( card->audioctrl == AudioCtrl )
210 /* Release it if we own it. */
211 card->audioctrl = NULL;
213 ReleaseSemaphore( &SB128Base->semaphore );
215 AudioCtrl->ahiac_DriverData = NULL;
220 /******************************************************************************
221 ** AHIsub_Disable *************************************************************
222 ******************************************************************************/
224 void
225 _AHIsub_Disable( struct AHIAudioCtrlDrv* AudioCtrl,
226 struct DriverBase* AHIsubBase )
228 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
230 /* V6 drivers do not have to preserve all registers */
232 Disable();
236 /******************************************************************************
237 ** AHIsub_Enable **************************************************************
238 ******************************************************************************/
240 void
241 _AHIsub_Enable( struct AHIAudioCtrlDrv* AudioCtrl,
242 struct DriverBase* AHIsubBase )
244 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
246 /* V6 drivers do not have to preserve all registers */
248 Enable();
252 /******************************************************************************
253 ** AHIsub_Start ***************************************************************
254 ******************************************************************************/
256 ULONG
257 _AHIsub_Start( ULONG flags,
258 struct AHIAudioCtrlDrv* AudioCtrl,
259 struct DriverBase* AHIsubBase )
261 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
262 struct SB128_DATA* card = (struct SB128_DATA*) AudioCtrl->ahiac_DriverData;
263 struct PCIDevice *dev = card->pci_dev;
264 unsigned long PlayCtrlFlags = 0, RecCtrlFlags = 0;
265 ULONG dma_buffer_size = 0;
266 int i, freqbit = 9;
267 unsigned long scon = 0;
268 APTR stack;
270 for( i = 0; i < FREQUENCIES; ++i )
272 if( AudioCtrl->ahiac_MixFreq == Frequencies[ i ] )
274 freqbit = i;
275 break;
279 if( flags & AHISF_PLAY )
282 ULONG dma_sample_frame_size;
283 int i;
284 short *a;
285 unsigned short cod, ChannelsFlag;
287 ChannelsFlag = 0;
289 /* Update cached/syncronized variables */
291 AHIsub_Update( AHISF_PLAY, AudioCtrl );
293 /* Allocate a new mixing buffer. Note: The buffer must be cleared, since
294 it might not be filled by the mixer software interrupt because of
295 pretimer/posttimer! */
297 card->mix_buffer = AllocVec( AudioCtrl->ahiac_BuffSize,
298 MEMF_PUBLIC | MEMF_CLEAR );
300 if( card->mix_buffer == NULL )
302 Req( "Unable to allocate %ld bytes for mixing buffer.",
303 AudioCtrl->ahiac_BuffSize );
304 return AHIE_NOMEM;
307 /* Allocate a buffer large enough for 16-bit double-buffered
308 playback (mono or stereo) */
310 if( AudioCtrl->ahiac_Flags & AHIACF_STEREO )
312 dma_sample_frame_size = 4;
313 dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size;
314 ChannelsFlag = SB128_STEREO;
316 else
318 dma_sample_frame_size = 2;
319 dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size;
322 card->playback_buffer = pci_alloc_consistent(dma_buffer_size * 2, &card->playback_buffer_nonaligned, 128);
324 if (!card->playback_buffer)
326 Req( "Unable to allocate playback buffer." );
327 return AHIE_NOMEM;
330 /* Enable Playback interrupt */
331 pci_outl((pci_inl(SB128_SCON, card) | SB128_DAC2_INTEN), SB128_SCON, card);
333 card->current_bytesize = dma_buffer_size;
334 card->current_frames = AudioCtrl->ahiac_MaxBuffSamples;
335 card->current_buffer = card->playback_buffer + card->current_bytesize;
336 card->playback_interrupt_enabled = TRUE;
338 card->flip = 0;
340 /* Select the DAC2 Memory Page */
341 pci_outl(SB128_PAGE_DAC, SB128_MEMPAGE, card);
343 /* Buffer address and length (in longwords) is set */
344 stack = SuperState();
345 // card->playback_buffer_phys = IMMU->GetPhysicalAddress(card->playback_buffer);
346 card->playback_buffer_phys = card->playback_buffer;
347 UserState(stack);
349 pci_outl((unsigned long)(card->playback_buffer_phys), SB128_DAC2_FRAME, card);
350 pci_outl((((dma_buffer_size * 2) >> 2) - 1) & 0xFFFF, SB128_DAC2_COUNT, card);
352 /* Playback format is always 16 Bit, Stereo, but checks exist in case of a Mono mode (not possible). */
353 PlayCtrlFlags = (SB128_16BIT | ChannelsFlag) << 2;
355 /* Set frequency */
356 if (card->currentPlayFreq != freqbit)
358 rate_set_dac2(card, Frequencies[freqbit]);
359 card->currentPlayFreq = freqbit;
361 card->is_playing = TRUE;
364 if( flags & AHISF_RECORD )
366 UWORD mask;
368 card->current_record_bytesize = RECORD_BUFFER_SAMPLES * 4;
370 /* Allocate a new recording buffer (page aligned!) */
371 card->record_buffer = pci_alloc_consistent(card->current_record_bytesize * 2, &card->record_buffer_nonaligned, 128);
373 if( card->record_buffer == NULL )
375 Req( "Unable to allocate %ld bytes for the recording buffer.", card->current_record_bytesize);
376 return AHIE_NOMEM;
379 SaveMixerState( card );
380 UpdateMonitorMixer( card );
382 /* Enable record interrupt */
383 pci_outl((pci_inl(SB128_SCON, card) | SB128_ADC_INTEN), SB128_SCON, card);
385 card->record_interrupt_enabled = TRUE;
387 card->recflip = 0;
389 /* Select the ADC Memory Page */
390 pci_outl(SB128_PAGE_ADC, SB128_MEMPAGE, card);
392 /* Buffer address and length (in longwords) is set */
393 stack = SuperState();
394 // card->record_buffer_phys = IMMU->GetPhysicalAddress(card->record_buffer);
395 card->record_buffer_phys = card->record_buffer;
396 UserState(stack);
398 pci_outl((unsigned long) card->record_buffer_phys, SB128_ADC_FRAME, card);
399 pci_outl((((card->current_record_bytesize * 2) >> 2) - 1) & 0xFFFF, SB128_ADC_COUNT, card);
401 card->is_recording = TRUE;
402 card->current_record_buffer = card->record_buffer + card->current_record_bytesize;
404 /* Record format is always 16 Bit, Stereo */
405 RecCtrlFlags = (SB128_16BIT | SB128_STEREO) << 4;
407 /* Set frequency */
408 if (card->currentRecFreq != freqbit)
410 rate_set_adc(card, Frequencies[freqbit]);
411 card->currentRecFreq = freqbit;
415 if( flags & AHISF_PLAY )
417 /* Set Sample Count per Interrupt */
418 if (PlayCtrlFlags & 0x04)
420 pci_outl(((dma_buffer_size >> 2) - 1) & 0xFFFF, SB128_DAC2_SCOUNT, card);
422 else
424 pci_outl(((dma_buffer_size >> 1) - 1) & 0xFFFF, SB128_DAC2_SCOUNT, card);
426 /* Set format, ENDINC set to 2 */
427 pci_outl((pci_inl(SB128_SCON, card) | PlayCtrlFlags | 2 << 19), SB128_SCON, card);
428 /* Start playback! */
429 pci_outl((pci_inl(SB128_CONTROL, card) | CTRL_DAC2_EN), SB128_CONTROL, card);
432 if( flags & AHISF_RECORD )
434 /* Set Sample Count per Interrupt */
435 pci_outl(((card->current_record_bytesize >> 2) - 1) & 0xFFFF, SB128_ADC_SCOUNT, card);
436 /* Set format */
437 pci_outl((pci_inl(SB128_SCON, card) | RecCtrlFlags), SB128_SCON, card);
438 /* Start recording! */
439 pci_outl((pci_inl(SB128_CONTROL, card) | CTRL_ADC_EN), SB128_CONTROL, card);
442 return AHIE_OK;
446 /******************************************************************************
447 ** AHIsub_Update **************************************************************
448 ******************************************************************************/
450 void
451 _AHIsub_Update( ULONG flags,
452 struct AHIAudioCtrlDrv* AudioCtrl,
453 struct DriverBase* AHIsubBase )
455 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
456 struct SB128_DATA* card = (struct SB128_DATA*) AudioCtrl->ahiac_DriverData;
458 card->current_frames = AudioCtrl->ahiac_BuffSamples;
460 if( AudioCtrl->ahiac_Flags & AHIACF_STEREO )
462 card->current_bytesize = card->current_frames * 4;
464 else
466 card->current_bytesize = card->current_frames * 2;
471 /******************************************************************************
472 ** AHIsub_Stop ****************************************************************
473 ******************************************************************************/
475 void
476 _AHIsub_Stop( ULONG flags,
477 struct AHIAudioCtrlDrv* AudioCtrl,
478 struct DriverBase* AHIsubBase )
480 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
481 struct SB128_DATA* card = (struct SB128_DATA*) AudioCtrl->ahiac_DriverData;
482 struct PCIDevice *dev = card->pci_dev;
485 if( flags & AHISF_PLAY )
487 unsigned long play_ctl;
488 card->is_playing= FALSE;
490 play_ctl = pci_inl(SB128_CONTROL, card);
491 play_ctl &= ~(CTRL_DAC2_EN);
492 /* Stop */
493 pci_outl(play_ctl, SB128_CONTROL, card);
495 /* Clear and mask interrupts */
496 pci_outl((pci_inl(SB128_SCON, card)) & SB128_IRQ_MASK, SB128_SCON, card);
498 if (card->current_bytesize > 0)
499 pci_free_consistent(card->playback_buffer_nonaligned);
501 card->current_bytesize = 0;
502 card->current_frames = 0;
503 card->current_buffer = NULL;
505 if ( card->mix_buffer)
506 FreeVec( card->mix_buffer );
507 card->mix_buffer = NULL;
508 card->playback_interrupt_enabled = FALSE;
509 card->current_bytesize = 0;
512 if( flags & AHISF_RECORD )
514 unsigned long rec_ctl, val;
516 rec_ctl = pci_inl(SB128_CONTROL, card);
517 rec_ctl &= ~(CTRL_ADC_EN);
518 /* Stop */
519 pci_outl(rec_ctl, SB128_CONTROL, card);
521 /* Clear and mask interrupts */
522 pci_outl((pci_inl(SB128_SCON, card)) & SB128_IRQ_MASK, SB128_SCON, card);
524 if( card->is_recording )
526 /* Do not restore mixer unless they have been saved */
527 RestoreMixerState( card );
530 if( card->record_buffer != NULL )
532 pci_free_consistent( card->record_buffer_nonaligned);
535 card->record_buffer = NULL;
536 card->current_record_bytesize = 0;
538 card->is_recording = FALSE;
539 card->record_interrupt_enabled = FALSE;
546 /******************************************************************************
547 ** AHIsub_GetAttr *************************************************************
548 ******************************************************************************/
550 LONG
551 _AHIsub_GetAttr( ULONG attribute,
552 LONG argument,
553 LONG def,
554 struct TagItem* taglist,
555 struct AHIAudioCtrlDrv* AudioCtrl,
556 struct DriverBase* AHIsubBase )
558 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
559 int i;
562 switch( attribute )
564 case AHIDB_Bits:
565 return 16;
567 case AHIDB_Frequencies:
568 return FREQUENCIES;
570 case AHIDB_Frequency: /* Index->Frequency */
571 return (LONG) Frequencies[ argument ];
573 case AHIDB_Index: /* Frequency->Index */
574 if( argument <= (LONG) Frequencies[ 0 ] )
576 return 0;
579 if( argument >= (LONG) Frequencies[ FREQUENCIES - 1 ] )
581 return FREQUENCIES-1;
584 for( i = 1; i < FREQUENCIES; i++ )
586 if( (LONG) Frequencies[ i ] > argument )
588 if( ( argument - (LONG) Frequencies[ i - 1 ] ) < ( (LONG) Frequencies[ i ] - argument ) )
590 return i-1;
592 else
594 return i;
599 return 0; /* Will not happen */
601 case AHIDB_Author:
602 return (LONG) "Ross Vumbaca";
604 case AHIDB_Copyright:
605 return (LONG) "(C) Ross Vumbaca";
607 case AHIDB_Version:
608 return (LONG) LibIDString;
610 case AHIDB_Annotation:
611 return (LONG)
612 "AROS SB128/ES137x Audio driver";
614 case AHIDB_Record:
615 return TRUE;
617 case AHIDB_FullDuplex:
618 return TRUE;
620 case AHIDB_Realtime:
621 return TRUE;
623 case AHIDB_MaxRecordSamples:
624 return RECORD_BUFFER_SAMPLES;
626 /* formula's:
627 #include <math.h>
629 unsigned long res = (unsigned long) (0x10000 * pow (10.0, dB / 20.0));
630 double dB = 20.0 * log10(0xVALUE / 65536.0);
632 printf("dB = %f, res = %lx\n", dB, res);*/
634 case AHIDB_MinMonitorVolume:
635 return 0x004d2;
637 case AHIDB_MaxMonitorVolume:
638 return 0x3fb27;
640 case AHIDB_MinInputGain:
641 return 0x10000; /* 0.0 dB gain */
643 case AHIDB_MaxInputGain:
644 return 0xD55D0; /* 22.5 dB gain */
646 case AHIDB_MinOutputVolume:
647 return 0x004d2; /* -34.5 dB / mute */
649 case AHIDB_MaxOutputVolume:
650 return 0x3fb27; /* 12 dB */
652 case AHIDB_Inputs:
653 return INPUTS;
655 case AHIDB_Input:
656 return (LONG) Inputs[ argument ];
658 case AHIDB_Outputs:
659 return OUTPUTS;
661 case AHIDB_Output:
662 return (LONG) Outputs[ argument ];
664 default:
665 return def;
670 /******************************************************************************
671 ** AHIsub_HardwareControl *****************************************************
672 ******************************************************************************/
674 ULONG
675 _AHIsub_HardwareControl( ULONG attribute,
676 LONG argument,
677 struct AHIAudioCtrlDrv* AudioCtrl,
678 struct DriverBase* AHIsubBase )
680 struct SB128Base* SB128Base = (struct SB128Base*) AHIsubBase;
681 struct SB128_DATA* card = (struct SB128_DATA*) AudioCtrl->ahiac_DriverData;
683 switch( attribute )
685 case AHIC_MonitorVolume:
686 card->monitor_volume = Linear2MixerGain( (Fixed) argument, &card->monitor_volume_bits );
687 if( card->is_recording )
689 UpdateMonitorMixer( card );
691 return TRUE;
693 case AHIC_MonitorVolume_Query:
694 return card->monitor_volume;
696 case AHIC_InputGain:
697 card->input_gain = Linear2RecordGain( (Fixed) argument, &card->input_gain_bits );
698 if(card->es1370)
700 /* Not supported on ES1370 */
702 else
703 codec_write(card, AC97_RECORD_GAIN, card->input_gain_bits );
704 return TRUE;
706 case AHIC_InputGain_Query:
707 return card->input_gain;
709 case AHIC_OutputVolume:
710 card->output_volume = Linear2MixerGain( (Fixed) argument, &card->output_volume_bits );
711 if(card->es1370)
713 ak4531_ac97_write(card, AC97_PCMOUT_VOL, card->output_volume_bits );
715 else
716 codec_write(card, AC97_PCMOUT_VOL, card->output_volume_bits );
717 return TRUE;
719 case AHIC_OutputVolume_Query:
720 return card->output_volume;
722 case AHIC_Input:
723 card->input = argument;
724 if(card->es1370)
726 ak4531_ac97_write(card, AC97_RECORD_SELECT, InputBits[ card->input ] );
728 else
729 codec_write(card, AC97_RECORD_SELECT, InputBits[ card->input ] );
731 if( card->is_recording )
733 UpdateMonitorMixer( card );
735 return TRUE;
737 case AHIC_Input_Query:
738 return card->input;
740 case AHIC_Output:
741 card->output = argument;
743 if( card->output == 0 )
746 else
749 return TRUE;
751 case AHIC_Output_Query:
752 return card->output;
754 default:
755 return FALSE;