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 timerequest
* TimerIO
= NULL
;
56 struct MsgPort
* replymp
;
58 replymp
= (struct MsgPort
*) CreateMsgPort();
61 bug("Could not create the reply port!\n");
65 TimerIO
= (struct timerequest
*) CreateIORequest(replymp
, sizeof(struct timerequest
));
69 DebugPrintF("Out of memory.\n");
73 if (OpenDevice((CONST_STRPTR
) "timer.device", UNIT_MICROHZ
, (struct IORequest
*) TimerIO
, 0) != 0)
75 DebugPrintF("Unable to open 'timer.device'.\n");
79 TimerIO
->tr_node
.io_Command
= TR_ADDREQUEST
; /* Add a request. */
80 TimerIO
->tr_time
.tv_secs
= 0; /* 0 seconds. */
81 TimerIO
->tr_time
.tv_micro
= val
; /* 'val' micro seconds. */
82 DoIO((struct IORequest
*) TimerIO
);
83 CloseDevice((struct IORequest
*) TimerIO
);
84 DeleteIORequest((struct IORequest
*) TimerIO
);
89 DeleteMsgPort(replymp
);
93 void WritePartialMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long shift
, unsigned long mask
, unsigned long val
)
97 tmp
= pci_inl(reg
, card
);
98 tmp
&= ~(mask
<< shift
);
100 pci_outl(tmp
, reg
, card
);
104 void ClearMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long mask
)
108 tmp
= pci_inl(reg
, card
);
110 pci_outl(tmp
, reg
, card
);
114 void WriteMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long mask
)
118 tmp
= pci_inl(reg
, card
);
120 pci_outl(tmp
, reg
, card
);
123 void cmimix_wr(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned char port
, unsigned char val
)
125 pci_outb(port
, CMPCI_REG_SBADDR
, card
);
126 pci_outb(val
, CMPCI_REG_SBDATA
, card
);
129 unsigned char cmimix_rd(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned char port
)
131 pci_outb(port
, CMPCI_REG_SBADDR
, card
);
132 return (unsigned char) pci_inb(CMPCI_REG_SBDATA
, card
);
136 /******************************************************************************
137 ** DriverData allocation ******************************************************
138 ******************************************************************************/
140 // This code used to be in _AHIsub_AllocAudio(), but since we're now
141 // handling CAMD support too, it needs to be done at driver loading
145 AllocDriverData( struct PCIDevice
*dev
,
146 struct DriverBase
* AHIsubBase
)
148 struct CMI8738_DATA
* card
;
156 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
158 // FIXME: This should be non-cachable, DMA-able memory
159 card
= AllocVec( sizeof( *card
), MEMF_PUBLIC
| MEMF_CLEAR
);
163 Req( "Unable to allocate driver structure." );
167 card
->ahisubbase
= AHIsubBase
;
169 card
->interrupt
.is_Node
.ln_Type
= IRQTYPE
;
170 card
->interrupt
.is_Node
.ln_Pri
= 0;
171 card
->interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
173 card
->interrupt
.is_Code
= (VOID_FUNC
)cardinterrupt
;
175 card
->interrupt
.is_Code
= (void(*)(void))CardInterrupt
;
177 card
->interrupt
.is_Data
= (APTR
) card
;
179 card
->playback_interrupt
.is_Node
.ln_Type
= IRQTYPE
;
180 card
->playback_interrupt
.is_Node
.ln_Pri
= 0;
181 card
->playback_interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
183 card
->playback_interrupt
.is_Code
= (VOID_FUNC
)playbackinterrupt
;
185 card
->playback_interrupt
.is_Code
= (void(*)(void))PlaybackInterrupt
;
187 card
->playback_interrupt
.is_Data
= (APTR
) card
;
189 card
->record_interrupt
.is_Node
.ln_Type
= IRQTYPE
;
190 card
->record_interrupt
.is_Node
.ln_Pri
= 0;
191 card
->record_interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
193 card
->record_interrupt
.is_Code
= (VOID_FUNC
)recordinterrupt
;
195 card
->record_interrupt
.is_Code
= (void(*)(void))RecordInterrupt
;
197 card
->record_interrupt
.is_Data
= (APTR
) card
;
201 command_word
= inw_config(PCI_COMMAND
, dev
);
202 command_word
|= PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
;
203 outw_config( PCI_COMMAND
, command_word
, dev
);
205 card
->pci_master_enabled
= TRUE
;
207 /*for (i = 0; i < 6; i++)
209 if (dev->GetResourceRange(i))
210 DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress);
213 card
->iobase
= ahi_pci_get_base_address(0, dev
);
214 card
->length
= ahi_pci_get_base_size(0, dev
);
215 card
->irq
= ahi_pci_get_irq(dev
);
216 card
->chiprev
= inb_config(PCI_REVISION_ID
, dev
);
217 card
->model
= inw_config(PCI_SUBSYSTEM_ID
, dev
);
219 bug("[CMI8738]: %s: iobase = 0x%p, len = %d\n", __PRETTY_FUNCTION__
, card
->iobase
, card
->length
);
221 chipvers
= pci_inl(CMPCI_REG_INTR_CTRL
, card
) & CMPCI_REG_VERSION_MASK
;
224 if (chipvers
& CMPCI_REG_VERSION_68
)
229 if (chipvers
& CMPCI_REG_VERSION_55
)
234 if (chipvers
& CMPCI_REG_VERSION_39
)
237 if (chipvers
& CMPCI_REG_VERSION_39B
)
249 chipvers
= pci_inl(CMPCI_REG_CHANNEL_FORMAT
, card
) & CMPCI_REG_VERSION_37
;
261 /*DebugPrintF("---> chiprev = %u, model = %x, Vendor = %x\n", dev->ReadConfigByte( PCI_REVISION_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_ID),
262 dev->ReadConfigWord( PCI_SUBSYSTEM_VENDOR_ID));*/
264 bug("[CMI8738]: %s: chipvers = %u, chiprev = %u, model = %x, Vendor = %x\n", __PRETTY_FUNCTION__
,
265 card
->chipvers
, card
->chiprev
,
267 inw_config( PCI_SUBSYSTEM_VENDOR_ID
, dev
));
269 bug("[CMI8738]: %s: max channels = %d\n", __PRETTY_FUNCTION__
, card
->channels
);
271 /* Initialize chip */
272 if( card_init( card
) < 0 )
274 DebugPrintF("Unable to initialize Card subsystem.");
278 //DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt());
279 ahi_pci_add_intserver(&card
->interrupt
, dev
);
280 card
->interrupt_added
= TRUE
;
282 card
->card_initialized
= TRUE
;
285 card
->monitor_volume
= Linear2MixerGain( 0, &card
->monitor_volume_bits
);
286 card
->input_gain
= Linear2RecordGain( 0x10000, &card
->input_gain_bits
);
287 card
->output_volume
= Linear2MixerGain( 0x10000, &card
->output_volume_bits
);
288 SaveMixerState(card
);
290 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_RESET
, 0);
291 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_ADCMIX_L
, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line
292 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_ADCMIX_R
, 0); //CMPCI_SB16_MIXER_LINE_SRC_R);
294 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_OUTMIX
, 0); // set output mute off for line and CD
296 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_VOICE_L
, 0xFF); // PCM
297 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_VOICE_R
, 0xFF);
299 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_CDDA_L
, 0x00);
300 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_CDDA_R
, 0x00);
302 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_LINE_L
, 0x00);
303 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_LINE_R
, 0x00);
305 byte
= pci_inb(CMPCI_REG_MIXER25
, card
);
306 pci_outb(byte
& ~0x30, CMPCI_REG_MIXER25
, card
); // mute Aux
307 pci_outb(byte
& ~0x01, CMPCI_REG_MIXER25
, card
); // turn on mic 20dB boost
308 pci_outb(0x00, CMPCI_REG_MIXER_AUX
, card
);
310 byte
= pci_inb(CMPCI_REG_MIXER24
, card
);
311 pci_outb(byte
| CMPCI_REG_FMMUTE
, CMPCI_REG_MIXER24
, card
);
313 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MIC
, 0x00);
315 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MASTER_L
, 0xFF);
316 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MASTER_R
, 0xFF);
318 card
->mixerstate
= cmimix_rd(dev
, card
, CMPCI_SB16_MIXER_OUTMIX
);
320 #if !defined(__AROS__)
321 AddResetHandler(card
);
328 /******************************************************************************
329 ** DriverData deallocation ****************************************************
330 ******************************************************************************/
332 // And this code used to be in _AHIsub_FreeAudio().
335 FreeDriverData( struct CMI8738_DATA
* card
,
336 struct DriverBase
* AHIsubBase
)
339 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
343 if( card
->pci_dev
!= NULL
)
345 if( card
->card_initialized
)
347 card_cleanup( card
);
350 if( card
->pci_master_enabled
)
354 cmd
= inw_config(PCI_COMMAND
, (struct PCIDevice
* ) card
->pci_dev
);
355 cmd
&= ~( PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
);
356 outw_config(PCI_COMMAND
, cmd
, (struct PCIDevice
* ) card
->pci_dev
);
360 if( card
->interrupt_added
)
362 ahi_pci_rem_intserver(&card
->interrupt
, card
->pci_dev
);
370 int card_init(struct CMI8738_DATA
*card
)
372 struct PCIDevice
*dev
= (struct PCIDevice
*) card
->pci_dev
;
374 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
376 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_POWER_DOWN
); // power up
378 WriteMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_BUS_AND_DSP_RESET
);
380 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_BUS_AND_DSP_RESET
);
383 WriteMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_RESET
| CMPCI_REG_CH1_RESET
);
385 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_RESET
| CMPCI_REG_CH1_RESET
);
387 /* Disable interrupts and channels */
388 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
,CMPCI_REG_CH0_ENABLE
| CMPCI_REG_CH1_ENABLE
);
389 ClearMask(dev
, card
, CMPCI_REG_INTR_CTRL
, CMPCI_REG_CH0_INTR_ENABLE
| CMPCI_REG_CH1_INTR_ENABLE
);
391 /* Configure DMA channels, ch0 = play, ch1 = capture */
392 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_DIR
);
393 WriteMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH1_DIR
);
396 ClearMask(dev
, card
, CMPCI_REG_FUNC_1
, CMPCI_REG_SPDIFOUT_DAC
| CMPCI_REG_SPDIF0_ENABLE
);
397 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, CMPCI_REG_LEGACY_SPDIF_ENABLE
);
399 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, 0x80000000);
400 ClearMask(dev
, card
, CMPCI_REG_CHANNEL_FORMAT
, CM_CHB3D
);
401 ClearMask(dev
, card
, CMPCI_REG_CHANNEL_FORMAT
, CM_CHB3D5C
);
402 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, CMPCI_REG_ENABLE_5_1
);
403 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_2ND_SPDIFIN
);
404 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_N4SPK3D
);
405 WriteMask(dev
, card
, CMPCI_REG_INTR_STATUS
, CMPCI_REG_LEGACY_STEREO
| CMPCI_REG_LEGACY_HDMA
);
411 void card_cleanup(struct CMI8738_DATA
*card
)
417 /******************************************************************************
418 ** Misc. **********************************************************************
419 ******************************************************************************/
422 SaveMixerState( struct CMI8738_DATA
* card
)
424 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
427 card
->ac97_mic
= codec_read( card
, AC97_MIC_VOL
);
428 card
->ac97_cd
= codec_read( card
, AC97_CD_VOL
);
429 card
->ac97_video
= codec_read( card
, AC97_VIDEO_VOL
);
430 card
->ac97_aux
= codec_read( card
, AC97_AUX_VOL
);
431 card
->ac97_linein
= codec_read( card
, AC97_LINEIN_VOL
);
432 card
->ac97_phone
= codec_read( card
, AC97_PHONE_VOL
);
438 RestoreMixerState( struct CMI8738_DATA
* card
)
440 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
443 codec_write(card
, AC97_MIC_VOL
, card
->ac97_mic
);
444 codec_write(card
, AC97_CD_VOL
, card
->ac97_cd
);
445 codec_write(card
, AC97_VIDEO_VOL
, card
->ac97_video
);
446 codec_write(card
, AC97_AUX_VOL
, card
->ac97_aux
);
447 codec_write(card
, AC97_LINEIN_VOL
, card
->ac97_linein
);
448 codec_write(card
, AC97_PHONE_VOL
, card
->ac97_phone
);
453 UpdateMonitorMixer( struct CMI8738_DATA
* card
)
455 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
458 int i
= InputBits
[ card
->input
];
459 UWORD m
= card
->monitor_volume_bits
& 0x801f;
460 UWORD s
= card
->monitor_volume_bits
;
461 UWORD mm
= AC97_MUTE
| 0x0008;
462 UWORD sm
= AC97_MUTE
| 0x0808;
464 if( i
== AC97_RECMUX_STEREO_MIX
||
465 i
== AC97_RECMUX_MONO_MIX
)
467 // Use the original mixer settings
468 RestoreMixerState( card
);
472 codec_write(card
, AC97_MIC_VOL
,
473 i
== AC97_RECMUX_MIC
? m
: mm
);
475 codec_write(card
, AC97_CD_VOL
,
476 i
== AC97_RECMUX_CD
? s
: sm
);
478 codec_write(card
, AC97_VIDEO_VOL
,
479 i
== AC97_RECMUX_VIDEO
? s
: sm
);
481 codec_write(card
, AC97_AUX_VOL
,
482 i
== AC97_RECMUX_AUX
? s
: sm
);
484 codec_write(card
, AC97_LINEIN_VOL
,
485 i
== AC97_RECMUX_LINE
? s
: sm
);
487 codec_write(card
, AC97_PHONE_VOL
,
488 i
== AC97_RECMUX_PHONE
? m
: mm
);
495 Linear2MixerGain( Fixed linear
,
498 static const Fixed gain
[ 33 ] =
537 while( linear
< gain
[ v
] )
544 *bits
= 0x8000; // Mute
548 *bits
= ( v
<< 8 ) | v
;
551 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
556 Linear2RecordGain( Fixed linear
,
559 static const Fixed gain
[ 17 ] =
582 while( linear
< gain
[ v
] )
589 *bits
= 0x8000; // Mute
593 *bits
= ( ( 15 - v
) << 8 ) | ( 15 - v
);
601 SamplerateToLinearPitch( ULONG samplingrate
)
603 samplingrate
= (samplingrate
<< 8) / 375;
604 return (samplingrate
>> 1) + (samplingrate
& 1);
609 #define GFXMEM_BUFFER (64 * 1024) // 64KB should be enough for everyone...
611 void *pci_alloc_consistent(size_t size
, APTR
*NonAlignedAddress
, unsigned int boundary
)
616 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
618 address
= (void *) AllocVec(size
+ boundary
, MEMF_PUBLIC
| MEMF_CLEAR
);
622 a
= (unsigned long) address
;
623 a
= (a
+ boundary
- 1) & ~(boundary
- 1);
624 address
= (void *) a
;
627 if (NonAlignedAddress
)
629 *NonAlignedAddress
= address
;
636 void pci_free_consistent(void* addr
)
638 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
643 #if !defined(__AROS__)
644 static ULONG
ResetHandler(struct ExceptionContext
*ctx
, struct ExecBase
*pExecBase
, struct CMI8738_DATA
*card
)
646 struct PCIDevice
*dev
= card
->pci_dev
;
648 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
650 ClearMask(dev
, card
, CMPCI_REG_INTR_CTRL
, CMPCI_REG_CH0_INTR_ENABLE
);
651 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_ENABLE
);
656 void AddResetHandler(struct CMI8738_DATA
*card
)
658 static struct Interrupt interrupt
;
660 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__
);
662 interrupt
.is_Code
= (void (*)())ResetHandler
;
663 interrupt
.is_Data
= (APTR
) card
;
664 interrupt
.is_Node
.ln_Pri
= 0;
665 interrupt
.is_Node
.ln_Type
= NT_EXTINTERRUPT
;
666 interrupt
.is_Node
.ln_Name
= "CMI8738 Reset Handler";
668 AddResetCallback( &interrupt
);