2 Copyright © 2005-2013, Davy Wentzler. All rights reserved.
3 Copyright © 2010-2016, The AROS Development Team. All rights reserved.
10 #include <proto/expansion.h>
12 extern struct UtilityIFace
* IUtility
;
13 extern struct AHIsubIFace
* IAHIsub
;
14 extern struct MMUIFace
* IMMU
;
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>
31 #include "pci_wrapper.h"
34 #include <aros/debug.h>
35 #define DebugPrintF bug
38 /******************************************************************************
39 ** Globals ********************************************************************
40 ******************************************************************************/
42 #define FREQUENCIES 11
44 static const ULONG Frequencies
[ FREQUENCIES
] =
61 static const STRPTR Inputs
[ INPUTS
] =
73 /* Not static since it's used in misc.c too */
74 const UWORD InputBits
[ INPUTS
] =
81 AC97_RECMUX_STEREO_MIX
,
90 BOOL
ac97_wait_idle2(struct CardData
*card
);
92 static const STRPTR Outputs
[ OUTPUTS
] =
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 */
115 val
= codec_xread(card
);
116 if (! (val
& VIA_REG_AC97_BUSY
))
121 snd_printk("(codec_ready()) AC97 codec not ready!\n");
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
);
141 void codec_wait(struct CardData
*card
)
147 void codec_write(struct CardData
*card
,
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
;
158 codec_xwrite(card
, xval
);
163 BOOL
ac97_wait_idle(struct CardData
*card
)
165 unsigned long tul
= 0;
170 if( !( ( tul
= pci_inl(VIA_REG_AC97
, card
)) & VIA_REG_AC97_BUSY
) )
175 DebugPrintF("Timed out waiting for AC97 controller!\n");
179 unsigned short codec_read(struct CardData
*card
, unsigned char reg
)
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");
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
225 if( !( ( tul
= pci_inl(VIA_AC97_RX
, card
) ) & VIA_AC97_RX_BUSY
) )
230 DebugPrintF("Timed out waiting for AC97 controller! VIA_AC97_RX = %lx\n", tul
);
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");
265 static void set_table_ptr(struct CardData
*card
, BOOL Play
)
276 stack
= IExec
->SuperState();
277 phys_addr
= IMMU
->GetPhysicalAddress(card
->play_idx_table
);
278 IExec
->UserState(stack
);
280 phys_addr
= (ULONG
)card
->play_idx_table
;
283 pci_outl(phys_addr
, 4, card
);
288 stack
= IExec
->SuperState();
289 phys_addr
= IMMU
->GetPhysicalAddress(card
->rec_idx_table
);
290 IExec
->UserState(stack
);
292 phys_addr
= (ULONG
)card
->rec_idx_table
;
295 pci_outl(phys_addr
, 4 + RECORD
, card
);
305 #define tolittle(a) ((((ULONG) (a) & 0xFF000000) >> 24) | \
306 (((ULONG) (a) & 0x00FF0000) >> 8) | \
307 (((ULONG) (a) & 0x0000FF00) << 8) | \
308 (((ULONG) (a) & 0x000000FF) << 24))
310 #define tolittle(a) AROS_LONG2LE(a)
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
)
321 *idx
= pci_alloc_consistent(sizeof(**idx
) * 4, idx_nonaligned
);
324 stack
= IExec
->SuperState();
325 phys_addr
= IMMU
->GetPhysicalAddress(sgbuf1
);
326 IExec
->UserState(stack
);
328 phys_addr
= (ULONG
)sgbuf1
;
331 (*idx
)[0].offset
= (APTR
) tolittle(phys_addr
);
332 (*idx
)[0].size
= tolittle( (OneBufferSize
) | VIA_TBL_BIT_FLAG
);
335 stack
= IExec
->SuperState();
336 phys_addr
= IMMU
->GetPhysicalAddress(sgbuf2
);
337 IExec
->UserState(stack
);
339 phys_addr
= (ULONG
)sgbuf2
;
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);
352 /******************************************************************************
353 ** AHIsub_AllocAudio **********************************************************
354 ******************************************************************************/
357 _AHIsub_AllocAudio( struct TagItem
* taglist
,
358 struct AHIAudioCtrlDrv
* AudioCtrl
,
359 struct DriverBase
* AHIsubBase
)
361 struct CardBase
* CardBase
= (struct CardBase
*) AHIsubBase
;
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
);
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
);
390 card
->audioctrl
= AudioCtrl
;
392 ReleaseSemaphore( &CardBase
->semaphore
);
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
;
420 /******************************************************************************
421 ** AHIsub_FreeAudio ***********************************************************
422 ******************************************************************************/
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
;
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 ******************************************************************************/
451 _AHIsub_Disable( struct AHIAudioCtrlDrv
* AudioCtrl
,
452 struct DriverBase
* AHIsubBase
)
454 // V6 drivers do not have to preserve all registers
460 /******************************************************************************
461 ** AHIsub_Enable **************************************************************
462 ******************************************************************************/
465 _AHIsub_Enable( struct AHIAudioCtrlDrv
* AudioCtrl
,
466 struct DriverBase
* AHIsubBase
)
468 // V6 drivers do not have to preserve all registers
474 /******************************************************************************
475 ** AHIsub_Start ***************************************************************
476 ******************************************************************************/
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;
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
);
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
;
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." );
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 |
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
);
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
);
576 SaveMixerState( card
);
577 UpdateMonitorMixer( card
);
579 card
->record_interrupt_enabled
= TRUE
;
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 |
588 VIA_REG_TYPE_STEREO
|
589 VIA_REG_TYPE_INT_EOL
|
590 VIA_REG_TYPE_INT_FLAG
,
591 VIA_REG_OFFSET_TYPE
+ RECORD
,
594 card
->is_recording
= TRUE
;
595 card
->current_record_buffer
= card
->record_buffer1
;
599 if( flags
& AHISF_PLAY
)
603 val
= VIA_REG_CTRL_START
;
604 pci_outb(val
, VIA_REG_OFFSET_CONTROL
, card
);
607 if( flags
& AHISF_RECORD
)
611 val
= VIA_REG_CTRL_START
;
612 pci_outb(val
, VIA_REG_OFFSET_CONTROL
+ RECORD
, card
);
619 /******************************************************************************
620 ** AHIsub_Update **************************************************************
621 ******************************************************************************/
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;
638 card
->current_bytesize
= card
->current_frames
* 2;
643 /******************************************************************************
644 ** AHIsub_Stop ****************************************************************
645 ******************************************************************************/
648 _AHIsub_Stop( ULONG flags
,
649 struct AHIAudioCtrlDrv
* AudioCtrl
,
650 struct DriverBase
* AHIsubBase
)
652 struct CardData
* card
= (struct CardData
*) AudioCtrl
->ahiac_DriverData
;
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 ******************************************************************************/
721 _AHIsub_GetAttr( ULONG attribute
,
724 struct TagItem
* taglist
,
725 struct AHIAudioCtrlDrv
* AudioCtrl
,
726 struct DriverBase
* AHIsubBase
)
735 case AHIDB_Frequencies
:
738 case AHIDB_Frequency
: // Index->Frequency
739 return (SIPTR
) Frequencies
[ argument
];
741 case AHIDB_Index
: // Frequency->Index
742 if( argument
<= (LONG
) Frequencies
[ 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
) )
767 return 0; // Will not happen
770 return (SIPTR
) "Davy Wentzler";
772 case AHIDB_Copyright
:
773 return (SIPTR
) "(C) Davy Wentzler";
776 return (SIPTR
) LibIDString
;
778 case AHIDB_Annotation
:
780 "VIA VT82C686 AC97 driver";
785 case AHIDB_FullDuplex
:
791 case AHIDB_MaxRecordSamples
:
792 return RECORD_BUFFER_SAMPLES
;
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
:
805 case AHIDB_MaxMonitorVolume
:
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
824 return (SIPTR
) Inputs
[ argument
];
830 return (SIPTR
) Outputs
[ argument
];
838 /******************************************************************************
839 ** AHIsub_HardwareControl *****************************************************
840 ******************************************************************************/
843 _AHIsub_HardwareControl( ULONG attribute
,
845 struct AHIAudioCtrlDrv
* AudioCtrl
,
846 struct DriverBase
* AHIsubBase
)
848 struct CardData
* card
= (struct CardData
*) AudioCtrl
->ahiac_DriverData
;
852 case AHIC_MonitorVolume
:
853 card
->monitor_volume
= Linear2MixerGain( (Fixed
) argument
, &card
->monitor_volume_bits
);
854 if( card
->is_recording
)
856 UpdateMonitorMixer( card
);
860 case AHIC_MonitorVolume_Query
:
861 return card
->monitor_volume
;
864 card
->input_gain
= Linear2RecordGain( (Fixed
) argument
, &card
->input_gain_bits
);
865 codec_write(card
, AC97_RECORD_GAIN
, card
->input_gain_bits
);
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
);
876 case AHIC_OutputVolume_Query
:
877 return card
->output_volume
;
880 card
->input
= argument
;
881 codec_write(card
, AC97_RECORD_SELECT
, InputBits
[ card
->input
] );
883 if( card
->is_recording
)
885 UpdateMonitorMixer( card
);
890 case AHIC_Input_Query
:
894 card
->output
= argument
;
898 case AHIC_Output_Query
: