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
;
86 TimerIO
->tr_node
.io_Command
= TR_ADDREQUEST
; /* Add a request. */
87 TimerIO
->tr_time
.tv_secs
= 0; /* 0 seconds. */
88 TimerIO
->tr_time
.tv_micro
= val
; /* 'val' micro seconds. */
89 DoIO((struct IORequest
*) TimerIO
);
90 DeleteIORequest((struct IORequest
*) TimerIO
);
92 CloseDevice((struct IORequest
*) TimerIO
);
97 DeleteMsgPort(replymp
);
101 void WritePartialMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long shift
, unsigned long mask
, unsigned long val
)
105 tmp
= pci_inl(reg
, card
);
106 tmp
&= ~(mask
<< shift
);
108 pci_outl(tmp
, reg
, card
);
112 void ClearMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long mask
)
116 tmp
= pci_inl(reg
, card
);
118 pci_outl(tmp
, reg
, card
);
122 void WriteMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long mask
)
126 tmp
= pci_inl(reg
, card
);
128 pci_outl(tmp
, reg
, card
);
131 void cmimix_wr(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned char port
, unsigned char val
)
133 pci_outb(port
, CMPCI_REG_SBADDR
, card
);
134 pci_outb(val
, CMPCI_REG_SBDATA
, card
);
137 unsigned char cmimix_rd(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned char port
)
139 pci_outb(port
, CMPCI_REG_SBADDR
, card
);
140 return (unsigned char) pci_inb(CMPCI_REG_SBDATA
, card
);
144 /******************************************************************************
145 ** DriverData allocation ******************************************************
146 ******************************************************************************/
148 // This code used to be in _AHIsub_AllocAudio(), but since we're now
149 // handling CAMD support too, it needs to be done at driver loading
153 AllocDriverData( struct PCIDevice
*dev
,
154 struct DriverBase
* AHIsubBase
)
156 struct CMI8738Base
* CMI8738Base
= (struct CMI8738Base
*) AHIsubBase
;
157 struct CMI8738_DATA
* card
;
163 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
165 // FIXME: This should be non-cachable, DMA-able memory
166 card
= AllocVec( sizeof( *card
), MEMF_PUBLIC
| MEMF_CLEAR
);
170 Req( "Unable to allocate driver structure." );
174 card
->ahisubbase
= AHIsubBase
;
176 card
->interrupt
.is_Node
.ln_Type
= IRQTYPE
;
177 card
->interrupt
.is_Node
.ln_Pri
= 0;
178 card
->interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
180 card
->interrupt
.is_Code
= (void(*)(void))&cardinterrupt
;
182 card
->interrupt
.is_Code
= (void(*)(void))CardInterrupt
;
184 card
->interrupt
.is_Data
= (APTR
) card
;
186 card
->playback_interrupt
.is_Node
.ln_Type
= IRQTYPE
;
187 card
->playback_interrupt
.is_Node
.ln_Pri
= 0;
188 card
->playback_interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
190 card
->playback_interrupt
.is_Code
= (void(*)(void))&playbackinterrupt
;
192 card
->playback_interrupt
.is_Code
= (void(*)(void))PlaybackInterrupt
;
194 card
->playback_interrupt
.is_Data
= (APTR
) card
;
196 card
->record_interrupt
.is_Node
.ln_Type
= IRQTYPE
;
197 card
->record_interrupt
.is_Node
.ln_Pri
= 0;
198 card
->record_interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
200 card
->record_interrupt
.is_Code
= (void(*)(void))&recordinterrupt
;
202 card
->record_interrupt
.is_Code
= (void(*)(void))RecordInterrupt
;
204 card
->record_interrupt
.is_Data
= (APTR
) card
;
208 command_word
= inw_config(PCI_COMMAND
, dev
);
209 command_word
|= PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
;
210 outw_config( PCI_COMMAND
, command_word
, dev
);
212 card
->pci_master_enabled
= TRUE
;
214 /*for (i = 0; i < 6; i++)
216 if (dev->GetResourceRange(i))
217 DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress);
220 card
->iobase
= ahi_pci_get_base_address(0, dev
);
221 card
->length
= ahi_pci_get_base_size(0, dev
);
222 card
->irq
= ahi_pci_get_irq(dev
);
223 card
->chiprev
= inb_config(PCI_REVISION_ID
, dev
);
224 card
->model
= inw_config(PCI_SUBSYSTEM_ID
, dev
);
226 bug("[CMI8738]: %s: iobase = 0x%p, len = %d\n", __PRETTY_FUNCTION__
, card
->iobase
, card
->length
);
228 chipvers
= pci_inl(CMPCI_REG_INTR_CTRL
, card
) & CMPCI_REG_VERSION_MASK
;
231 if (chipvers
& CMPCI_REG_VERSION_68
)
236 if (chipvers
& CMPCI_REG_VERSION_55
)
241 if (chipvers
& CMPCI_REG_VERSION_39
)
244 if (chipvers
& CMPCI_REG_VERSION_39B
)
256 chipvers
= pci_inl(CMPCI_REG_CHANNEL_FORMAT
, card
) & CMPCI_REG_VERSION_37
;
268 /*DebugPrintF("---> chiprev = %u, model = %x, Vendor = %x\n", dev->ReadConfigByte( PCI_REVISION_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_ID),
269 dev->ReadConfigWord( PCI_SUBSYSTEM_VENDOR_ID));*/
271 bug("[CMI8738]: %s: chipvers = %u, chiprev = %u, model = %x, Vendor = %x\n", __PRETTY_FUNCTION__
,
272 card
->chipvers
, card
->chiprev
,
274 inw_config( PCI_SUBSYSTEM_VENDOR_ID
, dev
));
276 bug("[CMI8738]: %s: max channels = %d\n", __PRETTY_FUNCTION__
, card
->channels
);
278 /* Initialize chip */
279 if( card_init( card
) < 0 )
281 DebugPrintF("Unable to initialize Card subsystem.");
285 //DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt());
286 ahi_pci_add_intserver(&card
->interrupt
, dev
);
287 card
->interrupt_added
= TRUE
;
289 card
->card_initialized
= TRUE
;
292 card
->monitor_volume
= Linear2MixerGain( 0, &card
->monitor_volume_bits
);
293 card
->input_gain
= Linear2RecordGain( 0x10000, &card
->input_gain_bits
);
294 card
->output_volume
= Linear2MixerGain( 0x10000, &card
->output_volume_bits
);
295 SaveMixerState(card
);
297 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_RESET
, 0);
298 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_ADCMIX_L
, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line
299 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_ADCMIX_R
, 0); //CMPCI_SB16_MIXER_LINE_SRC_R);
301 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_OUTMIX
, 0); // set output mute off for line and CD
303 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_VOICE_L
, 0xFF); // PCM
304 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_VOICE_R
, 0xFF);
306 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_CDDA_L
, 0x00);
307 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_CDDA_R
, 0x00);
309 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_LINE_L
, 0x00);
310 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_LINE_R
, 0x00);
312 byte
= pci_inb(CMPCI_REG_MIXER25
, card
);
313 pci_outb(byte
& ~0x30, CMPCI_REG_MIXER25
, card
); // mute Aux
314 pci_outb(byte
& ~0x01, CMPCI_REG_MIXER25
, card
); // turn on mic 20dB boost
315 pci_outb(0x00, CMPCI_REG_MIXER_AUX
, card
);
317 byte
= pci_inb(CMPCI_REG_MIXER24
, card
);
318 pci_outb(byte
| CMPCI_REG_FMMUTE
, CMPCI_REG_MIXER24
, card
);
320 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MIC
, 0x00);
322 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MASTER_L
, 0xFF);
323 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MASTER_R
, 0xFF);
325 card
->mixerstate
= cmimix_rd(dev
, card
, CMPCI_SB16_MIXER_OUTMIX
);
327 #if !defined(__AROS__)
328 AddResetHandler(card
);
335 /******************************************************************************
336 ** DriverData deallocation ****************************************************
337 ******************************************************************************/
339 // And this code used to be in _AHIsub_FreeAudio().
342 FreeDriverData( struct CMI8738_DATA
* card
,
343 struct DriverBase
* AHIsubBase
)
346 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
350 if( card
->pci_dev
!= NULL
)
352 if( card
->card_initialized
)
354 card_cleanup( card
);
357 if( card
->pci_master_enabled
)
361 cmd
= inw_config(PCI_COMMAND
, (struct PCIDevice
* ) card
->pci_dev
);
362 cmd
&= ~( PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
);
363 outw_config(PCI_COMMAND
, cmd
, (struct PCIDevice
* ) card
->pci_dev
);
367 if( card
->interrupt_added
)
369 ahi_pci_rem_intserver(&card
->interrupt
, card
->pci_dev
);
377 int card_init(struct CMI8738_DATA
*card
)
379 struct PCIDevice
*dev
= (struct PCIDevice
*) card
->pci_dev
;
383 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
385 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_POWER_DOWN
); // power up
387 WriteMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_BUS_AND_DSP_RESET
);
389 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_BUS_AND_DSP_RESET
);
392 WriteMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_RESET
| CMPCI_REG_CH1_RESET
);
394 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_RESET
| CMPCI_REG_CH1_RESET
);
396 /* Disable interrupts and channels */
397 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
,CMPCI_REG_CH0_ENABLE
| CMPCI_REG_CH1_ENABLE
);
398 ClearMask(dev
, card
, CMPCI_REG_INTR_CTRL
, CMPCI_REG_CH0_INTR_ENABLE
| CMPCI_REG_CH1_INTR_ENABLE
);
400 /* Configure DMA channels, ch0 = play, ch1 = capture */
401 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_DIR
);
402 WriteMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH1_DIR
);
405 ClearMask(dev
, card
, CMPCI_REG_FUNC_1
, CMPCI_REG_SPDIFOUT_DAC
| CMPCI_REG_SPDIF0_ENABLE
);
406 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, CMPCI_REG_LEGACY_SPDIF_ENABLE
);
408 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, 0x80000000);
409 ClearMask(dev
, card
, CMPCI_REG_CHANNEL_FORMAT
, CM_CHB3D
);
410 ClearMask(dev
, card
, CMPCI_REG_CHANNEL_FORMAT
, CM_CHB3D5C
);
411 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, CMPCI_REG_ENABLE_5_1
);
412 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_2ND_SPDIFIN
);
413 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_N4SPK3D
);
414 WriteMask(dev
, card
, CMPCI_REG_INTR_STATUS
, CMPCI_REG_LEGACY_STEREO
| CMPCI_REG_LEGACY_HDMA
);
420 void card_cleanup(struct CMI8738_DATA
*card
)
426 /******************************************************************************
427 ** Misc. **********************************************************************
428 ******************************************************************************/
431 SaveMixerState( struct CMI8738_DATA
* card
)
433 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
436 card
->ac97_mic
= codec_read( card
, AC97_MIC_VOL
);
437 card
->ac97_cd
= codec_read( card
, AC97_CD_VOL
);
438 card
->ac97_video
= codec_read( card
, AC97_VIDEO_VOL
);
439 card
->ac97_aux
= codec_read( card
, AC97_AUX_VOL
);
440 card
->ac97_linein
= codec_read( card
, AC97_LINEIN_VOL
);
441 card
->ac97_phone
= codec_read( card
, AC97_PHONE_VOL
);
447 RestoreMixerState( struct CMI8738_DATA
* card
)
449 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
452 codec_write(card
, AC97_MIC_VOL
, card
->ac97_mic
);
453 codec_write(card
, AC97_CD_VOL
, card
->ac97_cd
);
454 codec_write(card
, AC97_VIDEO_VOL
, card
->ac97_video
);
455 codec_write(card
, AC97_AUX_VOL
, card
->ac97_aux
);
456 codec_write(card
, AC97_LINEIN_VOL
, card
->ac97_linein
);
457 codec_write(card
, AC97_PHONE_VOL
, card
->ac97_phone
);
462 UpdateMonitorMixer( struct CMI8738_DATA
* card
)
464 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
467 int i
= InputBits
[ card
->input
];
468 UWORD m
= card
->monitor_volume_bits
& 0x801f;
469 UWORD s
= card
->monitor_volume_bits
;
470 UWORD mm
= AC97_MUTE
| 0x0008;
471 UWORD sm
= AC97_MUTE
| 0x0808;
473 if( i
== AC97_RECMUX_STEREO_MIX
||
474 i
== AC97_RECMUX_MONO_MIX
)
476 // Use the original mixer settings
477 RestoreMixerState( card
);
481 codec_write(card
, AC97_MIC_VOL
,
482 i
== AC97_RECMUX_MIC
? m
: mm
);
484 codec_write(card
, AC97_CD_VOL
,
485 i
== AC97_RECMUX_CD
? s
: sm
);
487 codec_write(card
, AC97_VIDEO_VOL
,
488 i
== AC97_RECMUX_VIDEO
? s
: sm
);
490 codec_write(card
, AC97_AUX_VOL
,
491 i
== AC97_RECMUX_AUX
? s
: sm
);
493 codec_write(card
, AC97_LINEIN_VOL
,
494 i
== AC97_RECMUX_LINE
? s
: sm
);
496 codec_write(card
, AC97_PHONE_VOL
,
497 i
== AC97_RECMUX_PHONE
? m
: mm
);
504 Linear2MixerGain( Fixed linear
,
507 static const Fixed gain
[ 33 ] =
546 while( linear
< gain
[ v
] )
553 *bits
= 0x8000; // Mute
557 *bits
= ( v
<< 8 ) | v
;
560 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
565 Linear2RecordGain( Fixed linear
,
568 static const Fixed gain
[ 17 ] =
591 while( linear
< gain
[ v
] )
598 *bits
= 0x8000; // Mute
602 *bits
= ( ( 15 - v
) << 8 ) | ( 15 - v
);
610 SamplerateToLinearPitch( ULONG samplingrate
)
612 samplingrate
= (samplingrate
<< 8) / 375;
613 return (samplingrate
>> 1) + (samplingrate
& 1);
618 #define GFXMEM_BUFFER (64 * 1024) // 64KB should be enough for everyone...
620 void *pci_alloc_consistent(size_t size
, APTR
*NonAlignedAddress
, unsigned int boundary
)
625 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
627 address
= (void *) AllocVec(size
+ boundary
, MEMF_PUBLIC
| MEMF_CLEAR
);
631 a
= (unsigned long) address
;
632 a
= (a
+ boundary
- 1) & ~(boundary
- 1);
633 address
= (void *) a
;
636 if (NonAlignedAddress
)
638 *NonAlignedAddress
= address
;
645 void pci_free_consistent(void* addr
)
647 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
652 static ULONG
ResetHandler(struct ExceptionContext
*ctx
, struct ExecBase
*pExecBase
, struct CMI8738_DATA
*card
)
654 struct PCIDevice
*dev
= card
->pci_dev
;
656 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
658 ClearMask(dev
, card
, CMPCI_REG_INTR_CTRL
, CMPCI_REG_CH0_INTR_ENABLE
);
659 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_ENABLE
);
664 #if !defined(__AROS__)
665 void AddResetHandler(struct CMI8738_DATA
*card
)
667 static struct Interrupt interrupt
;
669 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
671 interrupt
.is_Code
= (void (*)())ResetHandler
;
672 interrupt
.is_Data
= (APTR
) card
;
673 interrupt
.is_Node
.ln_Pri
= 0;
674 interrupt
.is_Node
.ln_Type
= NT_EXTINTERRUPT
;
675 interrupt
.is_Node
.ln_Name
= "CMI8738 Reset Handler";
677 AddResetCallback( &interrupt
);