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 <proto/expansion.h>
19 #include <libraries/openpci.h>
20 #include <proto/openpci.h>
23 #include <proto/exec.h>
24 #include <proto/dos.h>
25 #include <proto/fakedma.h>
28 #include "library_card.h"
30 #include "interrupt.h"
32 #include "DriverData.h"
34 #define CACHELINE_SIZE 32
36 /* Global in Card.c */
37 extern const UWORD InputBits
[];
38 extern struct DOSIFace
*IDOS
;
39 extern struct FakeDMAIFace
*IFakeDMA
;
41 /* Public functions in main.c */
42 int card_init(struct CardData
*card
);
43 void card_cleanup(struct CardData
*card
);
44 void AddResetHandler(struct CardData
*card
);
47 void WritePartialMask(struct PCIDevice
*dev
, struct CardData
* card
, unsigned long reg
, unsigned long shift
, unsigned long mask
, unsigned long val
)
51 tmp
= dev
->InLong(card
->iobase
+ reg
);
52 tmp
&= ~(mask
<< shift
);
54 dev
->OutLong(card
->iobase
+ reg
, tmp
);
58 void ClearMask(struct PCIDevice
*dev
, struct CardData
* card
, unsigned long reg
, unsigned long mask
)
62 tmp
= dev
->InLong(card
->iobase
+ reg
);
64 dev
->OutLong(card
->iobase
+ reg
, tmp
);
68 void WriteMask(struct PCIDevice
*dev
, struct CardData
* card
, unsigned long reg
, unsigned long mask
)
72 tmp
= dev
->InLong(card
->iobase
+ reg
);
74 dev
->OutLong(card
->iobase
+ reg
, tmp
);
77 void cmimix_wr(struct PCIDevice
*dev
, struct CardData
* card
, unsigned char port
, unsigned char val
)
79 dev
->OutByte(card
->iobase
+ CMPCI_REG_SBADDR
, port
);
80 dev
->OutByte(card
->iobase
+ CMPCI_REG_SBDATA
, val
);
83 unsigned char cmimix_rd(struct PCIDevice
*dev
, struct CardData
* card
, unsigned char port
)
85 dev
->OutByte(card
->iobase
+ CMPCI_REG_SBADDR
, port
);
86 return (unsigned char) dev
->InByte(card
->iobase
+ CMPCI_REG_SBDATA
);
90 /******************************************************************************
91 ** DriverData allocation ******************************************************
92 ******************************************************************************/
94 // This code used to be in _AHIsub_AllocAudio(), but since we're now
95 // handling CAMD support too, it needs to be done at driver loading
99 AllocDriverData( struct PCIDevice
*dev
,
100 struct DriverBase
* AHIsubBase
)
102 struct CardBase
* CardBase
= (struct CardBase
*) AHIsubBase
;
103 struct CardData
* card
;
108 // FIXME: This should be non-cachable, DMA-able memory
109 card
= IExec
->AllocVec( sizeof( *card
), MEMF_PUBLIC
| MEMF_CLEAR
);
113 Req( "Unable to allocate driver structure." );
117 card
->ahisubbase
= AHIsubBase
;
119 card
->interrupt
.is_Node
.ln_Type
= NT_EXTINTERRUPT
;
120 card
->interrupt
.is_Node
.ln_Pri
= 0;
121 card
->interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
122 card
->interrupt
.is_Code
= (void(*)(void)) CardInterrupt
;
123 card
->interrupt
.is_Data
= (APTR
) card
;
125 card
->playback_interrupt
.is_Node
.ln_Type
= NT_EXTINTERRUPT
;
126 card
->playback_interrupt
.is_Node
.ln_Pri
= 0;
127 card
->playback_interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
128 card
->playback_interrupt
.is_Code
= PlaybackInterrupt
;
129 card
->playback_interrupt
.is_Data
= (APTR
) card
;
131 card
->record_interrupt
.is_Node
.ln_Type
= NT_EXTINTERRUPT
;
132 card
->record_interrupt
.is_Node
.ln_Pri
= 0;
133 card
->record_interrupt
.is_Node
.ln_Name
= (STRPTR
) LibName
;
134 card
->record_interrupt
.is_Code
= RecordInterrupt
;
135 card
->record_interrupt
.is_Data
= (APTR
) card
;
139 command_word
= dev
->ReadConfigWord( PCI_COMMAND
);
140 command_word
|= PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
;
141 dev
->WriteConfigWord( PCI_COMMAND
, command_word
);
143 card
->pci_master_enabled
= TRUE
;
145 /*for (i = 0; i < 6; i++)
147 if (dev->GetResourceRange(i))
148 IExec->DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress);
151 card
->iobase
= dev
->GetResourceRange(0)->BaseAddress
;
152 card
->length
= ~( dev
->GetResourceRange(0)->Size
& PCI_BASE_ADDRESS_IO_MASK
);
153 card
->irq
= dev
->MapInterrupt();
154 card
->chiprev
= dev
->ReadConfigByte( PCI_REVISION_ID
);
155 card
->model
= dev
->ReadConfigWord( PCI_SUBSYSTEM_ID
);
157 /*IExec->DebugPrintF("---> chiprev = %u, model = %x, Vendor = %x\n", dev->ReadConfigByte( PCI_REVISION_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_ID),
158 dev->ReadConfigWord( PCI_SUBSYSTEM_VENDOR_ID));*/
161 /* Initialize chip */
162 if( card_init( card
) < 0 )
164 IExec
->DebugPrintF("Unable to initialize Card subsystem.");
169 //IExec->DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt());
170 IExec
->AddIntServer(dev
->MapInterrupt(), &card
->interrupt
);
171 card
->interrupt_added
= TRUE
;
174 card
->card_initialized
= TRUE
;
177 card
->monitor_volume
= Linear2MixerGain( 0, &card
->monitor_volume_bits
);
178 card
->input_gain
= Linear2RecordGain( 0x10000, &card
->input_gain_bits
);
179 card
->output_volume
= Linear2MixerGain( 0x10000, &card
->output_volume_bits
);
180 SaveMixerState(card
);
182 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_RESET
, 0);
183 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_ADCMIX_L
, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line
184 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_ADCMIX_R
, 0); //CMPCI_SB16_MIXER_LINE_SRC_R);
186 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_OUTMIX
, 0); // set output mute off for line and CD
188 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_VOICE_L
, 0xFF); // PCM
189 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_VOICE_R
, 0xFF);
191 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_CDDA_L
, 0x00);
192 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_CDDA_R
, 0x00);
194 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_LINE_L
, 0x00);
195 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_LINE_R
, 0x00);
197 byte
= dev
->InByte(card
->iobase
+ CMPCI_REG_MIXER25
);
198 dev
->OutByte(card
->iobase
+ CMPCI_REG_MIXER25
, byte
& ~0x30); // mute Aux
199 dev
->OutByte(card
->iobase
+ CMPCI_REG_MIXER25
, byte
& ~0x01); // turn on mic 20dB boost
200 dev
->OutByte(card
->iobase
+ CMPCI_REG_MIXER_AUX
, 0x00);
202 byte
= dev
->InByte(card
->iobase
+ CMPCI_REG_MIXER24
);
203 dev
->OutByte(card
->iobase
+ CMPCI_REG_MIXER24
, byte
| CMPCI_REG_FMMUTE
);
205 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MIC
, 0x00);
207 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MASTER_L
, 0xFF);
208 cmimix_wr(dev
, card
, CMPCI_SB16_MIXER_MASTER_R
, 0xFF);
210 card
->mixerstate
= cmimix_rd(dev
, card
, CMPCI_SB16_MIXER_OUTMIX
);
212 AddResetHandler(card
);
218 /******************************************************************************
219 ** DriverData deallocation ****************************************************
220 ******************************************************************************/
222 // And this code used to be in _AHIsub_FreeAudio().
225 FreeDriverData( struct CardData
* card
,
226 struct DriverBase
* AHIsubBase
)
230 if( card
->pci_dev
!= NULL
)
232 if( card
->card_initialized
)
234 card_cleanup( card
);
237 if( card
->pci_master_enabled
)
241 cmd
= ((struct PCIDevice
* ) card
->pci_dev
)->ReadConfigWord( PCI_COMMAND
);
242 cmd
&= ~( PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
);
243 ((struct PCIDevice
* ) card
->pci_dev
)->WriteConfigWord( PCI_COMMAND
, cmd
);
247 if( card
->interrupt_added
)
249 IExec
->RemIntServer(((struct PCIDevice
* ) card
->pci_dev
)->MapInterrupt(), &card
->interrupt
);
252 IExec
->FreeVec( card
);
257 int card_init(struct CardData
*card
)
259 struct PCIDevice
*dev
= (struct PCIDevice
*) card
->pci_dev
;
263 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_POWER_DOWN
); // power up
265 WriteMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_BUS_AND_DSP_RESET
);
267 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_BUS_AND_DSP_RESET
);
270 WriteMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_RESET
| CMPCI_REG_CH1_RESET
);
272 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_RESET
| CMPCI_REG_CH1_RESET
);
274 /* Disable interrupts and channels */
275 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
,CMPCI_REG_CH0_ENABLE
| CMPCI_REG_CH1_ENABLE
);
276 ClearMask(dev
, card
, CMPCI_REG_INTR_CTRL
, CMPCI_REG_CH0_INTR_ENABLE
| CMPCI_REG_CH1_INTR_ENABLE
);
278 /* Configure DMA channels, ch0 = play, ch1 = capture */
279 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_DIR
);
280 WriteMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH1_DIR
);
283 ClearMask(dev
, card
, CMPCI_REG_FUNC_1
, CMPCI_REG_SPDIFOUT_DAC
| CMPCI_REG_SPDIF0_ENABLE
);
284 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, CMPCI_REG_LEGACY_SPDIF_ENABLE
);
286 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, 0x80000000);
287 ClearMask(dev
, card
, CMPCI_REG_CHANNEL_FORMAT
, CM_CHB3D
);
288 ClearMask(dev
, card
, CMPCI_REG_CHANNEL_FORMAT
, CM_CHB3D5C
);
289 ClearMask(dev
, card
, CMPCI_REG_LEGACY_CTRL
, CMPCI_REG_ENABLE_5_1
);
290 ClearMask(dev
, card
, CMPCI_REG_MISC
, 0x100);
291 ClearMask(dev
, card
, CMPCI_REG_MISC
, CMPCI_REG_N4SPK3D
);
292 WriteMask(dev
, card
, CMPCI_REG_INTR_STATUS
, CMPCI_REG_LEGACY_STEREO
| CMPCI_REG_LEGACY_HDMA
);
298 void card_cleanup(struct CardData
*card
)
304 /******************************************************************************
305 ** Misc. **********************************************************************
306 ******************************************************************************/
309 SaveMixerState( struct CardData
* card
)
312 card
->ac97_mic
= codec_read( card
, AC97_MIC_VOL
);
313 card
->ac97_cd
= codec_read( card
, AC97_CD_VOL
);
314 card
->ac97_video
= codec_read( card
, AC97_VIDEO_VOL
);
315 card
->ac97_aux
= codec_read( card
, AC97_AUX_VOL
);
316 card
->ac97_linein
= codec_read( card
, AC97_LINEIN_VOL
);
317 card
->ac97_phone
= codec_read( card
, AC97_PHONE_VOL
);
323 RestoreMixerState( struct CardData
* card
)
326 codec_write(card
, AC97_MIC_VOL
, card
->ac97_mic
);
327 codec_write(card
, AC97_CD_VOL
, card
->ac97_cd
);
328 codec_write(card
, AC97_VIDEO_VOL
, card
->ac97_video
);
329 codec_write(card
, AC97_AUX_VOL
, card
->ac97_aux
);
330 codec_write(card
, AC97_LINEIN_VOL
, card
->ac97_linein
);
331 codec_write(card
, AC97_PHONE_VOL
, card
->ac97_phone
);
336 UpdateMonitorMixer( struct CardData
* card
)
339 int i
= InputBits
[ card
->input
];
340 UWORD m
= card
->monitor_volume_bits
& 0x801f;
341 UWORD s
= card
->monitor_volume_bits
;
342 UWORD mm
= AC97_MUTE
| 0x0008;
343 UWORD sm
= AC97_MUTE
| 0x0808;
345 if( i
== AC97_RECMUX_STEREO_MIX
||
346 i
== AC97_RECMUX_MONO_MIX
)
348 // Use the original mixer settings
349 RestoreMixerState( card
);
353 codec_write(card
, AC97_MIC_VOL
,
354 i
== AC97_RECMUX_MIC
? m
: mm
);
356 codec_write(card
, AC97_CD_VOL
,
357 i
== AC97_RECMUX_CD
? s
: sm
);
359 codec_write(card
, AC97_VIDEO_VOL
,
360 i
== AC97_RECMUX_VIDEO
? s
: sm
);
362 codec_write(card
, AC97_AUX_VOL
,
363 i
== AC97_RECMUX_AUX
? s
: sm
);
365 codec_write(card
, AC97_LINEIN_VOL
,
366 i
== AC97_RECMUX_LINE
? s
: sm
);
368 codec_write(card
, AC97_PHONE_VOL
,
369 i
== AC97_RECMUX_PHONE
? m
: mm
);
376 Linear2MixerGain( Fixed linear
,
379 static const Fixed gain
[ 33 ] =
418 while( linear
< gain
[ v
] )
425 *bits
= 0x8000; // Mute
429 *bits
= ( v
<< 8 ) | v
;
432 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
437 Linear2RecordGain( Fixed linear
,
440 static const Fixed gain
[ 17 ] =
463 while( linear
< gain
[ v
] )
470 *bits
= 0x8000; // Mute
474 *bits
= ( ( 15 - v
) << 8 ) | ( 15 - v
);
482 SamplerateToLinearPitch( ULONG samplingrate
)
484 samplingrate
= (samplingrate
<< 8) / 375;
485 return (samplingrate
>> 1) + (samplingrate
& 1);
490 #define GFXMEM_BUFFER (64 * 1024) // 64KB should be enough for everyone...
492 void *pci_alloc_consistent(size_t size
, APTR
*NonAlignedAddress
)
499 if (size
> GFXMEM_BUFFER
)
501 IExec
->DebugPrintF("Error allocating memory! Asking %ld bytes\n", size
);
506 DMAheader
= IFakeDMA
->AllocDMABuffer(GFXMEM_BUFFER
); // alloc once
511 APTR bufStart
= IFakeDMA
->GetDMABufferAttr(DMAheader
, DMAB_PUDDLE
);
512 ULONG bufSize
= (ULONG
)IFakeDMA
->GetDMABufferAttr(DMAheader
, DMAB_SIZE
);
515 *NonAlignedAddress
= address
;
517 a
= (unsigned long) address
;
518 a
= (a
+ CACHELINE_SIZE
- 1) & ~(CACHELINE_SIZE
- 1);
519 address
= (void *) a
;
525 IExec
->DebugPrintF("No gfx mem\n");
526 if (IExec
->OpenResource("newmemory.resource"))
528 address
= IExec
->AllocVecTags(size
, AVT_Type
, MEMF_SHARED
, AVT_Contiguous
, TRUE
, AVT_Lock
, TRUE
,
529 AVT_PhysicalAlignment
, 32, AVT_Clear
, 0, TAG_DONE
);
533 address
= IExec
->AllocVec( size
+ CACHELINE_SIZE
, MEMF_PUBLIC
| MEMF_CLEAR
);
535 if( address
!= NULL
)
537 a
= (unsigned long) address
;
538 a
= (a
+ CACHELINE_SIZE
- 1) & ~(CACHELINE_SIZE
- 1);
539 address
= (void *) a
;
543 *NonAlignedAddress
= address
;
549 void pci_free_consistent(void* addr
)
556 IExec
->FreeVec( addr
);
560 static ULONG
ResetHandler(struct ExceptionContext
*ctx
, struct ExecBase
*pExecBase
, struct CardData
*card
)
562 struct PCIDevice
*dev
= card
->pci_dev
;
564 ClearMask(dev
, card
, CMPCI_REG_INTR_CTRL
, CMPCI_REG_CH0_INTR_ENABLE
);
565 ClearMask(dev
, card
, CMPCI_REG_FUNC_0
, CMPCI_REG_CH0_ENABLE
);
571 void AddResetHandler(struct CardData
*card
)
573 static struct Interrupt interrupt
;
575 interrupt
.is_Code
= (void (*)())ResetHandler
;
576 interrupt
.is_Data
= (APTR
) card
;
577 interrupt
.is_Node
.ln_Pri
= 0;
578 interrupt
.is_Node
.ln_Type
= NT_EXTINTERRUPT
;
579 interrupt
.is_Node
.ln_Name
= "reset handler";
581 IExec
->AddResetCallback( &interrupt
);