Fixed warnings in AHI code (Part 2).
[AROS.git] / workbench / devs / AHI / Drivers / VIA-AC97 / via.c
blobc1f9745169d71b50f96728c9a45a02a3c9d69f6f
1 /*
2 Copyright © 2005-2013, Davy Wentzler. All rights reserved.
3 Copyright © 2010-2016, 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 codec_ready(card);
144 udelay(500);
147 void codec_write(struct CardData *card,
148 unsigned short reg,
149 unsigned short val)
151 unsigned int xval;
153 xval = VIA_REG_AC97_CODEC_ID_PRIMARY;
154 xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;
155 xval |= reg << VIA_REG_AC97_CMD_SHIFT;
156 xval |= val << VIA_REG_AC97_DATA_SHIFT;
157 codec_ready(card);
158 codec_xwrite(card, xval);
159 codec_ready(card);
163 BOOL ac97_wait_idle(struct CardData *card)
165 unsigned long tul = 0;
166 int cnt = 10000;
168 while( --cnt )
170 if( !( ( tul = pci_inl(VIA_REG_AC97, card )) & VIA_REG_AC97_BUSY ) )
171 return TRUE;
172 MicroDelay(100);
175 DebugPrintF("Timed out waiting for AC97 controller!\n");
176 return FALSE;
179 unsigned short codec_read(struct CardData *card, unsigned char reg)
181 unsigned long xval;
182 unsigned short data;
184 xval = 0;
185 xval |= VIA_REG_AC97_PRIMARY_VALID;
186 xval |= VIA_REG_AC97_READ;
187 xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
189 ac97_wait_idle2(card);
190 codec_xwrite(card, xval);
192 ac97_wait_idle2(card);
193 xval = codec_xread(card);
195 data = (xval & 0xFFFF);
197 if ( !( xval & VIA_REG_AC97_PRIMARY_VALID) )
199 DebugPrintF("Codec read failed!\n");
202 return data;
206 //IO base 0 registers
207 static const unsigned char VIA_AC97_RX = 0x80; //ac97 register
208 //static const unsigned long VIA_AC97_RX_PRIMARY_ID = 0x00; //primamry codec ID (RW)
209 //static const unsigned long VIA_AC97_RX_SECODARY_ID = 0x40000000; //secondary codec ID (RW)
210 //static const unsigned long VIA_AC97_RX_SECODARY_VALID = 0x08000000; //secondary valid data/status/index (RWC)
211 static const unsigned long VIA_AC97_RX_PRIMARY_VALID = 0x02000000; //primary valid data etc. (RWC)
212 static const unsigned long VIA_AC97_RX_BUSY = 0x01000000; //controller busy (R)
213 static const unsigned long VIA_AC97_RX_READ = 0x00800000; //read/write select (RW)
215 static const unsigned char VIA_AC97_RX_SHIFT = 0x10; //register shift
216 static const unsigned long VIA_AC97_RX_DATA_MASK = 0xffff; //data mask
218 BOOL ac97_wait_idle2(struct CardData *card)
220 unsigned long tul = 0;
221 int cnt = 26; //..about half a second, for no good reason
223 while( --cnt )
225 if( !( ( tul = pci_inl(VIA_AC97_RX, card) ) & VIA_AC97_RX_BUSY ) )
226 return TRUE;
227 MicroDelay(1000);
230 DebugPrintF("Timed out waiting for AC97 controller! VIA_AC97_RX = %lx\n", tul);
231 return FALSE;
235 //note: this only reads the primary codec
236 BOOL ac97_read_reg(struct CardData *card, unsigned char reg, unsigned short *data )
238 //set up with required codec register, read mode, and clear the primary codec valid flag
239 unsigned long tul = ( ( reg << VIA_AC97_RX_SHIFT ) | VIA_AC97_RX_READ | VIA_AC97_RX_PRIMARY_VALID );
241 //wait for the controller to become free, and write the command
242 ac97_wait_idle2(card);
243 pci_outl(tul, VIA_AC97_RX, card);
245 //wait for the controller to become free, and read the result
246 ac97_wait_idle2(card);
247 tul = pci_inl(VIA_AC97_RX, card);
248 *data = ( tul & VIA_AC97_RX_DATA_MASK );
250 //complain if the data/register etc. is invalid...
251 if( !( tul & VIA_AC97_RX_PRIMARY_VALID ) )
253 DebugPrintF("Info: (ac97_read_reg) Primary codec operation failed!\n");
254 return( FALSE );
257 return( TRUE );
265 static void set_table_ptr(struct CardData *card, BOOL Play)
267 ULONG phys_addr;
268 #ifdef __amigaos4__
269 APTR stack;
270 #endif
272 codec_ready(card);
273 if (Play)
275 #ifdef __amigaos4__
276 stack = IExec->SuperState();
277 phys_addr = IMMU->GetPhysicalAddress(card->play_idx_table);
278 IExec->UserState(stack);
279 #else
280 phys_addr = (ULONG)card->play_idx_table;
281 #endif
283 pci_outl(phys_addr, 4, card);
285 else
287 #ifdef __amigaos4__
288 stack = IExec->SuperState();
289 phys_addr = IMMU->GetPhysicalAddress(card->rec_idx_table);
290 IExec->UserState(stack);
291 #else
292 phys_addr = (ULONG)card->rec_idx_table;
293 #endif
295 pci_outl(phys_addr, 4 + RECORD, card);
298 udelay(20);
299 codec_ready(card);
304 #ifdef __amigaos4__
305 #define tolittle(a) ((((ULONG) (a) & 0xFF000000) >> 24) | \
306 (((ULONG) (a) & 0x00FF0000) >> 8) | \
307 (((ULONG) (a) & 0x0000FF00) << 8) | \
308 (((ULONG) (a) & 0x000000FF) << 24))
309 #else
310 #define tolittle(a) AROS_LONG2LE(a)
311 #endif
313 static int build_via_table(struct CardData *card, APTR sgbuf1, APTR sgbuf2, int OneBufferSize, struct snd_via_sg_table **idx,
314 APTR *idx_nonaligned)
316 ULONG phys_addr;
317 #ifdef __amigaos4__
318 APTR stack;
319 #endif
321 *idx = pci_alloc_consistent(sizeof(**idx) * 4, idx_nonaligned);
323 #ifdef __amigaos4__
324 stack = IExec->SuperState();
325 phys_addr = IMMU->GetPhysicalAddress(sgbuf1);
326 IExec->UserState(stack);
327 #else
328 phys_addr = (ULONG)sgbuf1;
329 #endif
331 (*idx)[0].offset = (APTR) tolittle(phys_addr);
332 (*idx)[0].size = tolittle( (OneBufferSize) | VIA_TBL_BIT_FLAG);
334 #ifdef __amigaos4__
335 stack = IExec->SuperState();
336 phys_addr = IMMU->GetPhysicalAddress(sgbuf2);
337 IExec->UserState(stack);
338 #else
339 phys_addr = (ULONG)sgbuf2;
340 #endif
342 (*idx)[1].offset = (APTR) tolittle(phys_addr);
343 (*idx)[1].size = tolittle( (OneBufferSize) | VIA_TBL_BIT_EOL );
345 CacheClearE(*idx, sizeof(**idx) * 4, CACRF_ClearD);
346 //DebugPrintF("===> play_idx_table at %lx, %lx\n", *idx, *idx_nonaligned);
348 return 0;
352 /******************************************************************************
353 ** AHIsub_AllocAudio **********************************************************
354 ******************************************************************************/
356 ULONG
357 _AHIsub_AllocAudio( struct TagItem* taglist,
358 struct AHIAudioCtrlDrv* AudioCtrl,
359 struct DriverBase* AHIsubBase )
361 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
363 int card_num;
364 ULONG ret;
365 int i;
369 card_num = (GetTagData( AHIDB_AudioID, 0, taglist) & 0x0000f000 ) >> 12;
371 if( card_num >= CardBase->cards_found ||
372 CardBase->driverdatas[ card_num ] == NULL )
374 DebugPrintF("no date for card = %ld\n", card_num);
375 Req( "No CardData for card %ld.", card_num );
376 return AHISF_ERROR;
378 else
380 BOOL in_use;
381 struct CardData *card;
383 card = CardBase->driverdatas[ card_num ];
384 AudioCtrl->ahiac_DriverData = card;
386 ObtainSemaphore( &CardBase->semaphore );
387 in_use = ( card->audioctrl != NULL );
388 if( !in_use )
390 card->audioctrl = AudioCtrl;
392 ReleaseSemaphore( &CardBase->semaphore );
394 if( in_use )
396 return AHISF_ERROR;
399 card->playback_interrupt_enabled = FALSE;
400 card->record_interrupt_enabled = FALSE;
403 ret = AHISF_KNOWHIFI | AHISF_KNOWSTEREO | AHISF_MIXING | AHISF_TIMING;
406 for( i = 0; i < FREQUENCIES; ++i )
408 if( AudioCtrl->ahiac_MixFreq == Frequencies[ i ] )
410 ret |= AHISF_CANRECORD;
411 break;
415 return ret;
420 /******************************************************************************
421 ** AHIsub_FreeAudio ***********************************************************
422 ******************************************************************************/
424 void
425 _AHIsub_FreeAudio( struct AHIAudioCtrlDrv* AudioCtrl,
426 struct DriverBase* AHIsubBase )
428 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
429 struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData;
431 if( card != NULL )
433 ObtainSemaphore( &CardBase->semaphore );
434 if( card->audioctrl == AudioCtrl )
436 // Release it if we own it.
437 card->audioctrl = NULL;
439 ReleaseSemaphore( &CardBase->semaphore );
441 AudioCtrl->ahiac_DriverData = NULL;
446 /******************************************************************************
447 ** AHIsub_Disable *************************************************************
448 ******************************************************************************/
450 void
451 _AHIsub_Disable( struct AHIAudioCtrlDrv* AudioCtrl,
452 struct DriverBase* AHIsubBase )
454 // V6 drivers do not have to preserve all registers
456 Disable();
460 /******************************************************************************
461 ** AHIsub_Enable **************************************************************
462 ******************************************************************************/
464 void
465 _AHIsub_Enable( struct AHIAudioCtrlDrv* AudioCtrl,
466 struct DriverBase* AHIsubBase )
468 // V6 drivers do not have to preserve all registers
470 Enable();
474 /******************************************************************************
475 ** AHIsub_Start ***************************************************************
476 ******************************************************************************/
478 ULONG
479 _AHIsub_Start( ULONG flags,
480 struct AHIAudioCtrlDrv* AudioCtrl,
481 struct DriverBase* AHIsubBase )
483 struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData;
484 ULONG dma_buffer_size = 0;
485 unsigned short uval;
487 //channel_reset(card);
488 codec_write(card, 0x2, 0);
489 codec_write(card, 0x08, 0x0F0F);
490 codec_write(card, 0x0A, 0x8000);
491 codec_write(card, 0x18, 0x0808);
493 uval = codec_read(card, 0x2A);
494 codec_write(card, 0x2A, uval | 0x1); // enable VRA
495 codec_write(card, 0x2C, AudioCtrl->ahiac_MixFreq);
498 if( flags & AHISF_PLAY )
501 ULONG dma_sample_frame_size;
503 card->mix_buffer = AllocVec( AudioCtrl->ahiac_BuffSize, MEMF_PUBLIC | MEMF_CLEAR );
505 if( card->mix_buffer == NULL )
507 Req( "Unable to allocate %ld bytes for mixing buffer.",
508 AudioCtrl->ahiac_BuffSize );
509 return AHIE_NOMEM;
512 /* Allocate a buffer large enough for 16-bit double-buffered
513 playback (mono or stereo) */
516 if( AudioCtrl->ahiac_Flags & AHIACF_STEREO )
518 dma_sample_frame_size = 4;
519 dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size;
521 else
523 dma_sample_frame_size = 2;
524 dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size;
527 //DebugPrintF("dma_buffer_size = %ld, %lx\n", dma_buffer_size, dma_buffer_size);
529 card->playback_buffer1 = pci_alloc_consistent(dma_buffer_size, &card->playback_buffer1_nonaligned);
530 card->playback_buffer2 = pci_alloc_consistent(dma_buffer_size, &card->playback_buffer2_nonaligned);
532 if (!card->playback_buffer1)
534 Req( "Unable to allocate playback buffer." );
535 return AHIE_NOMEM;
538 CacheClearE(card->playback_buffer1, dma_buffer_size, CACRF_ClearD);
539 CacheClearE(card->playback_buffer2, dma_buffer_size, CACRF_ClearD);
541 card->current_bytesize = dma_buffer_size;
542 card->current_frames = AudioCtrl->ahiac_MaxBuffSamples;
543 card->current_buffer = card->playback_buffer1;
544 card->playback_interrupt_enabled = TRUE;
546 build_via_table(card, card->playback_buffer1, card->playback_buffer2, dma_buffer_size, &card->play_idx_table, &card->play_idx_table_nonaligned);
547 set_table_ptr(card, TRUE);
549 pci_outb(VIA_REG_TYPE_AUTOSTART | 0x40 |
550 VIA_REG_TYPE_16BIT |
551 VIA_REG_TYPE_STEREO |
552 VIA_REG_TYPE_INT_LSAMPLE |
553 VIA_REG_TYPE_INT_EOL |
554 VIA_REG_TYPE_INT_FLAG,
555 VIA_REG_OFFSET_TYPE, card);
557 card->flip = 0;
559 card->is_playing = TRUE;
562 if( flags & AHISF_RECORD )
564 card->current_record_bytesize = RECORD_BUFFER_SAMPLES * 4;
566 /* Allocate a new recording buffer (page aligned!) */
567 card->record_buffer1 = pci_alloc_consistent(card->current_record_bytesize, &card->record_buffer1_nonaligned);
568 card->record_buffer2 = pci_alloc_consistent(card->current_record_bytesize, &card->record_buffer2_nonaligned);
570 if( card->record_buffer1 == NULL )
572 Req( "Unable to allocate %ld bytes for the recording buffer.", card->current_record_bytesize);
573 return AHIE_NOMEM;
576 SaveMixerState( card );
577 UpdateMonitorMixer( card );
579 card->record_interrupt_enabled = TRUE;
581 card->recflip = 0;
583 build_via_table(card, card->record_buffer1, card->record_buffer2, card->current_record_bytesize, &card->rec_idx_table, &card->rec_idx_table_nonaligned);
584 set_table_ptr(card, FALSE);
586 pci_outb(VIA_REG_TYPE_AUTOSTART | 0x40 |
587 VIA_REG_TYPE_16BIT |
588 VIA_REG_TYPE_STEREO |
589 VIA_REG_TYPE_INT_EOL |
590 VIA_REG_TYPE_INT_FLAG,
591 VIA_REG_OFFSET_TYPE + RECORD,
592 card);
594 card->is_recording = TRUE;
595 card->current_record_buffer = card->record_buffer1;
599 if( flags & AHISF_PLAY )
601 unsigned char val;
603 val = VIA_REG_CTRL_START;
604 pci_outb(val, VIA_REG_OFFSET_CONTROL, card);
607 if( flags & AHISF_RECORD )
609 unsigned char val;
611 val = VIA_REG_CTRL_START;
612 pci_outb(val, VIA_REG_OFFSET_CONTROL + RECORD, card);
615 return AHIE_OK;
619 /******************************************************************************
620 ** AHIsub_Update **************************************************************
621 ******************************************************************************/
623 void
624 _AHIsub_Update( ULONG flags,
625 struct AHIAudioCtrlDrv* AudioCtrl,
626 struct DriverBase* AHIsubBase )
628 struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData;
630 card->current_frames = AudioCtrl->ahiac_BuffSamples;
632 if( AudioCtrl->ahiac_Flags & AHIACF_STEREO )
634 card->current_bytesize = card->current_frames * 4;
636 else
638 card->current_bytesize = card->current_frames * 2;
643 /******************************************************************************
644 ** AHIsub_Stop ****************************************************************
645 ******************************************************************************/
647 void
648 _AHIsub_Stop( ULONG flags,
649 struct AHIAudioCtrlDrv* AudioCtrl,
650 struct DriverBase* AHIsubBase )
652 struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData;
654 unsigned char val;
656 val = VIA_REG_CTRL_TERMINATE;
658 if( flags & AHISF_PLAY && card->is_playing)
660 pci_outb(val, VIA_REG_OFFSET_CONTROL, card);
661 card->is_playing= FALSE;
663 if (card->current_bytesize > 0)
665 pci_free_consistent(card->playback_buffer1);
666 pci_free_consistent(card->playback_buffer2);
669 card->current_bytesize = 0;
670 card->current_frames = 0;
671 card->current_buffer = NULL;
673 if ( card->mix_buffer)
674 FreeVec( card->mix_buffer );
675 card->mix_buffer = NULL;
676 card->playback_interrupt_enabled = FALSE;
678 if (card->play_idx_table_nonaligned)
680 FreeVec(card->play_idx_table_nonaligned);
682 card->play_idx_table = NULL;
685 if( flags & AHISF_RECORD && card->is_recording)
687 pci_outb(val, VIA_REG_OFFSET_CONTROL + RECORD, card);
688 if( card->is_recording )
690 // Do not restore mixer unless they have been saved
691 RestoreMixerState( card );
694 if( card->record_buffer1 != NULL )
696 pci_free_consistent( card->record_buffer1);
697 pci_free_consistent( card->record_buffer2);
700 card->record_buffer1 = NULL;
701 card->record_buffer2 = NULL;
702 card->current_record_bytesize = 0;
704 card->is_recording = FALSE;
705 card->record_interrupt_enabled = FALSE;
707 pci_free_consistent(card->rec_idx_table_nonaligned);
708 card->rec_idx_table = NULL;
712 card->current_bytesize = 0;
716 /******************************************************************************
717 ** AHIsub_GetAttr *************************************************************
718 ******************************************************************************/
720 SIPTR
721 _AHIsub_GetAttr( ULONG attribute,
722 LONG argument,
723 LONG def,
724 struct TagItem* taglist,
725 struct AHIAudioCtrlDrv* AudioCtrl,
726 struct DriverBase* AHIsubBase )
728 int i;
730 switch( attribute )
732 case AHIDB_Bits:
733 return 16;
735 case AHIDB_Frequencies:
736 return FREQUENCIES;
738 case AHIDB_Frequency: // Index->Frequency
739 return (SIPTR) Frequencies[ argument ];
741 case AHIDB_Index: // Frequency->Index
742 if( argument <= (LONG) Frequencies[ 0 ] )
744 return 0;
747 if( argument >= (LONG) Frequencies[ FREQUENCIES - 1 ] )
749 return FREQUENCIES-1;
752 for( i = 1; i < FREQUENCIES; i++ )
754 if( (LONG) Frequencies[ i ] > argument )
756 if( ( argument - (LONG) Frequencies[ i - 1 ] ) < ( (LONG) Frequencies[ i ] - argument ) )
758 return i-1;
760 else
762 return i;
767 return 0; // Will not happen
769 case AHIDB_Author:
770 return (SIPTR) "Davy Wentzler";
772 case AHIDB_Copyright:
773 return (SIPTR) "(C) Davy Wentzler";
775 case AHIDB_Version:
776 return (SIPTR) LibIDString;
778 case AHIDB_Annotation:
779 return (SIPTR)
780 "VIA VT82C686 AC97 driver";
782 case AHIDB_Record:
783 return TRUE;
785 case AHIDB_FullDuplex:
786 return TRUE;
788 case AHIDB_Realtime:
789 return TRUE;
791 case AHIDB_MaxRecordSamples:
792 return RECORD_BUFFER_SAMPLES;
794 /* formula's:
795 #include <math.h>
797 unsigned long res = (unsigned long) (0x10000 * pow (10.0, dB / 20.0));
798 double dB = 20.0 * log10(0xVALUE / 65536.0);
800 printf("dB = %f, res = %lx\n", dB, res);*/
802 case AHIDB_MinMonitorVolume:
803 return 0x00000;
805 case AHIDB_MaxMonitorVolume:
806 return 0x40000;
808 case AHIDB_MinInputGain:
809 return 0x10000; // 0.0 dB gain
811 case AHIDB_MaxInputGain:
812 return 0xD55D0; // 22.5 dB gain
814 case AHIDB_MinOutputVolume:
815 return 0x00000; // -96 dB
817 case AHIDB_MaxOutputVolume:
818 return 0x10000; // 0 dB
820 case AHIDB_Inputs:
821 return INPUTS;
823 case AHIDB_Input:
824 return (SIPTR) Inputs[ argument ];
826 case AHIDB_Outputs:
827 return OUTPUTS;
829 case AHIDB_Output:
830 return (SIPTR) Outputs[ argument ];
832 default:
833 return def;
838 /******************************************************************************
839 ** AHIsub_HardwareControl *****************************************************
840 ******************************************************************************/
842 ULONG
843 _AHIsub_HardwareControl( ULONG attribute,
844 LONG argument,
845 struct AHIAudioCtrlDrv* AudioCtrl,
846 struct DriverBase* AHIsubBase )
848 struct CardData* card = (struct CardData*) AudioCtrl->ahiac_DriverData;
850 switch( attribute )
852 case AHIC_MonitorVolume:
853 card->monitor_volume = Linear2MixerGain( (Fixed) argument, &card->monitor_volume_bits );
854 if( card->is_recording )
856 UpdateMonitorMixer( card );
858 return TRUE;
860 case AHIC_MonitorVolume_Query:
861 return card->monitor_volume;
863 case AHIC_InputGain:
864 card->input_gain = Linear2RecordGain( (Fixed) argument, &card->input_gain_bits );
865 codec_write(card, AC97_RECORD_GAIN, card->input_gain_bits );
866 return TRUE;
868 case AHIC_InputGain_Query:
869 return card->input_gain;
871 case AHIC_OutputVolume:
872 card->output_volume = Linear2MixerGain( (Fixed) argument, &card->output_volume_bits );
873 codec_write(card, AC97_PCMOUT_VOL, card->output_volume_bits );
874 return TRUE;
876 case AHIC_OutputVolume_Query:
877 return card->output_volume;
879 case AHIC_Input:
880 card->input = argument;
881 codec_write(card, AC97_RECORD_SELECT, InputBits[ card->input ] );
883 if( card->is_recording )
885 UpdateMonitorMixer( card );
888 return TRUE;
890 case AHIC_Input_Query:
891 return card->input;
893 case AHIC_Output:
894 card->output = argument;
896 return TRUE;
898 case AHIC_Output_Query:
899 return card->output;
901 default:
902 return FALSE;