alsa.audio: move handling of XRUN when writting to the slave task
[AROS.git] / workbench / devs / AHI / Drivers / CMI8738 / misc.c
blobfee4e23bcaad1dc83a64e521a51bb7f931cdc8f5
1 /*
2 The contents of this file are subject to the AROS Public License Version 1.1 (the "License");
3 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
5 Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
6 ANY KIND, either express or implied. See the License for the specific language governing rights and
7 limitations under the License.
9 The Original Code is written by Davy Wentzler.
12 //#include <config.h>
14 #include <exec/memory.h>
16 #ifdef __AROS__
17 #define DEBUG 1
18 #include <aros/debug.h>
19 #endif
21 #include <proto/exec.h>
22 #include <proto/dos.h>
24 #include <string.h>
26 #include "library.h"
27 #include "regs.h"
28 #include "interrupt.h"
29 #include "misc.h"
31 #include "pci_wrapper.h"
33 #define CACHELINE_SIZE 32
35 #ifdef INTGW
36 #define DebugPrintF bug
37 INTGW(static, void, playbackinterrupt, PlaybackInterrupt);
38 INTGW(static, void, recordinterrupt, RecordInterrupt);
39 INTGW(static, ULONG, cardinterrupt, CardInterrupt);
40 #endif
42 /* Global in Card.c */
43 extern const UWORD InputBits[];
45 /* Public functions in main.c */
46 int card_init(struct CMI8738_DATA *card);
47 void card_cleanup(struct CMI8738_DATA *card);
49 #if !defined(__AROS__)
50 void AddResetHandler(struct CMI8738_DATA *card);
51 #endif
53 void micro_delay(unsigned int val)
55 struct Device* TimerBase = NULL;
56 struct timerequest* TimerIO = NULL;
57 struct MsgPort * replymp;
59 replymp = (struct MsgPort *) CreateMsgPort();
60 if (!replymp)
62 bug("Could not create the reply port!\n");
63 return;
66 TimerIO = (struct timerequest *) CreateIORequest(replymp, sizeof(struct timerequest));
68 if (TimerIO == NULL)
70 DebugPrintF("Out of memory.\n");
71 return;
74 if (OpenDevice((CONST_STRPTR) "timer.device", UNIT_MICROHZ, (struct IORequest *) TimerIO, 0) != 0)
76 DebugPrintF("Unable to open 'timer.device'.\n");
77 return;
79 else
81 TimerBase = (struct Device *) TimerIO->tr_node.io_Device;
84 TimerIO->tr_node.io_Command = TR_ADDREQUEST; /* Add a request. */
85 TimerIO->tr_time.tv_secs = 0; /* 0 seconds. */
86 TimerIO->tr_time.tv_micro = val; /* 'val' micro seconds. */
87 DoIO((struct IORequest *) TimerIO);
88 CloseDevice((struct IORequest *) TimerIO);
89 DeleteIORequest((struct IORequest *) TimerIO);
90 TimerIO = NULL;
92 if (replymp)
94 DeleteMsgPort(replymp);
98 void WritePartialMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long shift, unsigned long mask, unsigned long val)
100 ULONG tmp;
102 tmp = pci_inl(reg, card);
103 tmp &= ~(mask << shift);
104 tmp |= val << shift;
105 pci_outl(tmp, reg, card);
109 void ClearMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long mask)
111 ULONG tmp;
113 tmp = pci_inl(reg, card);
114 tmp &= ~mask;
115 pci_outl(tmp, reg, card);
119 void WriteMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long mask)
121 ULONG tmp;
123 tmp = pci_inl(reg, card);
124 tmp |= mask;
125 pci_outl(tmp, reg, card);
128 void cmimix_wr(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned char port, unsigned char val)
130 pci_outb(port, CMPCI_REG_SBADDR, card);
131 pci_outb(val, CMPCI_REG_SBDATA, card);
134 unsigned char cmimix_rd(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned char port)
136 pci_outb(port, CMPCI_REG_SBADDR, card);
137 return (unsigned char) pci_inb(CMPCI_REG_SBDATA, card);
141 /******************************************************************************
142 ** DriverData allocation ******************************************************
143 ******************************************************************************/
145 // This code used to be in _AHIsub_AllocAudio(), but since we're now
146 // handling CAMD support too, it needs to be done at driver loading
147 // time.
149 struct CMI8738_DATA*
150 AllocDriverData( struct PCIDevice *dev,
151 struct DriverBase* AHIsubBase )
153 struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase;
154 struct CMI8738_DATA* card;
155 UWORD command_word;
156 ULONG chipvers;
157 int i, v;
158 unsigned char byte;
160 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
162 // FIXME: This should be non-cachable, DMA-able memory
163 card = AllocVec( sizeof( *card ), MEMF_PUBLIC | MEMF_CLEAR );
165 if( card == NULL )
167 Req( "Unable to allocate driver structure." );
168 return NULL;
171 card->ahisubbase = AHIsubBase;
173 card->interrupt.is_Node.ln_Type = IRQTYPE;
174 card->interrupt.is_Node.ln_Pri = 0;
175 card->interrupt.is_Node.ln_Name = (STRPTR) LibName;
176 #ifdef INTGW
177 card->interrupt.is_Code = (VOID_FUNC)cardinterrupt;
178 #else
179 card->interrupt.is_Code = (void(*)(void))CardInterrupt;
180 #endif
181 card->interrupt.is_Data = (APTR) card;
183 card->playback_interrupt.is_Node.ln_Type = IRQTYPE;
184 card->playback_interrupt.is_Node.ln_Pri = 0;
185 card->playback_interrupt.is_Node.ln_Name = (STRPTR) LibName;
186 #ifdef INTGW
187 card->playback_interrupt.is_Code = (VOID_FUNC)playbackinterrupt;
188 #else
189 card->playback_interrupt.is_Code = (void(*)(void))PlaybackInterrupt;
190 #endif
191 card->playback_interrupt.is_Data = (APTR) card;
193 card->record_interrupt.is_Node.ln_Type = IRQTYPE;
194 card->record_interrupt.is_Node.ln_Pri = 0;
195 card->record_interrupt.is_Node.ln_Name = (STRPTR) LibName;
196 #ifdef INTGW
197 card->record_interrupt.is_Code = (VOID_FUNC)recordinterrupt;
198 #else
199 card->record_interrupt.is_Code = (void(*)(void))RecordInterrupt;
200 #endif
201 card->record_interrupt.is_Data = (APTR) card;
203 card->pci_dev = dev;
205 command_word = inw_config(PCI_COMMAND, dev);
206 command_word |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
207 outw_config( PCI_COMMAND, command_word, dev);
209 card->pci_master_enabled = TRUE;
211 /*for (i = 0; i < 6; i++)
213 if (dev->GetResourceRange(i))
214 DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress);
217 card->iobase = ahi_pci_get_base_address(0, dev);
218 card->length = ahi_pci_get_base_size(0, dev);
219 card->irq = ahi_pci_get_irq(dev);
220 card->chiprev = inb_config(PCI_REVISION_ID, dev);
221 card->model = inw_config(PCI_SUBSYSTEM_ID, dev);
223 bug("[CMI8738]: %s: iobase = 0x%p, len = %d\n", __PRETTY_FUNCTION__, card->iobase, card->length);
225 chipvers = pci_inl(CMPCI_REG_INTR_CTRL, card) & CMPCI_REG_VERSION_MASK;
226 if (chipvers)
228 if (chipvers & CMPCI_REG_VERSION_68)
230 card->chipvers = 68;
231 card->channels = 8;
233 if (chipvers & CMPCI_REG_VERSION_55)
235 card->chipvers = 55;
236 card->channels = 6;
238 if (chipvers & CMPCI_REG_VERSION_39)
240 card->chipvers = 39;
241 if (chipvers & CMPCI_REG_VERSION_39B)
243 card->channels = 6;
245 else
247 card->channels = 4;
251 else
253 chipvers = pci_inl(CMPCI_REG_CHANNEL_FORMAT, card) & CMPCI_REG_VERSION_37;
254 if (!chipvers)
256 card->chipvers = 33;
257 card->channels = 2;
259 else
261 card->chipvers = 37;
262 card->channels = 2;
265 /*DebugPrintF("---> chiprev = %u, model = %x, Vendor = %x\n", dev->ReadConfigByte( PCI_REVISION_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_ID),
266 dev->ReadConfigWord( PCI_SUBSYSTEM_VENDOR_ID));*/
268 bug("[CMI8738]: %s: chipvers = %u, chiprev = %u, model = %x, Vendor = %x\n", __PRETTY_FUNCTION__,
269 card->chipvers, card->chiprev,
270 card->model,
271 inw_config( PCI_SUBSYSTEM_VENDOR_ID, dev));
273 bug("[CMI8738]: %s: max channels = %d\n", __PRETTY_FUNCTION__, card->channels);
275 /* Initialize chip */
276 if( card_init( card ) < 0 )
278 DebugPrintF("Unable to initialize Card subsystem.");
279 return NULL;
282 //DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt());
283 ahi_pci_add_intserver(&card->interrupt, dev);
284 card->interrupt_added = TRUE;
286 card->card_initialized = TRUE;
287 card->input = 0;
288 card->output = 0;
289 card->monitor_volume = Linear2MixerGain( 0, &card->monitor_volume_bits );
290 card->input_gain = Linear2RecordGain( 0x10000, &card->input_gain_bits );
291 card->output_volume = Linear2MixerGain( 0x10000, &card->output_volume_bits );
292 SaveMixerState(card);
294 cmimix_wr(dev, card, CMPCI_SB16_MIXER_RESET, 0);
295 cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line
296 cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, 0); //CMPCI_SB16_MIXER_LINE_SRC_R);
298 cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, 0); // set output mute off for line and CD
300 cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_L, 0xFF); // PCM
301 cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_R, 0xFF);
303 cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_L, 0x00);
304 cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_R, 0x00);
306 cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_L, 0x00);
307 cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_R, 0x00);
309 byte = pci_inb(CMPCI_REG_MIXER25, card);
310 pci_outb(byte & ~0x30, CMPCI_REG_MIXER25, card); // mute Aux
311 pci_outb(byte & ~0x01, CMPCI_REG_MIXER25, card); // turn on mic 20dB boost
312 pci_outb(0x00, CMPCI_REG_MIXER_AUX, card);
314 byte = pci_inb(CMPCI_REG_MIXER24, card);
315 pci_outb(byte | CMPCI_REG_FMMUTE, CMPCI_REG_MIXER24, card);
317 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MIC, 0x00);
319 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_L, 0xFF);
320 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_R, 0xFF);
322 card->mixerstate = cmimix_rd(dev, card, CMPCI_SB16_MIXER_OUTMIX);
324 #if !defined(__AROS__)
325 AddResetHandler(card);
326 #endif
328 return card;
332 /******************************************************************************
333 ** DriverData deallocation ****************************************************
334 ******************************************************************************/
336 // And this code used to be in _AHIsub_FreeAudio().
338 void
339 FreeDriverData( struct CMI8738_DATA* card,
340 struct DriverBase* AHIsubBase )
343 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
345 if( card != NULL )
347 if( card->pci_dev != NULL )
349 if( card->card_initialized )
351 card_cleanup( card );
354 if( card->pci_master_enabled )
356 UWORD cmd;
358 cmd = inw_config(PCI_COMMAND, (struct PCIDevice * ) card->pci_dev);
359 cmd &= ~( PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER );
360 outw_config(PCI_COMMAND, cmd, (struct PCIDevice * ) card->pci_dev );
364 if( card->interrupt_added )
366 ahi_pci_rem_intserver(&card->interrupt, card->pci_dev);
369 FreeVec( card );
374 int card_init(struct CMI8738_DATA *card)
376 struct PCIDevice *dev = (struct PCIDevice *) card->pci_dev;
377 unsigned short cod;
378 unsigned long val;
380 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
382 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); // power up
384 WriteMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET);
385 udelay(1);
386 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET);
388 /* reset channels */
389 WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET);
390 udelay(1);
391 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET);
393 /* Disable interrupts and channels */
394 ClearMask(dev, card, CMPCI_REG_FUNC_0,CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE);
395 ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE | CMPCI_REG_CH1_INTR_ENABLE);
397 /* Configure DMA channels, ch0 = play, ch1 = capture */
398 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR);
399 WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR);
401 // digital I/O
402 ClearMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIFOUT_DAC | CMPCI_REG_SPDIF0_ENABLE);
403 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_LEGACY_SPDIF_ENABLE);
405 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, 0x80000000);
406 ClearMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CM_CHB3D);
407 ClearMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CM_CHB3D5C);
408 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_ENABLE_5_1);
409 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_2ND_SPDIFIN);
410 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_N4SPK3D);
411 WriteMask(dev, card, CMPCI_REG_INTR_STATUS, CMPCI_REG_LEGACY_STEREO | CMPCI_REG_LEGACY_HDMA);
413 return 0;
417 void card_cleanup(struct CMI8738_DATA *card)
423 /******************************************************************************
424 ** Misc. **********************************************************************
425 ******************************************************************************/
427 void
428 SaveMixerState( struct CMI8738_DATA* card )
430 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
432 #if 0
433 card->ac97_mic = codec_read( card, AC97_MIC_VOL );
434 card->ac97_cd = codec_read( card, AC97_CD_VOL );
435 card->ac97_video = codec_read( card, AC97_VIDEO_VOL );
436 card->ac97_aux = codec_read( card, AC97_AUX_VOL );
437 card->ac97_linein = codec_read( card, AC97_LINEIN_VOL );
438 card->ac97_phone = codec_read( card, AC97_PHONE_VOL );
439 #endif
443 void
444 RestoreMixerState( struct CMI8738_DATA* card )
446 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
448 #if 0
449 codec_write(card, AC97_MIC_VOL, card->ac97_mic );
450 codec_write(card, AC97_CD_VOL, card->ac97_cd );
451 codec_write(card, AC97_VIDEO_VOL, card->ac97_video );
452 codec_write(card, AC97_AUX_VOL, card->ac97_aux );
453 codec_write(card, AC97_LINEIN_VOL, card->ac97_linein );
454 codec_write(card, AC97_PHONE_VOL, card->ac97_phone );
455 #endif
458 void
459 UpdateMonitorMixer( struct CMI8738_DATA* card )
461 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
463 #if 0
464 int i = InputBits[ card->input ];
465 UWORD m = card->monitor_volume_bits & 0x801f;
466 UWORD s = card->monitor_volume_bits;
467 UWORD mm = AC97_MUTE | 0x0008;
468 UWORD sm = AC97_MUTE | 0x0808;
470 if( i == AC97_RECMUX_STEREO_MIX ||
471 i == AC97_RECMUX_MONO_MIX )
473 // Use the original mixer settings
474 RestoreMixerState( card );
476 else
478 codec_write(card, AC97_MIC_VOL,
479 i == AC97_RECMUX_MIC ? m : mm );
481 codec_write(card, AC97_CD_VOL,
482 i == AC97_RECMUX_CD ? s : sm );
484 codec_write(card, AC97_VIDEO_VOL,
485 i == AC97_RECMUX_VIDEO ? s : sm );
487 codec_write(card, AC97_AUX_VOL,
488 i == AC97_RECMUX_AUX ? s : sm );
490 codec_write(card, AC97_LINEIN_VOL,
491 i == AC97_RECMUX_LINE ? s : sm );
493 codec_write(card, AC97_PHONE_VOL,
494 i == AC97_RECMUX_PHONE ? m : mm );
496 #endif
500 Fixed
501 Linear2MixerGain( Fixed linear,
502 UWORD* bits )
504 static const Fixed gain[ 33 ] =
506 260904, // +12.0 dB
507 219523, // +10.5 dB
508 184706, // +9.0 dB
509 155410, // +7.5 dB
510 130762, // +6.0 dB
511 110022, // +4.5 dB
512 92572, // +3.0 dB
513 77890, // +1.5 dB
514 65536, // ±0.0 dB
515 55142, // -1.5 dB
516 46396, // -3.0 dB
517 39037, // -4.5 dB
518 32846, // -6.0 dB
519 27636, // -7.5 dB
520 23253, // -9.0 dB
521 19565, // -10.5 dB
522 16462, // -12.0 dB
523 13851, // -13.5 dB
524 11654, // -15.0 dB
525 9806, // -16.5 dB
526 8250, // -18.0 dB
527 6942, // -19.5 dB
528 5841, // -21.0 dB
529 4915, // -22.5 dB
530 4135, // -24.0 dB
531 3479, // -25.5 dB
532 2927, // -27.0 dB
533 2463, // -28.5 dB
534 2072, // -30.0 dB
535 1744, // -31.5 dB
536 1467, // -33.0 dB
537 1234, // -34.5 dB
538 0 // -oo dB
541 int v = 0;
543 while( linear < gain[ v ] )
545 ++v;
548 if( v == 32 )
550 *bits = 0x8000; // Mute
552 else
554 *bits = ( v << 8 ) | v;
557 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
558 return gain[ v ];
561 Fixed
562 Linear2RecordGain( Fixed linear,
563 UWORD* bits )
565 static const Fixed gain[ 17 ] =
567 873937, // +22.5 dB
568 735326, // +21.0 dB
569 618700, // +19.5 dB
570 520571, // +18.0 dB
571 438006, // +16.5 dB
572 368536, // +15.0 dB
573 310084, // +13.5 dB
574 260904, // +12.0 dB
575 219523, // +10.5 dB
576 184706, // +9.0 dB
577 155410, // +7.5 dB
578 130762, // +6.0 dB
579 110022, // +4.5 dB
580 92572, // +3.0 dB
581 77890, // +1.5 dB
582 65536, // ±0.0 dB
583 0 // -oo dB
586 int v = 0;
588 while( linear < gain[ v ] )
590 ++v;
593 if( v == 16 )
595 *bits = 0x8000; // Mute
597 else
599 *bits = ( ( 15 - v ) << 8 ) | ( 15 - v );
602 return gain[ v ];
606 ULONG
607 SamplerateToLinearPitch( ULONG samplingrate )
609 samplingrate = (samplingrate << 8) / 375;
610 return (samplingrate >> 1) + (samplingrate & 1);
614 APTR DMAheader = 0;
615 #define GFXMEM_BUFFER (64 * 1024) // 64KB should be enough for everyone...
617 void *pci_alloc_consistent(size_t size, APTR *NonAlignedAddress, unsigned int boundary)
619 void* address;
620 unsigned long a;
622 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
624 address = (void *) AllocVec(size + boundary, MEMF_PUBLIC | MEMF_CLEAR);
626 if (address != NULL)
628 a = (unsigned long) address;
629 a = (a + boundary - 1) & ~(boundary - 1);
630 address = (void *) a;
633 if (NonAlignedAddress)
635 *NonAlignedAddress = address;
638 return address;
642 void pci_free_consistent(void* addr)
644 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
646 FreeVec(addr);
649 static ULONG ResetHandler(struct ExceptionContext *ctx, struct ExecBase *pExecBase, struct CMI8738_DATA *card)
651 struct PCIDevice *dev = card->pci_dev;
653 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
655 ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
656 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE);
658 return 0UL;
661 #if !defined(__AROS__)
662 void AddResetHandler(struct CMI8738_DATA *card)
664 static struct Interrupt interrupt;
666 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
668 interrupt.is_Code = (void (*)())ResetHandler;
669 interrupt.is_Data = (APTR) card;
670 interrupt.is_Node.ln_Pri = 0;
671 interrupt.is_Node.ln_Type = NT_EXTINTERRUPT;
672 interrupt.is_Node.ln_Name = "CMI8738 Reset Handler";
674 AddResetCallback( &interrupt );
676 #endif