Updated interrupt handlers for current ABI (untested).
[AROS.git] / workbench / devs / AHI / Drivers / VIA-AC97 / misc.c
blob8e90dc29f1a59a7edf39a17b58c22f62301ce9c4
1 /*
2 Copyright © 2005-2013, Davy Wentzler. All rights reserved.
3 Copyright © 2010-2014, The AROS Development Team. All rights reserved.
4 $Id$
5 */
7 #include <config.h>
9 #include <exec/memory.h>
10 #include <proto/expansion.h>
12 #include <proto/dos.h>
14 #include "library.h"
15 #include "regs.h"
16 #include "interrupt.h"
17 #include "hwaccess.h"
18 #include "misc.h"
19 #include "pci_wrapper.h"
21 //#define DEBUG 1
23 #ifdef __AROS__
24 #include <asm/io.h>
25 #include <aros/debug.h>
26 #define DebugPrintF bug
27 #endif
29 //SB- Some debug/err/info output stuff.
31 #define ERR(a) DebugPrintF("[VIA-AC97] Error: " a "\n")
32 #define INF(a) DebugPrintF("[VIA-AC97] Info: " a "\n")
33 #define INFL(a,b) DebugPrintF("[VIA-AC97] Info: " a " (0x%08lx).\n", (long)b)
35 #ifdef DEBUG
36 #define DBG(a) DebugPrintF( "[VIA-AC97] Debug: " a "\n" )
37 #define DBGL(a,b) DebugPrintF( "[VIA-AC97] Debug: " a " (0x%08lx).\n", (long)b )
38 #else
39 #define DBG(a)
40 #define DBGL(a,b)
41 #endif
43 /* Global in Card.c */
44 extern const UWORD InputBits[];
45 #ifdef __amigaos4__
46 extern struct DOSIFace *IDOS;
47 extern struct PCIIFace* IPCI;
48 #endif
50 /* Public functions in main.c */
51 int card_init(struct CardData *card);
52 void card_cleanup(struct CardData *card);
55 struct Device *TimerBase = NULL;
56 struct timerequest *TimerIO = NULL;
57 struct MsgPort *replymp = NULL;
58 void AddResetHandler(struct CardData *card);
60 static const unsigned long IO_PWR_MANAGEMENT = 0xdd00;
61 static const unsigned long IO_HW_MONITOR = 0xec00;
62 static const unsigned long IO_SGD = 0xdc00;
63 static const unsigned long IO_FM = 0xe000;
64 static const unsigned long IO_MIDI = 0xe400;
66 #ifdef __AROS__
67 INTGW(static, void, playbackinterrupt, PlaybackInterrupt);
68 INTGW(static, void, recordinterrupt, RecordInterrupt);
69 INTGW(static, ULONG, cardinterrupt, CardInterrupt);
70 #endif
73 void MicroDelay(unsigned int val)
75 replymp = (struct MsgPort *) CreateMsgPort();
76 if( !replymp )
78 DebugPrintF("Could not create the reply port!\n" );
79 return;
82 TimerIO = (struct timerequest *) CreateIORequest( replymp, sizeof( struct timerequest) );
84 if( TimerIO == NULL)
86 DebugPrintF( "Out of memory.\n" );
87 return;
90 if( OpenDevice( "timer.device", UNIT_MICROHZ, (struct IORequest *) TimerIO, 0) != 0 )
92 DebugPrintF( "Unable to open 'timer.device'.\n" );
93 return;
95 else
97 TimerBase = (struct Device *) TimerIO->tr_node.io_Device;
100 if (TimerIO)
102 TimerIO->tr_node.io_Command = TR_ADDREQUEST; /* Add a request. */
103 TimerIO->tr_time.tv_secs = 0; /* 0 seconds. */
104 TimerIO->tr_time.tv_micro = val; /* 'val' micro seconds. */
105 DoIO( (struct IORequest *) TimerIO );
106 CloseDevice( (struct IORequest *) TimerIO );
107 DeleteIORequest( (struct IORequest *) TimerIO);
108 TimerIO = NULL;
111 if( replymp )
112 DeleteMsgPort(replymp);
116 /******************************************************************************
117 ** DriverData allocation ******************************************************
118 ******************************************************************************/
120 // This code used to be in _AHIsub_AllocAudio(), but since we're now
121 // handling CAMD support too, it needs to be done at driver loading
122 // time.
124 struct CardData*
125 AllocDriverData( struct PCIDevice * dev,
126 struct DriverBase* AHIsubBase )
128 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
129 struct CardData* dd;
130 UWORD command_word;
131 int i;
132 unsigned short uval;
134 // FIXME: This should be non-cachable, DMA-able memory
135 dd = AllocVec( sizeof( *dd ), MEMF_PUBLIC | MEMF_CLEAR );
137 if( dd == NULL )
139 Req( "Unable to allocate driver structure." );
140 return NULL;
143 dd->ahisubbase = AHIsubBase;
145 dd->interrupt.is_Node.ln_Type = IRQTYPE;
146 dd->interrupt.is_Node.ln_Pri = 0;
147 dd->interrupt.is_Node.ln_Name = (STRPTR) LibName;
148 #ifdef __AROS__
149 dd->interrupt.is_Code = (void(*)(void)) cardinterrupt;
150 #else
151 dd->interrupt.is_Code = (void(*)(void)) CardInterrupt;
152 #endif
153 dd->interrupt.is_Data = (APTR) dd;
155 dd->playback_interrupt.is_Node.ln_Type = IRQTYPE;
156 dd->playback_interrupt.is_Node.ln_Pri = 0;
157 dd->playback_interrupt.is_Node.ln_Name = (STRPTR) LibName;
158 #ifdef __AROS__
159 dd->playback_interrupt.is_Code = playbackinterrupt;
160 #else
161 dd->playback_interrupt.is_Code = PlaybackInterrupt;
162 #endif
163 dd->playback_interrupt.is_Data = (APTR) dd;
165 dd->record_interrupt.is_Node.ln_Type = IRQTYPE;
166 dd->record_interrupt.is_Node.ln_Pri = 0;
167 dd->record_interrupt.is_Node.ln_Name = (STRPTR) LibName;
168 #ifdef __AROS__
169 dd->record_interrupt.is_Code = recordinterrupt;
170 #else
171 dd->record_interrupt.is_Code = RecordInterrupt;
172 #endif
173 dd->record_interrupt.is_Data = (APTR) dd;
175 dd->pci_dev = dev;
177 outw_config(PCI_COMMAND, 0x00, dd->pci_dev);
178 //dev->WriteConfigLong( PCI_BASE_ADDRESS_0, 0xdc00 );
180 //SB- Configure IO, if required. Force IO into 16bit/ISA address space, since it
181 // apparently won't work in 32bit address range. Really ought to check this in
182 // Linux sometime...
183 unsigned long tula = ( inl_config(PCI_BASE_ADDRESS_0, dd->pci_dev) & 0xfffffffc );
184 if( ( tula == 0 ) || ( tula & 0xffff0000 ) )
186 outl_config(PCI_BASE_ADDRESS_0, IO_SGD, dd->pci_dev);
187 DBGL( "configured audio SGD IO base", IO_SGD );
190 tula = ( inl_config(PCI_BASE_ADDRESS_1, dd->pci_dev) & 0xfffffffc );
191 if( ( tula == 0 ) || ( tula & 0xffff0000 ) )
193 outl_config(PCI_BASE_ADDRESS_1, IO_FM, dd->pci_dev);
194 //DBGL( "configured audio FM IO base", IO_FM );
197 tula = ( inl_config(PCI_BASE_ADDRESS_2, dd->pci_dev) & 0xfffffffc );
198 if( ( tula == 0 ) || ( tula & 0xffff0000 ) )
200 outl_config(PCI_BASE_ADDRESS_2, IO_MIDI, dd->pci_dev);
201 //DBGL( "configured audio MIDI IO base", IO_MIDI );
204 outw_config(PCI_COMMAND, PCI_COMMAND_IO, dd->pci_dev);
206 dd->pci_master_enabled = TRUE;
208 dd->iobase = inl_config(PCI_BASE_ADDRESS_0, dd->pci_dev) & 0xfffffffe;
210 dd->length = ~( ahi_pci_get_base_size(0, dd->pci_dev) & PCI_BASE_ADDRESS_IO_MASK );
211 dd->irq = ahi_pci_get_irq(dev);
212 dd->chiprev = inb_config(PCI_REVISION_ID, dev);
213 dd->model = inw_config(PCI_SUBSYSTEM_ID, dev);
215 dd->table.area = NULL;
216 dd->table.addr = NULL;
217 dd->table.bytes = 0;
218 dd->play_idx_table = NULL;
219 dd->rec_idx_table = NULL;
221 /* Initialize chip */
222 if( card_init( dd ) < 0 )
224 DebugPrintF("Unable to initialize Card subsystem.\n");
226 FreeVec(dd);
227 return NULL;
231 ahi_pci_add_intserver(&dd->interrupt, dd->pci_dev);
232 dd->interrupt_added = TRUE;
234 dd->card_initialized = TRUE;
235 dd->input = 0;
236 dd->output = 0;
237 dd->monitor_volume = Linear2MixerGain( 0x10000, &dd->monitor_volume_bits );
238 dd->input_gain = Linear2RecordGain( 0x10000, &dd->input_gain_bits );
239 dd->output_volume = Linear2MixerGain( 0x10000, &dd->output_volume_bits );
240 SaveMixerState(dd);
242 AddResetHandler(dd);
244 return dd;
248 /******************************************************************************
249 ** DriverData deallocation ****************************************************
250 ******************************************************************************/
252 // And this code used to be in _AHIsub_FreeAudio().
254 void
255 FreeDriverData( struct CardData* dd,
256 struct DriverBase* AHIsubBase )
258 if( dd != NULL )
260 if( dd->pci_dev != NULL )
262 if( dd->card_initialized )
264 card_cleanup( dd );
267 if( dd->pci_master_enabled )
269 UWORD cmd;
271 cmd = inw_config(PCI_COMMAND, dd->pci_dev);
272 cmd &= ~( PCI_COMMAND_IO | PCI_COMMAND_MASTER );
273 outw_config(PCI_COMMAND, cmd, dd->pci_dev);
277 if( dd->reset_handler_added )
279 RemResetCallback(&dd->reset_handler);
282 if( dd->interrupt_added )
284 ahi_pci_rem_intserver(&dd->interrupt, dd->pci_dev);
287 FreeVec( dd );
292 void channel_reset(struct CardData *card)
294 struct PCIDevice *dev = (struct PCIDevice *) card->pci_dev;
296 pci_outb(VIA_REG_CTRL_TERMINATE /*| VIA_REG_CTRL_RESET*/, VIA_REG_OFFSET_CONTROL, card);
297 pci_inb(VIA_REG_OFFSET_CONTROL, card);
298 udelay(50);
299 /* disable interrupts */
300 pci_outb(0x00, VIA_REG_OFFSET_CONTROL, card);
301 /* clear interrupts */
302 pci_outb(0x03, VIA_REG_OFFSET_STATUS, card);
303 pci_outb(0x00, VIA_REG_OFFSET_TYPE, card); /* for via686 */
304 // pci_outl(0, VIA_REG_OFFSET_CURR_PTR, card);
307 //reset/init ac97 codec. Returns false if the primary codec isn't found/ready.
308 BOOL ac97_reset( struct PCIDevice *via686b_audio)
310 static const unsigned long reset_delay = 100; //link operation delay, should be some uS..
311 static const unsigned long codec_timeout = 50; //codec ready timeout, about half a second...
313 //cold reset..
314 //SB- Set the link to a known initial configuration.
315 //SB- Note: The 'standard' ***x reset code is quite similar to this, except it
316 // de-asserts SYNC at this point, possibly in case the link/codec is
317 // in low power mode. We don't, because if we do, the dreaded half-
318 // rate problem occurs, with ~100% reliability (..interesting).
319 // It is a bit of a worry that the 'standard' reset code fails, but
320 // perhaps it is simply because we have a completely untouched link,
321 // whereas on any 686 based PC, the link was probably confugured
322 // already in the BIOS.
324 outb_config(VIA_ACLINK_CTRL,
325 VIA_ACLINK_CTRL_ENABLE | VIA_ACLINK_CTRL_RESET,
326 via686b_audio);
327 MicroDelay( reset_delay );
329 //SB- Assert reset.
330 outb_config(VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_ENABLE, via686b_audio);
331 MicroDelay( reset_delay );
333 //SB- De-assert reset, enable VRA/PCM etc.
334 outb_config( VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_ENABLE |
335 VIA_ACLINK_CTRL_RESET |
336 VIA_ACLINK_CTRL_VRA |
337 VIA_ACLINK_CTRL_PCM,
338 via686b_audio);
339 MicroDelay( reset_delay );
341 //SB- Check primary codec...
342 unsigned long delay = codec_timeout;
343 while( delay-- )
345 if(inb_config( VIA_ACLINK_STAT, via686b_audio) & VIA_ACLINK_C00_READY)
347 //DBG( "AC-Link reset ok." );
348 return TRUE;
351 MicroDelay( 10000 );
354 DBG( "AC-Link reset, primary codec not ready!" );
355 return FALSE;
361 int card_init(struct CardData *card)
363 struct PCIDevice *dev = (struct PCIDevice *) card->pci_dev;
364 unsigned short cod, uval;
365 unsigned char pval, byt;
366 long *ptr;
367 int teller = 0;
368 ULONG val;
369 struct PCIDevice *via686b_ACPI;
370 BOOL aclink = FALSE;
373 #ifdef __amigaos4__
374 via686b_ACPI = IPCI->FindDeviceTags( FDT_VendorID, 0x1106, FDT_DeviceID, 0x3057,
375 FDT_Index, 0x00,
376 TAG_DONE );
377 #else
378 via686b_ACPI = ahi_pci_find_device(0x1106, 0x3057, NULL);
379 #endif
381 if (via686b_ACPI == NULL) // try device 0x3058
383 #ifdef __amigaos4__
384 via686b_ACPI = IPCI->FindDeviceTags( FDT_VendorID, 0x1106, FDT_DeviceID, 0x3058,
385 FDT_Index, 0x00,
386 TAG_DONE );
387 #else
388 via686b_ACPI = ahi_pci_find_device(0x1106, 0x3058, NULL);
389 #endif
392 if (via686b_ACPI)
394 BOOL lock;
396 #ifdef __amigaos4__
397 lock = via686b_ACPI->Lock( PCI_LOCK_SHARED );
398 if (lock == FALSE)
400 DBG( "couldn't lock the ACPI! Trying anyway..." );
402 #endif
404 //SB- Configure power management, if it isn't already.
405 if( !( inl_config(0x48, via686b_ACPI) & 0xfffffffe ) )
407 outl_config(0x48, IO_PWR_MANAGEMENT, via686b_ACPI);
408 DBGL( "configured power management IO", IO_PWR_MANAGEMENT );
410 else
412 DBG("Power management IO already configured");
415 //SB- Enable IO (preserve other bits, but note that technically speaking
416 // we should also be clreaing PSON gating here (it's already cleared))
417 outb_config( 0x41, (inb_config(0x41, via686b_ACPI) | 0x80), via686b_ACPI);
419 //SB- Power up the 686b, if it isn't already.
420 if( !( inb_config(0x42, via686b_ACPI) & 0x40 ) )
422 //Cause a soft resume event...
423 outb(inb(IO_PWR_MANAGEMENT + 0x05) | 0x80, IO_PWR_MANAGEMENT + 0x05 );
425 //Busy loop until the soft resume completes.
426 //We have a bail out counter, but no idea how long we should wait really.
427 //..1/10th of a second wasn't long enough
428 unsigned long delay = 25; //1/2 a second, or so
430 while( --delay )
432 if( ( inb_config( 0x42, via686b_ACPI) & 0x40))
434 DBG( "powered up the 686b." );
435 break; //SUSC# state
438 Delay(1);
441 if( delay == 0 )
442 ERR( "soft resume timed out!" );
444 else
446 DBG("VIA already powered up");
449 #ifdef __amigaos4__
450 if (lock)
451 via686b_ACPI->Unlock();
453 IPCI->FreeDevice( via686b_ACPI );
454 #endif
456 else
458 ERR( "couldn't find the ACPI!" );
459 return -1;
462 //SB- Don't know if there's a codec yet?
463 // codec_write(card, 0x2, 0x8000);
464 // codec_write(card, 0x4, 0x8000);
466 //SB- Check codec..
467 aclink = ( inb_config(VIA_ACLINK_STAT, dev) & VIA_ACLINK_C00_READY );
469 //SB- If no codec, reset.
470 //SB- Note: This is a possible source of trouble. It might be safer to reset
471 // every time. Only reason not to is 'pop' avoidance on soft reboot
472 // and in case UBoot did the reset.
473 if( !aclink )
475 aclink = ac97_reset(dev);
477 else
479 //SB- Make sure VRA/PCM are enabled if we didn't use our own reset code.
481 outb_config(VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_ENABLE |\
482 VIA_ACLINK_CTRL_RESET |\
483 VIA_ACLINK_CTRL_VRA |\
484 VIA_ACLINK_CTRL_PCM, dev);
487 if( aclink )
489 //INF( "initialized AC'97 codec." );
491 else
493 ERR( "sorry, you don't seem to have the AC'97 codec!" );
494 return -1;
498 Delay( 1 );
501 pval = inb_config(VIA_ACLINK_STAT, dev);
503 if (! (pval & VIA_ACLINK_C00_READY))
505 DebugPrintF("WHY?\n");
506 pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL,
507 VIA_ACLINK_CTRL_ENABLE |
508 VIA_ACLINK_CTRL_RESET |
509 VIA_ACLINK_CTRL_SYNC);
510 udelay(100);
512 pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, 0x00);
513 udelay(100);
515 pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_INIT);
516 udelay(100);
518 pval = inb_config(VIA_ACLINK_STAT, dd->pci_dev);
520 if (! (pval & VIA_ACLINK_C00_READY))
522 return -1;
526 while (teller < 1000)
528 pval = inb_config(VIA_ACLINK_STAT, dd->pci_dev);
529 if (pval & VIA_ACLINK_C00_READY)
530 break;
532 udelay(20);
533 teller++;
537 if ((val = pci_inl(VIA_CODEC_CMD, card)) & VIA_REG_AC97_BUSY)
538 snd_printk("AC97 codec is not ready!\n");
540 outb_config(VIA_FM_NMI_CTRL, 0, card->pci_dev);
541 pci_outl(0, VIA_REG_GPI_INTR, card);
543 channel_reset(card);
545 codec_write(card, AC97_MASTER_VOL_STEREO, 0x0000 ); // no attenuation
546 codec_write(card, AC97_AUXOUT_VOL, 0x8000 ); // volume of the rear output
547 codec_write(card, AC97_MASTER_VOL_MONO, 0x8000 );
548 codec_write(card, AC97_MASTER_TONE, 0x0f0f ); // bass/treble control (if present)
549 codec_write(card, AC97_PCBEEP_VOL, 0x8000 ); // PC beep internal speaker?
551 codec_write(card, AC97_RECORD_SELECT, 0);
552 codec_write(card, AC97_RECORD_GAIN, 0x0000 ); // 0 dB gain
555 // Analog mixer input gain registers
556 codec_write(card, AC97_PHONE_VOL, AC97_MUTE | 0x0008 );
557 codec_write(card, AC97_MIC_VOL, AC97_MUTE | 0x0048 ); // 10 dB boost
558 codec_write(card, AC97_LINEIN_VOL, AC97_MUTE | 0x0808 );
559 codec_write(card, AC97_CD_VOL, 0x0808 );
560 codec_write(card, AC97_VIDEO_VOL, AC97_MUTE | 0x0808 );
561 codec_write(card, AC97_AUX_VOL, 0x0808 );
562 codec_write(card, AC97_PCMOUT_VOL, 0x0808 );
564 DBG("card_init() was a success!");
566 return 0;
570 void card_cleanup(struct CardData *card)
576 /******************************************************************************
577 ** Misc. **********************************************************************
578 ******************************************************************************/
580 void
581 SaveMixerState( struct CardData* dd )
583 dd->ac97_mic = codec_read( dd, AC97_MIC_VOL );
584 dd->ac97_cd = codec_read( dd, AC97_CD_VOL );
585 dd->ac97_video = codec_read( dd, AC97_VIDEO_VOL );
586 dd->ac97_aux = codec_read( dd, AC97_AUX_VOL );
587 dd->ac97_linein = codec_read( dd, AC97_LINEIN_VOL );
588 dd->ac97_phone = codec_read( dd, AC97_PHONE_VOL );
592 void
593 RestoreMixerState( struct CardData* dd )
595 codec_write(dd, AC97_MIC_VOL, dd->ac97_mic );
596 codec_write(dd, AC97_CD_VOL, dd->ac97_cd );
597 codec_write(dd, AC97_VIDEO_VOL, dd->ac97_video );
598 codec_write(dd, AC97_AUX_VOL, dd->ac97_aux );
599 codec_write(dd, AC97_LINEIN_VOL, dd->ac97_linein );
600 codec_write(dd, AC97_PHONE_VOL, dd->ac97_phone );
603 void
604 UpdateMonitorMixer( struct CardData* dd )
606 int i = InputBits[ dd->input ];
607 UWORD m = dd->monitor_volume_bits & 0x801f;
608 UWORD s = dd->monitor_volume_bits;
609 UWORD mm = AC97_MUTE | 0x0008;
610 UWORD sm = AC97_MUTE | 0x0808;
612 if( i == AC97_RECMUX_STEREO_MIX ||
613 i == AC97_RECMUX_MONO_MIX )
615 // Use the original mixer settings
616 RestoreMixerState( dd );
618 else
620 codec_write(dd, AC97_MIC_VOL,
621 i == AC97_RECMUX_MIC ? m : mm );
623 codec_write(dd, AC97_CD_VOL,
624 i == AC97_RECMUX_CD ? s : sm );
626 codec_write(dd, AC97_VIDEO_VOL,
627 i == AC97_RECMUX_VIDEO ? s : sm );
629 codec_write(dd, AC97_AUX_VOL,
630 i == AC97_RECMUX_AUX ? s : sm );
632 codec_write(dd, AC97_LINEIN_VOL,
633 i == AC97_RECMUX_LINE ? s : sm );
635 codec_write(dd, AC97_PHONE_VOL,
636 i == AC97_RECMUX_PHONE ? m : mm );
641 Fixed
642 Linear2MixerGain( Fixed linear,
643 UWORD* bits )
645 static const Fixed gain[ 33 ] =
647 260904, // +12.0 dB
648 219523, // +10.5 dB
649 184706, // +9.0 dB
650 155410, // +7.5 dB
651 130762, // +6.0 dB
652 110022, // +4.5 dB
653 92572, // +3.0 dB
654 77890, // +1.5 dB
655 65536, // ±0.0 dB
656 55142, // -1.5 dB
657 46396, // -3.0 dB
658 39037, // -4.5 dB
659 32846, // -6.0 dB
660 27636, // -7.5 dB
661 23253, // -9.0 dB
662 19565, // -10.5 dB
663 16462, // -12.0 dB
664 13851, // -13.5 dB
665 11654, // -15.0 dB
666 9806, // -16.5 dB
667 8250, // -18.0 dB
668 6942, // -19.5 dB
669 5841, // -21.0 dB
670 4915, // -22.5 dB
671 4135, // -24.0 dB
672 3479, // -25.5 dB
673 2927, // -27.0 dB
674 2463, // -28.5 dB
675 2072, // -30.0 dB
676 1744, // -31.5 dB
677 1467, // -33.0 dB
678 1234, // -34.5 dB
679 0 // -oo dB
682 int v = 0;
684 while( linear < gain[ v ] )
686 ++v;
689 if( v == 32 )
691 *bits = 0x8000; // Mute
693 else
695 *bits = ( v << 8 ) | v;
698 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
699 return gain[ v ];
702 Fixed
703 Linear2RecordGain( Fixed linear,
704 UWORD* bits )
706 static const Fixed gain[ 17 ] =
708 873937, // +22.5 dB
709 735326, // +21.0 dB
710 618700, // +19.5 dB
711 520571, // +18.0 dB
712 438006, // +16.5 dB
713 368536, // +15.0 dB
714 310084, // +13.5 dB
715 260904, // +12.0 dB
716 219523, // +10.5 dB
717 184706, // +9.0 dB
718 155410, // +7.5 dB
719 130762, // +6.0 dB
720 110022, // +4.5 dB
721 92572, // +3.0 dB
722 77890, // +1.5 dB
723 65536, // ±0.0 dB
724 0 // -oo dB
727 int v = 0;
729 while( linear < gain[ v ] )
731 ++v;
734 if( v == 16 )
736 *bits = 0x8000; // Mute
738 else
740 *bits = ( ( 15 - v ) << 8 ) | ( 15 - v );
743 return gain[ v ];
747 ULONG
748 SamplerateToLinearPitch( ULONG samplingrate )
750 samplingrate = (samplingrate << 8) / 375;
751 return (samplingrate >> 1) + (samplingrate & 1);
755 #define CACHELINE_SIZE 32
757 void *pci_alloc_consistent(size_t size, APTR *NonAlignedAddress)
759 void* address;
760 unsigned long a;
762 #ifdef __amigaos4__
763 if (OpenResource("newmemory.resource"))
765 address = AllocVecTags(size, AVT_Type, MEMF_SHARED, AVT_Contiguous, TRUE, AVT_Lock, TRUE,
766 AVT_PhysicalAlignment, 32, AVT_Clear, 0, TAG_DONE);
768 else
769 #endif
771 address = AllocVec( size + CACHELINE_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
773 if( address != NULL )
775 a = (unsigned long) address;
776 a = (a + CACHELINE_SIZE - 1) & ~(CACHELINE_SIZE - 1);
777 address = (void *) a;
781 *NonAlignedAddress = address;
783 return address;
787 void pci_free_consistent(void* addr)
789 FreeVec( addr );
793 #ifdef __amigaos4__
794 static ULONG ResetHandler(struct ExceptionContext *ctx, struct ExecBase *pExecBase, struct CardData *card)
795 #else
796 static ULONG ResetHandler(struct CardData *card)
797 #endif
799 struct PCIDevice *dev = card->pci_dev;
801 unsigned char val = VIA_REG_CTRL_TERMINATE;
803 pci_outb(val, VIA_REG_OFFSET_CONTROL, card);
804 pci_outb(val, VIA_REG_OFFSET_CONTROL + RECORD, card);
806 channel_reset(card);
808 return 0UL;
812 void AddResetHandler(struct CardData *card)
814 struct Interrupt *handler = &card->reset_handler;
816 handler->is_Code = (APTR)ResetHandler;
817 handler->is_Data = (APTR) card;
818 handler->is_Node.ln_Pri = 0;
819 #ifdef __amigaos4__
820 handler->is_Node.ln_Type = NT_EXTINTERRUPT;
821 #else
822 handler->is_Node.ln_Type = NT_INTERRUPT;
823 #endif
824 handler->is_Node.ln_Name = "VIA-AC97 reset handler";
826 card->reset_handler_added = AddResetCallback(handler);