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.
14 #include <exec/memory.h>
18 #include <aros/debug.h>
21 #include <proto/exec.h>
22 #include <proto/dos.h>
28 #include "interrupt.h"
31 #include "pci_wrapper.h"
33 #define CACHELINE_SIZE 32
36 #define DebugPrintF bug
37 INTGW(static, void, playbackinterrupt
, PlaybackInterrupt
);
38 INTGW(static, void, recordinterrupt
, RecordInterrupt
);
39 INTGW(static, ULONG
, cardinterrupt
, CardInterrupt
);
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
);
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();
62 bug("Could not create the reply port!\n");
66 TimerIO
= (struct timerequest
*) CreateIORequest(replymp
, sizeof(struct timerequest
));
70 DebugPrintF("Out of memory.\n");
74 if (OpenDevice((CONST_STRPTR
) "timer.device", UNIT_MICROHZ
, (struct IORequest
*) TimerIO
, 0) != 0)
76 DebugPrintF("Unable to open 'timer.device'.\n");
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
);
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
)
102 tmp
= pci_inl(reg
, card
);
103 tmp
&= ~(mask
<< shift
);
105 pci_outl(tmp
, reg
, card
);
109 void ClearMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long mask
)
113 tmp
= pci_inl(reg
, card
);
115 pci_outl(tmp
, reg
, card
);
119 void WriteMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long mask
)
123 tmp
= pci_inl(reg
, card
);
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
150 AllocDriverData( struct PCIDevice
*dev
,
151 struct DriverBase
* AHIsubBase
)
153 struct CMI8738Base
* CMI8738Base
= (struct CMI8738Base
*) AHIsubBase
;
154 struct CMI8738_DATA
* card
;
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
);
167 Req( "Unable to allocate driver structure." );
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
;
177 card
->interrupt
.is_Code
= (VOID_FUNC
)cardinterrupt
;
179 card
->interrupt
.is_Code
= (void(*)(void))CardInterrupt
;
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
;
187 card
->playback_interrupt
.is_Code
= (VOID_FUNC
)playbackinterrupt
;
189 card
->playback_interrupt
.is_Code
= (void(*)(void))PlaybackInterrupt
;
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
;
197 card
->record_interrupt
.is_Code
= (VOID_FUNC
)recordinterrupt
;
199 card
->record_interrupt
.is_Code
= (void(*)(void))RecordInterrupt
;
201 card
->record_interrupt
.is_Data
= (APTR
) card
;
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
;
228 if (chipvers
& CMPCI_REG_VERSION_68
)
233 if (chipvers
& CMPCI_REG_VERSION_55
)
238 if (chipvers
& CMPCI_REG_VERSION_39
)
241 if (chipvers
& CMPCI_REG_VERSION_39B
)
253 chipvers
= pci_inl(CMPCI_REG_CHANNEL_FORMAT
, card
) & CMPCI_REG_VERSION_37
;
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
,
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.");
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
;
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
);
332 /******************************************************************************
333 ** DriverData deallocation ****************************************************
334 ******************************************************************************/
336 // And this code used to be in _AHIsub_FreeAudio().
339 FreeDriverData( struct CMI8738_DATA
* card
,
340 struct DriverBase
* AHIsubBase
)
343 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
347 if( card
->pci_dev
!= NULL
)
349 if( card
->card_initialized
)
351 card_cleanup( card
);
354 if( card
->pci_master_enabled
)
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
);
374 int card_init(struct CMI8738_DATA
*card
)
376 struct PCIDevice
*dev
= (struct PCIDevice
*) card
->pci_dev
;
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
);
386 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_BUS_AND_DSP_RESET
);
389 WriteMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_RESET
| CMPCI_REG_CH1_RESET
);
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
);
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
);
417 void card_cleanup(struct CMI8738_DATA
*card
)
423 /******************************************************************************
424 ** Misc. **********************************************************************
425 ******************************************************************************/
428 SaveMixerState( struct CMI8738_DATA
* card
)
430 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
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
);
444 RestoreMixerState( struct CMI8738_DATA
* card
)
446 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
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
);
459 UpdateMonitorMixer( struct CMI8738_DATA
* card
)
461 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
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
);
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
);
501 Linear2MixerGain( Fixed linear
,
504 static const Fixed gain
[ 33 ] =
543 while( linear
< gain
[ v
] )
550 *bits
= 0x8000; // Mute
554 *bits
= ( v
<< 8 ) | v
;
557 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
562 Linear2RecordGain( Fixed linear
,
565 static const Fixed gain
[ 17 ] =
588 while( linear
< gain
[ v
] )
595 *bits
= 0x8000; // Mute
599 *bits
= ( ( 15 - v
) << 8 ) | ( 15 - v
);
607 SamplerateToLinearPitch( ULONG samplingrate
)
609 samplingrate
= (samplingrate
<< 8) / 375;
610 return (samplingrate
>> 1) + (samplingrate
& 1);
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
)
622 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
624 address
= (void *) AllocVec(size
+ boundary
, MEMF_PUBLIC
| MEMF_CLEAR
);
628 a
= (unsigned long) address
;
629 a
= (a
+ boundary
- 1) & ~(boundary
- 1);
630 address
= (void *) a
;
633 if (NonAlignedAddress
)
635 *NonAlignedAddress
= address
;
642 void pci_free_consistent(void* addr
)
644 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
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
);
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
);