Added port of Davy Wentzler's VIA VT82C686 AC97 driver.
[AROS.git] / workbench / devs / AHI / Drivers / VIA-AC97 / via.c
blob1c26f2ccbd5f104afe1e907d5033a36c74d5897d
1 /*
2 Copyright © 2005-2013, Davy Wentzler. All rights reserved.
3 Copyright © 2010-2013, The AROS Development Team. All rights reserved.
4 $Id$
5 */
7 #include <config.h>
9 #undef __USE_INLINE__
10 #include <proto/expansion.h>
11 #ifdef __amigaos4__
12 extern struct UtilityIFace* IUtility;
13 extern struct AHIsubIFace* IAHIsub;
14 extern struct MMUIFace* IMMU;
15 #endif
17 #include <devices/ahi.h>
18 #include <exec/memory.h>
19 #include <libraries/ahi_sub.h>
21 #include <proto/ahi_sub.h>
22 #include <proto/exec.h>
23 #include <proto/dos.h>
24 #include <proto/utility.h>
26 #include <string.h>
28 #include "library.h"
29 #include "regs.h"
30 #include "misc.h"
31 #include "pci_wrapper.h"
33 #ifdef __AROS__
34 #include <aros/debug.h>
35 #define DebugPrintF bug
36 #endif
38 /******************************************************************************
39 ** Globals ********************************************************************
40 ******************************************************************************/
42 #define FREQUENCIES 11
44 static const ULONG Frequencies[ FREQUENCIES ] =
46 5500,
47 8000, // µ- and A-Law
48 9600,
49 11025, // CD/4
50 16000, // DAT/3
51 19200,
52 22050, // CD/2
53 32000, // DAT/1.5
54 38400,
55 44100, // CD
56 48000 // DAT
59 #define INPUTS 8
61 static const STRPTR Inputs[ INPUTS ] =
63 "Line in",
64 "Mic",
65 "CD",
66 "Video",
67 "Aux",
68 "Mixer",
69 "Mixer (mono)",
70 "Phone"
73 /* Not static since it's used in misc.c too */
74 const UWORD InputBits[ INPUTS ] =
76 AC97_RECMUX_LINE,
77 AC97_RECMUX_MIC,
78 AC97_RECMUX_CD,
79 AC97_RECMUX_VIDEO,
80 AC97_RECMUX_AUX,
81 AC97_RECMUX_STEREO_MIX,
82 AC97_RECMUX_MONO_MIX,
83 AC97_RECMUX_PHONE
87 #define OUTPUTS 1
90 BOOL ac97_wait_idle2(struct CardData *card);
92 static const STRPTR Outputs[ OUTPUTS ] =
94 "Line",
97 inline unsigned int codec_xread(struct CardData *card)
99 return pci_inl(VIA_REG_AC97, card);
103 inline void codec_xwrite(struct CardData *card, unsigned int val)
105 pci_outl(val, VIA_REG_AC97, card);
108 int codec_ready(struct CardData *card)
110 unsigned int timeout = 100; /* 1ms */
111 unsigned int val;
113 while ( --timeout )
115 val = codec_xread(card);
116 if (! (val & VIA_REG_AC97_BUSY))
117 return val & 0xffff;
118 udelay( 1000 );
121 snd_printk("(codec_ready()) AC97 codec not ready!\n");
122 return -1;
125 int codec_valid(struct CardData *card)
127 unsigned int timeout = 1000; /* 1ms */
128 unsigned int val, val1;
129 unsigned int stat = VIA_REG_AC97_PRIMARY_VALID;
131 while (timeout-- > 0) {
132 val = codec_xread(card);
133 val1 = val & (VIA_REG_AC97_BUSY | stat);
134 if (val1 == stat)
135 return val & 0xffff;
136 udelay(1);
138 return -1;
141 void codec_wait(struct CardData *card)
143 int err;
144 err = codec_ready(card);
145 udelay(500);
148 void codec_write(struct CardData *card,
149 unsigned short reg,
150 unsigned short val)
152 unsigned int xval;
154 xval = VIA_REG_AC97_CODEC_ID_PRIMARY;
155 xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;
156 xval |= reg << VIA_REG_AC97_CMD_SHIFT;
157 xval |= val << VIA_REG_AC97_DATA_SHIFT;
158 codec_ready(card);
159 codec_xwrite(card, xval);
160 codec_ready(card);
164 BOOL ac97_wait_idle(struct CardData *card)
166 unsigned long tul = 0;
167 int cnt = 10000;
168 unsigned long iobase = 0;
169 struct PCIDevice *dev = card->pci_dev;
171 while( --cnt )
173 if( !( ( tul = pci_inl(VIA_REG_AC97, card )) & VIA_REG_AC97_BUSY ) )
174 return TRUE;
175 MicroDelay(100);
178 DebugPrintF("Timed out waiting for AC97 controller!\n");
179 return FALSE;
182 unsigned short codec_read(struct CardData *card, unsigned char reg)
184 unsigned long xval;
185 unsigned short data;
186 int again = 0;
188 xval = 0;
189 xval |= VIA_REG_AC97_PRIMARY_VALID;
190 xval |= VIA_REG_AC97_READ;
191 xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
193 ac97_wait_idle2(card);
194 codec_xwrite(card, xval);
196 ac97_wait_idle2(card);
197 xval = codec_xread(card);
199 data = (xval & 0xFFFF);
201 if ( !( xval & VIA_REG_AC97_PRIMARY_VALID) )
203 DebugPrintF("Codec read failed!\n");
206 return data;
210 //IO base 0 registers
211 static const unsigned char VIA_AC97_RX = 0x80; //ac97 register
212 static const unsigned long VIA_AC97_RX_PRIMARY_ID = 0x00; //primamry codec ID (RW)
213 static const unsigned long VIA_AC97_RX_SECODARY_ID = 0x40000000; //secondary codec ID (RW)
214 static const unsigned long VIA_AC97_RX_SECODARY_VALID = 0x08000000; //secondary valid data/status/index (RWC)
215 static const unsigned long VIA_AC97_RX_PRIMARY_VALID = 0x02000000; //primary valid data etc. (RWC)
216 static const unsigned long VIA_AC97_RX_BUSY = 0x01000000; //controller busy (R)
217 static const unsigned long VIA_AC97_RX_READ = 0x00800000; //read/write select (RW)
219 static const unsigned char VIA_AC97_RX_SHIFT = 0x10; //register shift
220 static const unsigned long VIA_AC97_RX_DATA_MASK = 0xffff; //data mask
222 BOOL ac97_wait_idle2(struct CardData *card)
224 struct PCIDevice *dev = card->pci_dev;
225 unsigned long tul = 0;
226 int cnt = 26; //..about half a second, for no good reason
227 unsigned long iobase = card->iobase;
229 while( --cnt )
231 if( !( ( tul = pci_inl(VIA_AC97_RX, card) ) & VIA_AC97_RX_BUSY ) )
232 return TRUE;
233 MicroDelay(1000);
236 DebugPrintF("Timed out waiting for AC97 controller! VIA_AC97_RX = %lx\n", tul);
237 return FALSE;
241 //note: this only reads the primary codec
242 BOOL ac97_read_reg(struct CardData *card, unsigned char reg, unsigned short *data )
244 struct PCIDevice *dev = card->pci_dev;
245 unsigned long iobase = card->iobase;
246 //set up with required codec register, read mode, and clear the primary codec valid flag
247 unsigned long tul = ( ( reg << VIA_AC97_RX_SHIFT ) | VIA_AC97_RX_READ | VIA_AC97_RX_PRIMARY_VALID );
249 //wait for the controller to become free, and write the command
250 ac97_wait_idle2(card);
251 pci_outl(tul, VIA_AC97_RX, card);
253 //wait for the controller to become free, and read the result
254 ac97_wait_idle2(card);
255 tul = pci_inl(VIA_AC97_RX, card);
256 *data = ( tul & VIA_AC97_RX_DATA_MASK );
258 //complain if the data/register etc. is invalid...
259 if( !( tul & VIA_AC97_RX_PRIMARY_VALID ) )
261 DebugPrintF("Info: (ac97_read_reg) Primary codec operation failed!\n");
262 return( FALSE );
265 return( TRUE );
273 static void set_table_ptr(struct CardData *card, BOOL Play)
275 struct PCIDevice *dev = card->pci_dev;
276 ULONG phys_addr;
277 #ifdef __amigaos4__
278 APTR stack;
279 #endif
281 codec_ready(card);
282 if (Play)
284 #ifdef __amigaos4__
285 stack = IExec->SuperState();
286 phys_addr = IMMU->GetPhysicalAddress(card->play_idx_table);
287 IExec->UserState(stack);
288 #else
289 phys_addr = (ULONG)card->play_idx_table;
290 #endif
292 pci_outl(phys_addr, 4, card);
294 else
296 #ifdef __amigaos4__
297 stack = IExec->SuperState();
298 phys_addr = IMMU->GetPhysicalAddress(card->rec_idx_table);
299 IExec->UserState(stack);
300 #else
301 phys_addr = (ULONG)card->rec_idx_table;
302 #endif
304 pci_outl(phys_addr, 4 + RECORD, card);
307 udelay(20);
308 codec_ready(card);
313 #ifdef __amigaos4__
314 #define tolittle(a) ((((ULONG) (a) & 0xFF000000) >> 24) | \
315 (((ULONG) (a) & 0x00FF0000) >> 8) | \
316 (((ULONG) (a) & 0x0000FF00) << 8) | \
317 (((ULONG) (a) & 0x000000FF) << 24))
318 #else
319 #define tolittle(a) AROS_LONG2LE(a)
320 #endif
322 static int build_via_table(struct CardData *card, APTR sgbuf1, APTR sgbuf2, int OneBufferSize, struct snd_via_sg_table **idx,
323 APTR *idx_nonaligned)
325 struct PCIDevice *dev = card->pci_dev;
326 int i;
327 ULONG phys_addr;
328 #ifdef __amigaos4__
329 APTR stack;
330 #endif
332 *idx = pci_alloc_consistent(sizeof(**idx) * 4, idx_nonaligned);
334 #ifdef __amigaos4__
335 stack = IExec->SuperState();
336 phys_addr = IMMU->GetPhysicalAddress(sgbuf1);
337 IExec->UserState(stack);
338 #else
339 phys_addr = (ULONG)sgbuf1;
340 #endif
342 (*idx)[0].offset = (APTR) tolittle(phys_addr);
343 (*idx)[0].size = tolittle( (OneBufferSize) | VIA_TBL_BIT_FLAG);
345 #ifdef __amigaos4__
346 stack = IExec->SuperState();
347 phys_addr = IMMU->GetPhysicalAddress(sgbuf2);
348 IExec->UserState(stack);
349 #else
350 phys_addr = (ULONG)sgbuf2;
351 #endif
353 (*idx)[1].offset = (APTR) tolittle(phys_addr);
354 (*idx)[1].size = tolittle( (OneBufferSize) | VIA_TBL_BIT_EOL );
356 CacheClearE(*idx, sizeof(**idx) * 4, CACRF_ClearD);
357 //DebugPrintF("===> play_idx_table at %lx, %lx\n", *idx, *idx_nonaligned);
359 return 0;
363 /******************************************************************************
364 ** AHIsub_AllocAudio **********************************************************
365 ******************************************************************************/
367 ULONG
368 _AHIsub_AllocAudio( struct TagItem* taglist,
369 struct AHIAudioCtrlDrv* AudioCtrl,
370 struct DriverBase* AHIsubBase )
372 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
374 int card_num;
375 ULONG ret;
376 int i, freq = 9;
380 card_num = (GetTagData( AHIDB_AudioID, 0, taglist) & 0x0000f000 ) >> 12;
382 if( card_num >= CardBase->cards_found ||
383 CardBase->driverdatas[ card_num ] == NULL )
385 DebugPrintF("no date for card = %ld\n", card_num);
386 Req( "No CardData for card %ld.", card_num );
387 return AHISF_ERROR;
389 else
391 BOOL in_use;
392 struct PCIDevice *dev;
393 struct CardData *card;
394 unsigned short uval;
396 card = CardBase->driverdatas[ card_num ];
397 AudioCtrl->ahiac_DriverData = card;
399 ObtainSemaphore( &CardBase->semaphore );
400 in_use = ( card->audioctrl != NULL );
401 if( !in_use )
403 card->audioctrl = AudioCtrl;
405 ReleaseSemaphore( &CardBase->semaphore );
407 if( in_use )
409 return AHISF_ERROR;
412 dev = card->pci_dev;
413 card->playback_interrupt_enabled = FALSE;
414 card->record_interrupt_enabled = FALSE;
416 for( i = 1; i < FREQUENCIES; i++ )
418 if( (ULONG) Frequencies[ i ] > AudioCtrl->ahiac_MixFreq )
420 if ( ( AudioCtrl->ahiac_MixFreq - (LONG) Frequencies[ i - 1 ] ) < ( (LONG) Frequencies[ i ] - AudioCtrl->ahiac_MixFreq ) )
422 freq = i-1;
423 break;
425 else
427 freq = i;
428 break;
435 ret = AHISF_KNOWHIFI | AHISF_KNOWSTEREO | AHISF_MIXING | AHISF_TIMING;
438 for( i = 0; i < FREQUENCIES; ++i )
440 if( AudioCtrl->ahiac_MixFreq == Frequencies[ i ] )
442 ret |= AHISF_CANRECORD;
443 break;
447 return ret;
452 /******************************************************************************
453 ** AHIsub_FreeAudio ***********************************************************
454 ******************************************************************************/
456 void
457 _AHIsub_FreeAudio( struct AHIAudioCtrlDrv* AudioCtrl,
458 struct DriverBase* AHIsubBase )
460 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
461 struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData;
463 if( card != NULL )
465 ObtainSemaphore( &CardBase->semaphore );
466 if( card->audioctrl == AudioCtrl )
468 // Release it if we own it.
469 card->audioctrl = NULL;
471 ReleaseSemaphore( &CardBase->semaphore );
473 AudioCtrl->ahiac_DriverData = NULL;
478 /******************************************************************************
479 ** AHIsub_Disable *************************************************************
480 ******************************************************************************/
482 void
483 _AHIsub_Disable( struct AHIAudioCtrlDrv* AudioCtrl,
484 struct DriverBase* AHIsubBase )
486 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
488 // V6 drivers do not have to preserve all registers
490 Disable();
494 /******************************************************************************
495 ** AHIsub_Enable **************************************************************
496 ******************************************************************************/
498 void
499 _AHIsub_Enable( struct AHIAudioCtrlDrv* AudioCtrl,
500 struct DriverBase* AHIsubBase )
502 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
504 // V6 drivers do not have to preserve all registers
506 Enable();
510 /******************************************************************************
511 ** AHIsub_Start ***************************************************************
512 ******************************************************************************/
514 ULONG
515 _AHIsub_Start( ULONG flags,
516 struct AHIAudioCtrlDrv* AudioCtrl,
517 struct DriverBase* AHIsubBase )
519 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
520 struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData;
521 UWORD PlayCtrlFlags = 0, RecCtrlFlags = 0;
522 ULONG dma_buffer_size = 0;
523 int i, freqbit = 9;
524 unsigned short uval;
526 //channel_reset(card);
527 codec_write(card, 0x2, 0);
528 codec_write(card, 0x08, 0x0F0F);
529 codec_write(card, 0x0A, 0x8000);
530 codec_write(card, 0x18, 0x0808);
532 uval = codec_read(card, 0x2A);
533 codec_write(card, 0x2A, uval | 0x1); // enable VRA
534 codec_write(card, 0x2C, AudioCtrl->ahiac_MixFreq);
537 if( flags & AHISF_PLAY )
540 ULONG dma_sample_frame_size;
541 int i;
542 short *a;
543 unsigned short cod, ChannelsFlag = 0;
545 card->mix_buffer = AllocVec( AudioCtrl->ahiac_BuffSize, MEMF_PUBLIC | MEMF_CLEAR );
547 if( card->mix_buffer == NULL )
549 Req( "Unable to allocate %ld bytes for mixing buffer.",
550 AudioCtrl->ahiac_BuffSize );
551 return AHIE_NOMEM;
554 /* Allocate a buffer large enough for 16-bit double-buffered
555 playback (mono or stereo) */
558 if( AudioCtrl->ahiac_Flags & AHIACF_STEREO )
560 dma_sample_frame_size = 4;
561 dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size;
563 else
565 dma_sample_frame_size = 2;
566 dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size;
569 //DebugPrintF("dma_buffer_size = %ld, %lx\n", dma_buffer_size, dma_buffer_size);
571 card->playback_buffer1 = pci_alloc_consistent(dma_buffer_size, &card->playback_buffer1_nonaligned);
572 card->playback_buffer2 = pci_alloc_consistent(dma_buffer_size, &card->playback_buffer2_nonaligned);
574 if (!card->playback_buffer1)
576 Req( "Unable to allocate playback buffer." );
577 return AHIE_NOMEM;
580 CacheClearE(card->playback_buffer1, dma_buffer_size, CACRF_ClearD);
581 CacheClearE(card->playback_buffer2, dma_buffer_size, CACRF_ClearD);
583 card->current_bytesize = dma_buffer_size;
584 card->current_frames = AudioCtrl->ahiac_MaxBuffSamples;
585 card->current_buffer = card->playback_buffer1;
586 card->playback_interrupt_enabled = TRUE;
588 build_via_table(card, card->playback_buffer1, card->playback_buffer2, dma_buffer_size, &card->play_idx_table, &card->play_idx_table_nonaligned);
589 set_table_ptr(card, TRUE);
591 pci_outb(VIA_REG_TYPE_AUTOSTART | 0x40 |
592 VIA_REG_TYPE_16BIT |
593 VIA_REG_TYPE_STEREO |
594 VIA_REG_TYPE_INT_LSAMPLE |
595 VIA_REG_TYPE_INT_EOL |
596 VIA_REG_TYPE_INT_FLAG,
597 VIA_REG_OFFSET_TYPE, card);
599 card->flip = 0;
601 card->is_playing = TRUE;
604 if( flags & AHISF_RECORD )
606 UWORD mask;
608 card->current_record_bytesize = RECORD_BUFFER_SAMPLES * 4;
610 /* Allocate a new recording buffer (page aligned!) */
611 card->record_buffer1 = pci_alloc_consistent(card->current_record_bytesize, &card->record_buffer1_nonaligned);
612 card->record_buffer2 = pci_alloc_consistent(card->current_record_bytesize, &card->record_buffer2_nonaligned);
614 if( card->record_buffer1 == NULL )
616 Req( "Unable to allocate %ld bytes for the recording buffer.", card->current_record_bytesize);
617 return AHIE_NOMEM;
620 SaveMixerState( card );
621 UpdateMonitorMixer( card );
623 card->record_interrupt_enabled = TRUE;
625 card->recflip = 0;
627 build_via_table(card, card->record_buffer1, card->record_buffer2, card->current_record_bytesize, &card->rec_idx_table, &card->rec_idx_table_nonaligned);
628 set_table_ptr(card, FALSE);
630 pci_outb(VIA_REG_TYPE_AUTOSTART | 0x40 |
631 VIA_REG_TYPE_16BIT |
632 VIA_REG_TYPE_STEREO |
633 VIA_REG_TYPE_INT_EOL |
634 VIA_REG_TYPE_INT_FLAG,
635 VIA_REG_OFFSET_TYPE + RECORD,
636 card);
638 card->is_recording = TRUE;
639 card->current_record_buffer = card->record_buffer1;
643 if( flags & AHISF_PLAY )
645 unsigned char val;
647 val = VIA_REG_CTRL_START;
648 pci_outb(val, VIA_REG_OFFSET_CONTROL, card);
651 if( flags & AHISF_RECORD )
653 unsigned char val;
655 val = VIA_REG_CTRL_START;
656 pci_outb(val, VIA_REG_OFFSET_CONTROL + RECORD, card);
659 return AHIE_OK;
663 /******************************************************************************
664 ** AHIsub_Update **************************************************************
665 ******************************************************************************/
667 void
668 _AHIsub_Update( ULONG flags,
669 struct AHIAudioCtrlDrv* AudioCtrl,
670 struct DriverBase* AHIsubBase )
672 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
673 struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData;
675 card->current_frames = AudioCtrl->ahiac_BuffSamples;
677 if( AudioCtrl->ahiac_Flags & AHIACF_STEREO )
679 card->current_bytesize = card->current_frames * 4;
681 else
683 card->current_bytesize = card->current_frames * 2;
688 /******************************************************************************
689 ** AHIsub_Stop ****************************************************************
690 ******************************************************************************/
692 void
693 _AHIsub_Stop( ULONG flags,
694 struct AHIAudioCtrlDrv* AudioCtrl,
695 struct DriverBase* AHIsubBase )
697 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
698 struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData;
699 struct PCIDevice *dev = card->pci_dev;
701 unsigned char val;
703 val = VIA_REG_CTRL_TERMINATE;
705 if( flags & AHISF_PLAY && card->is_playing)
707 pci_outb(val, VIA_REG_OFFSET_CONTROL, card);
708 card->is_playing= FALSE;
710 if (card->current_bytesize > 0)
712 pci_free_consistent(card->playback_buffer1);
713 pci_free_consistent(card->playback_buffer2);
716 card->current_bytesize = 0;
717 card->current_frames = 0;
718 card->current_buffer = NULL;
720 if ( card->mix_buffer)
721 FreeVec( card->mix_buffer );
722 card->mix_buffer = NULL;
723 card->playback_interrupt_enabled = FALSE;
725 if (card->play_idx_table_nonaligned)
727 FreeVec(card->play_idx_table_nonaligned);
729 card->play_idx_table = NULL;
732 if( flags & AHISF_RECORD && card->is_recording)
734 unsigned short rec_ctl;
736 pci_outb(val, VIA_REG_OFFSET_CONTROL + RECORD, card);
737 if( card->is_recording )
739 // Do not restore mixer unless they have been saved
740 RestoreMixerState( card );
743 if( card->record_buffer1 != NULL )
745 pci_free_consistent( card->record_buffer1);
746 pci_free_consistent( card->record_buffer2);
749 card->record_buffer1 = NULL;
750 card->record_buffer2 = NULL;
751 card->current_record_bytesize = 0;
753 card->is_recording = FALSE;
754 card->record_interrupt_enabled = FALSE;
756 pci_free_consistent(card->rec_idx_table_nonaligned);
757 card->rec_idx_table = NULL;
761 card->current_bytesize = 0;
765 /******************************************************************************
766 ** AHIsub_GetAttr *************************************************************
767 ******************************************************************************/
769 SIPTR
770 _AHIsub_GetAttr( ULONG attribute,
771 LONG argument,
772 LONG def,
773 struct TagItem* taglist,
774 struct AHIAudioCtrlDrv* AudioCtrl,
775 struct DriverBase* AHIsubBase )
777 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
778 int i;
781 switch( attribute )
783 case AHIDB_Bits:
784 return 16;
786 case AHIDB_Frequencies:
787 return FREQUENCIES;
789 case AHIDB_Frequency: // Index->Frequency
790 return (SIPTR) Frequencies[ argument ];
792 case AHIDB_Index: // Frequency->Index
793 if( argument <= (LONG) Frequencies[ 0 ] )
795 return 0;
798 if( argument >= (LONG) Frequencies[ FREQUENCIES - 1 ] )
800 return FREQUENCIES-1;
803 for( i = 1; i < FREQUENCIES; i++ )
805 if( (LONG) Frequencies[ i ] > argument )
807 if( ( argument - (LONG) Frequencies[ i - 1 ] ) < ( (LONG) Frequencies[ i ] - argument ) )
809 return i-1;
811 else
813 return i;
818 return 0; // Will not happen
820 case AHIDB_Author:
821 return (SIPTR) "Davy Wentzler";
823 case AHIDB_Copyright:
824 return (SIPTR) "(C) Davy Wentzler";
826 case AHIDB_Version:
827 return (SIPTR) LibIDString;
829 case AHIDB_Annotation:
830 return (SIPTR)
831 "VIA VT82C686 AC97 driver";
833 case AHIDB_Record:
834 return TRUE;
836 case AHIDB_FullDuplex:
837 return TRUE;
839 case AHIDB_Realtime:
840 return TRUE;
842 case AHIDB_MaxRecordSamples:
843 return RECORD_BUFFER_SAMPLES;
845 /* formula's:
846 #include <math.h>
848 unsigned long res = (unsigned long) (0x10000 * pow (10.0, dB / 20.0));
849 double dB = 20.0 * log10(0xVALUE / 65536.0);
851 printf("dB = %f, res = %lx\n", dB, res);*/
853 case AHIDB_MinMonitorVolume:
854 return 0x00000;
856 case AHIDB_MaxMonitorVolume:
857 return 0x40000;
859 case AHIDB_MinInputGain:
860 return 0x10000; // 0.0 dB gain
862 case AHIDB_MaxInputGain:
863 return 0xD55D0; // 22.5 dB gain
865 case AHIDB_MinOutputVolume:
866 return 0x00000; // -96 dB
868 case AHIDB_MaxOutputVolume:
869 return 0x10000; // 0 dB
871 case AHIDB_Inputs:
872 return INPUTS;
874 case AHIDB_Input:
875 return (SIPTR) Inputs[ argument ];
877 case AHIDB_Outputs:
878 return OUTPUTS;
880 case AHIDB_Output:
881 return (SIPTR) Outputs[ argument ];
883 default:
884 return def;
889 /******************************************************************************
890 ** AHIsub_HardwareControl *****************************************************
891 ******************************************************************************/
893 ULONG
894 _AHIsub_HardwareControl( ULONG attribute,
895 LONG argument,
896 struct AHIAudioCtrlDrv* AudioCtrl,
897 struct DriverBase* AHIsubBase )
899 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
900 struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData;
902 switch( attribute )
904 case AHIC_MonitorVolume:
905 card->monitor_volume = Linear2MixerGain( (Fixed) argument, &card->monitor_volume_bits );
906 if( card->is_recording )
908 UpdateMonitorMixer( card );
910 return TRUE;
912 case AHIC_MonitorVolume_Query:
913 return card->monitor_volume;
915 case AHIC_InputGain:
916 card->input_gain = Linear2RecordGain( (Fixed) argument, &card->input_gain_bits );
917 codec_write(card, AC97_RECORD_GAIN, card->input_gain_bits );
918 return TRUE;
920 case AHIC_InputGain_Query:
921 return card->input_gain;
923 case AHIC_OutputVolume:
924 card->output_volume = Linear2MixerGain( (Fixed) argument, &card->output_volume_bits );
925 codec_write(card, AC97_PCMOUT_VOL, card->output_volume_bits );
926 return TRUE;
928 case AHIC_OutputVolume_Query:
929 return card->output_volume;
931 case AHIC_Input:
932 card->input = argument;
933 codec_write(card, AC97_RECORD_SELECT, InputBits[ card->input ] );
935 if( card->is_recording )
937 UpdateMonitorMixer( card );
940 return TRUE;
942 case AHIC_Input_Query:
943 return card->input;
945 case AHIC_Output:
946 card->output = argument;
948 return TRUE;
950 case AHIC_Output_Query:
951 return card->output;
953 default:
954 return FALSE;