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>
17 #include <aros/debug.h>
20 #include <proto/exec.h>
21 #include <proto/dos.h>
27 #include "interrupt.h"
30 #include "pci_wrapper.h"
32 #define CACHELINE_SIZE 32
35 #define DebugPrintF bug
36 INTGW(static, void, playbackinterrupt
, PlaybackInterrupt
);
37 INTGW(static, void, recordinterrupt
, RecordInterrupt
);
38 INTGW(static, ULONG
, cardinterrupt
, CardInterrupt
);
41 /* Global in Card.c */
42 extern const UWORD InputBits
[];
44 /* Public functions in main.c */
45 int card_init(struct CMI8738_DATA
*card
);
46 void card_cleanup(struct CMI8738_DATA
*card
);
47 #if !defined(__AROS__)
48 void AddResetHandler(struct CMI8738_DATA
*card
);
51 void WritePartialMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long shift
, unsigned long mask
, unsigned long val
)
55 tmp
= pci_inl(reg
, card
);
56 tmp
&= ~(mask
<< shift
);
58 pci_outl(tmp
, reg
, card
);
62 void ClearMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long mask
)
66 tmp
= pci_inl(reg
, card
);
68 pci_outl(tmp
, reg
, card
);
72 void WriteMask(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned long reg
, unsigned long mask
)
76 tmp
= pci_inl(reg
, card
);
78 pci_outl(tmp
, reg
, card
);
81 void cmimix_wr(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned char port
, unsigned char val
)
83 pci_outb(port
, CMPCI_REG_SBADDR
, card
);
84 pci_outb(val
, CMPCI_REG_SBDATA
, card
);
87 unsigned char cmimix_rd(struct PCIDevice
*dev
, struct CMI8738_DATA
* card
, unsigned char port
)
89 pci_outb(port
, CMPCI_REG_SBADDR
, card
);
90 return (unsigned char) pci_inb(CMPCI_REG_SBDATA
, card
);
94 /******************************************************************************
95 ** DriverData allocation ******************************************************
96 ******************************************************************************/
98 // This code used to be in _AHIsub_AllocAudio(), but since we're now
99 // handling CAMD support too, it needs to be done at driver loading
103 AllocDriverData( struct PCIDevice
*dev
,
104 struct DriverBase
* AHIsubBase
)
106 struct CMI8738Base
* CMI8738Base
= (struct CMI8738Base
*) AHIsubBase
;
107 struct CMI8738_DATA
* card
;
112 // FIXME: This should be non-cachable, DMA-able memory
113 card
= AllocVec( sizeof( *card
), MEMF_PUBLIC
| MEMF_CLEAR
);
117 Req( "Unable to allocate driver structure." );
121 card
->ahisubbase
= AHIsubBase
;
123 card
->interrupt
.is_Node
.ln_Type
= IRQTYPE
;
124 card
->interrupt
.is_Node
.ln_Pri
= 0;
125 card
->interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
127 card
->interrupt
.is_Code
= (void(*)(void)) &cardinterrupt
;
129 card
->interrupt
.is_Code
= (void(*)(void)) CardInterrupt
;
131 card
->interrupt
.is_Data
= (APTR
) card
;
133 card
->playback_interrupt
.is_Node
.ln_Type
= IRQTYPE
;
134 card
->playback_interrupt
.is_Node
.ln_Pri
= 0;
135 card
->playback_interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
137 card
->playback_interrupt
.is_Code
= &playbackinterrupt
;
139 card
->interrupt
.is_Code
= PlaybackInterrupt
;
141 card
->playback_interrupt
.is_Data
= (APTR
) card
;
143 card
->record_interrupt
.is_Node
.ln_Type
= IRQTYPE
;
144 card
->record_interrupt
.is_Node
.ln_Pri
= 0;
145 card
->record_interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
147 card
->record_interrupt
.is_Code
= &recordinterrupt
;
149 card
->interrupt
.is_Code
= RecordInterrupt
;
151 card
->record_interrupt
.is_Data
= (APTR
) card
;
155 command_word
= inw_config(PCI_COMMAND
, dev
);
156 command_word
|= PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
;
157 outw_config( PCI_COMMAND
, command_word
, dev
);
159 card
->pci_master_enabled
= TRUE
;
161 /*for (i = 0; i < 6; i++)
163 if (dev->GetResourceRange(i))
164 DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress);
167 card
->iobase
= ahi_pci_get_base_address(0, dev
);
168 card
->length
= ahi_pci_get_base_size(0, dev
);
169 card
->irq
= ahi_pci_get_irq(dev
);
170 card
->chiprev
= inb_config(PCI_REVISION_ID
, dev
);
171 card
->model
= inw_config(PCI_SUBSYSTEM_ID
, dev
);
173 /*DebugPrintF("---> chiprev = %u, model = %x, Vendor = %x\n", dev->ReadConfigByte( PCI_REVISION_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_ID),
174 dev->ReadConfigWord( PCI_SUBSYSTEM_VENDOR_ID));*/
177 /* Initialize chip */
178 if( card_init( card
) < 0 )
180 DebugPrintF("Unable to initialize Card subsystem.");
184 //DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt());
185 ahi_pci_add_intserver(&card
->interrupt
, dev
);
186 card
->interrupt_added
= TRUE
;
188 card
->card_initialized
= TRUE
;
191 card
->monitor_volume
= Linear2MixerGain( 0, &card
->monitor_volume_bits
);
192 card
->input_gain
= Linear2RecordGain( 0x10000, &card
->input_gain_bits
);
193 card
->output_volume
= Linear2MixerGain( 0x10000, &card
->output_volume_bits
);
194 SaveMixerState(card
);
196 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_RESET
, 0);
197 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_ADCMIX_L
, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line
198 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_ADCMIX_R
, 0); //CMPCI_SB16_MIXER_LINE_SRC_R);
200 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_OUTMIX
, 0); // set output mute off for line and CD
202 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_VOICE_L
, 0xFF); // PCM
203 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_VOICE_R
, 0xFF);
205 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_CDDA_L
, 0x00);
206 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_CDDA_R
, 0x00);
208 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_LINE_L
, 0x00);
209 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_LINE_R
, 0x00);
211 byte
= pci_inb(CMPCI_REG_MIXER25
, card
);
212 pci_outb(byte
& ~0x30, CMPCI_REG_MIXER25
, card
); // mute Aux
213 pci_outb(byte
& ~0x01, CMPCI_REG_MIXER25
, card
); // turn on mic 20dB boost
214 pci_outb(0x00, CMPCI_REG_MIXER_AUX
, card
);
216 byte
= pci_inb(CMPCI_REG_MIXER24
, card
);
217 pci_outb(byte
| CMPCI_REG_FMMUTE
, CMPCI_REG_MIXER24
, card
);
219 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MIC
, 0x00);
221 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MASTER_L
, 0xFF);
222 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MASTER_R
, 0xFF);
224 card
->mixerstate
= cmimix_rd(dev
, card
, CMPCI_SB16_MIXER_OUTMIX
);
226 #if !defined(__AROS__)
227 AddResetHandler(card
);
234 /******************************************************************************
235 ** DriverData deallocation ****************************************************
236 ******************************************************************************/
238 // And this code used to be in _AHIsub_FreeAudio().
241 FreeDriverData( struct CMI8738_DATA
* card
,
242 struct DriverBase
* AHIsubBase
)
246 if( card
->pci_dev
!= NULL
)
248 if( card
->card_initialized
)
250 card_cleanup( card
);
253 if( card
->pci_master_enabled
)
257 cmd
= inw_config(PCI_COMMAND
, (struct PCIDevice
* ) card
->pci_dev
);
258 cmd
&= ~( PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
);
259 outw_config(PCI_COMMAND
, cmd
, (struct PCIDevice
* ) card
->pci_dev
);
263 if( card
->interrupt_added
)
265 ahi_pci_rem_intserver(&card
->interrupt
, card
->pci_dev
);
273 int card_init(struct CMI8738_DATA
*card
)
275 struct PCIDevice
*dev
= (struct PCIDevice
*) card
->pci_dev
;
279 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_POWER_DOWN
); // power up
281 WriteMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_BUS_AND_DSP_RESET
);
283 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_BUS_AND_DSP_RESET
);
286 WriteMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_RESET
| CMPCI_REG_CH1_RESET
);
288 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_RESET
| CMPCI_REG_CH1_RESET
);
290 /* Disable interrupts and channels */
291 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
,CMPCI_REG_CH0_ENABLE
| CMPCI_REG_CH1_ENABLE
);
292 ClearMask(dev
, card
, CMPCI_REG_INTR_CTRL
, CMPCI_REG_CH0_INTR_ENABLE
| CMPCI_REG_CH1_INTR_ENABLE
);
294 /* Configure DMA channels, ch0 = play, ch1 = capture */
295 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_DIR
);
296 WriteMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH1_DIR
);
299 ClearMask(dev
, card
, CMPCI_REG_FUNC_1
, CMPCI_REG_SPDIFOUT_DAC
| CMPCI_REG_SPDIF0_ENABLE
);
300 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, CMPCI_REG_LEGACY_SPDIF_ENABLE
);
302 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, 0x80000000);
303 ClearMask(dev
, card
, CMPCI_REG_CHANNEL_FORMAT
, CM_CHB3D
);
304 ClearMask(dev
, card
, CMPCI_REG_CHANNEL_FORMAT
, CM_CHB3D5C
);
305 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, CMPCI_REG_ENABLE_5_1
);
306 ClearMask(dev
, card
, CMPCI_REG_MISC
, 0x100);
307 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_N4SPK3D
);
308 WriteMask(dev
, card
, CMPCI_REG_INTR_STATUS
, CMPCI_REG_LEGACY_STEREO
| CMPCI_REG_LEGACY_HDMA
);
314 void card_cleanup(struct CMI8738_DATA
*card
)
320 /******************************************************************************
321 ** Misc. **********************************************************************
322 ******************************************************************************/
325 SaveMixerState( struct CMI8738_DATA
* card
)
328 card
->ac97_mic
= codec_read( card
, AC97_MIC_VOL
);
329 card
->ac97_cd
= codec_read( card
, AC97_CD_VOL
);
330 card
->ac97_video
= codec_read( card
, AC97_VIDEO_VOL
);
331 card
->ac97_aux
= codec_read( card
, AC97_AUX_VOL
);
332 card
->ac97_linein
= codec_read( card
, AC97_LINEIN_VOL
);
333 card
->ac97_phone
= codec_read( card
, AC97_PHONE_VOL
);
339 RestoreMixerState( struct CMI8738_DATA
* card
)
342 codec_write(card
, AC97_MIC_VOL
, card
->ac97_mic
);
343 codec_write(card
, AC97_CD_VOL
, card
->ac97_cd
);
344 codec_write(card
, AC97_VIDEO_VOL
, card
->ac97_video
);
345 codec_write(card
, AC97_AUX_VOL
, card
->ac97_aux
);
346 codec_write(card
, AC97_LINEIN_VOL
, card
->ac97_linein
);
347 codec_write(card
, AC97_PHONE_VOL
, card
->ac97_phone
);
352 UpdateMonitorMixer( struct CMI8738_DATA
* card
)
355 int i
= InputBits
[ card
->input
];
356 UWORD m
= card
->monitor_volume_bits
& 0x801f;
357 UWORD s
= card
->monitor_volume_bits
;
358 UWORD mm
= AC97_MUTE
| 0x0008;
359 UWORD sm
= AC97_MUTE
| 0x0808;
361 if( i
== AC97_RECMUX_STEREO_MIX
||
362 i
== AC97_RECMUX_MONO_MIX
)
364 // Use the original mixer settings
365 RestoreMixerState( card
);
369 codec_write(card
, AC97_MIC_VOL
,
370 i
== AC97_RECMUX_MIC
? m
: mm
);
372 codec_write(card
, AC97_CD_VOL
,
373 i
== AC97_RECMUX_CD
? s
: sm
);
375 codec_write(card
, AC97_VIDEO_VOL
,
376 i
== AC97_RECMUX_VIDEO
? s
: sm
);
378 codec_write(card
, AC97_AUX_VOL
,
379 i
== AC97_RECMUX_AUX
? s
: sm
);
381 codec_write(card
, AC97_LINEIN_VOL
,
382 i
== AC97_RECMUX_LINE
? s
: sm
);
384 codec_write(card
, AC97_PHONE_VOL
,
385 i
== AC97_RECMUX_PHONE
? m
: mm
);
392 Linear2MixerGain( Fixed linear
,
395 static const Fixed gain
[ 33 ] =
434 while( linear
< gain
[ v
] )
441 *bits
= 0x8000; // Mute
445 *bits
= ( v
<< 8 ) | v
;
448 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
453 Linear2RecordGain( Fixed linear
,
456 static const Fixed gain
[ 17 ] =
479 while( linear
< gain
[ v
] )
486 *bits
= 0x8000; // Mute
490 *bits
= ( ( 15 - v
) << 8 ) | ( 15 - v
);
498 SamplerateToLinearPitch( ULONG samplingrate
)
500 samplingrate
= (samplingrate
<< 8) / 375;
501 return (samplingrate
>> 1) + (samplingrate
& 1);
506 #define GFXMEM_BUFFER (64 * 1024) // 64KB should be enough for everyone...
508 void *pci_alloc_consistent(size_t size
, APTR
*NonAlignedAddress
, unsigned int boundary
)
513 address
= (void *) AllocVec(size
+ boundary
, MEMF_PUBLIC
| MEMF_CLEAR
);
517 a
= (unsigned long) address
;
518 a
= (a
+ boundary
- 1) & ~(boundary
- 1);
519 address
= (void *) a
;
522 if (NonAlignedAddress
)
524 *NonAlignedAddress
= address
;
531 void pci_free_consistent(void* addr
)
536 static ULONG
ResetHandler(struct ExceptionContext
*ctx
, struct ExecBase
*pExecBase
, struct CMI8738_DATA
*card
)
538 struct PCIDevice
*dev
= card
->pci_dev
;
540 ClearMask(dev
, card
, CMPCI_REG_INTR_CTRL
, CMPCI_REG_CH0_INTR_ENABLE
);
541 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_ENABLE
);
546 #if !defined(__AROS__)
547 void AddResetHandler(struct CMI8738_DATA
*card
)
549 static struct Interrupt interrupt
;
551 interrupt
.is_Code
= (void (*)())ResetHandler
;
552 interrupt
.is_Data
= (APTR
) card
;
553 interrupt
.is_Node
.ln_Pri
= 0;
554 interrupt
.is_Node
.ln_Type
= IRQTYPE
;
555 interrupt
.is_Node
.ln_Name
= "reset handler";
557 AddResetCallback( &interrupt
);