2 Copyright (c) 2006-2007 dogbert <dogber1@gmail.com>
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #pragma code_seg("PAGE") /* warning - ignored by GCC compiler */
38 PUNKNOWN UnknownOuter
,
43 DBGPRINT(("NewCMIAdapter()"));
46 STD_CREATE_BODY_(CCMIAdapter
, Unknown
, UnknownOuter
, PoolType
, PCMIADAPTER
);
50 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::init(PRESOURCELIST ResourceList
, PDEVICE_OBJECT aDeviceObject
)
54 //ASSERT(ResourceList);
55 //ASSERT(aDeviceObject);
56 //ASSERT(ResourceList->FindTranslatedPort(0));
57 DBGPRINT(("CCMIAdapter[%p]::init()", this));
60 NTSTATUS ntStatus
= STATUS_SUCCESS
;
62 RtlFillMemory(&mixerCache
, 0xFF, 0xFF);
63 RtlFillMemory(&cm
, sizeof(cm
), 0x00);
65 DeviceObject
= aDeviceObject
;
68 for ( UINT i
=0; i
< ResourceList
->NumberOfPorts(); i
++ ) {
69 if (ResourceList
->FindTranslatedPort(i
)->u
.Port
.Length
== 0x100) {
70 cm
.IOBase
= (UInt32
*)ResourceList
->FindTranslatedPort(i
)->u
.Port
.Start
.QuadPart
;
75 return STATUS_INSUFFICIENT_RESOURCES
;
80 INFOPRINT(("Driver Version: %s-WAVERT", CMIVERSION
));
82 INFOPRINT(("Driver Version: %s", CMIVERSION
));
84 INFOPRINT(("Configuration:"));
85 INFOPRINT((" IO Base: 0x%X", cm
.IOBase
));
86 INFOPRINT((" MPU Base: 0x%X", cm
.MPUBase
));
89 return STATUS_INSUFFICIENT_RESOURCES
;
92 INFOPRINT((" Chip Version: %d", cm
.chipVersion
));
93 INFOPRINT((" Max Channels: %d", cm
.maxChannels
));
94 INFOPRINT((" CanAC3HW: %d", cm
.canAC3HW
));
98 ntStatus
= PcNewInterruptSync(&(InterruptSync
), NULL
, ResourceList
, 0, InterruptSyncModeNormal
);
99 if (!NT_SUCCESS(ntStatus
) || !(InterruptSync
)) {
100 DBGPRINT(("Failed to create an interrupt sync!"));
101 return STATUS_INSUFFICIENT_RESOURCES
;
103 ntStatus
= InterruptSync
->RegisterServiceRoutine(InterruptServiceRoutine
, (PVOID
)this, FALSE
);
104 if (!NT_SUCCESS(ntStatus
)) {
105 DBGPRINT(("Failed to register ISR!"));
109 ntStatus
= InterruptSync
->Connect();
110 if (!NT_SUCCESS(ntStatus
)) {
111 DBGPRINT(("Failed to connect the ISR with InterruptSync!"));
115 // Initialize the device state.
116 CurrentPowerState
= PowerDeviceD0
;
122 CCMIAdapter::~CCMIAdapter()
125 DBGPRINT(("CCMIAdapter[%p]::~CCMIAdapter()", this));
128 InterruptSync
->Disconnect();
129 InterruptSync
->Release();
130 InterruptSync
= NULL
;
134 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::QueryInterface(REFIID Interface
, PVOID
* Object
)
138 DBGPRINT(("CCMIAdapter[%p]::NonDelegatingQueryInterface()", this));
142 // Is it IID_IUnknown?
143 if (IsEqualGUIDAligned (Interface
, IID_IUnknown
)) {
144 *Object
= (PVOID
)(PUNKNOWN
)(PCMIADAPTER
)this;
147 // or IID_IAdapterCommon ...
148 if (IsEqualGUIDAligned (Interface
, IID_ICMIAdapter
)) {
149 *Object
= (PVOID
)(PCMIADAPTER
)this;
151 // or IID_IAdapterPowerManagement ...
152 if (IsEqualGUIDAligned (Interface
, IID_IAdapterPowerManagement
)) {
153 *Object
= (PVOID
)(PADAPTERPOWERMANAGEMENT
)this;
155 // nothing found, must be an unknown interface.
157 return STATUS_INVALID_PARAMETER
;
161 // We reference the interface for the caller.
163 ((PUNKNOWN
)*Object
)->AddRef();
164 return STATUS_SUCCESS
;
167 bool CCMIAdapter::queryChip()
170 DBGPRINT(("CCMIAdapter[%p]::queryChip()", this));
172 UInt32 version
= readUInt32(REG_INTHLDCLR
) & VERSION_MASK
;
173 if (version
== 0xFFFFFFFF) {
177 if (version
& VERSION_68
) {
181 cm
.hasDualDAC
= true;
182 cm
.canMultiChannel
= true;
185 if (version
& VERSION_55
) {
189 cm
.hasDualDAC
= true;
190 cm
.canMultiChannel
= true;
193 if (version
& VERSION_39
) {
195 if (version
& VERSION_39_6
) {
201 cm
.hasDualDAC
= true;
202 cm
.canMultiChannel
= true;
206 version
= readUInt32(REG_CHFORMAT
) & VERSION_37
;
215 cm
.hasDualDAC
= true;
228 void CCMIAdapter::resetMixer()
231 DBGPRINT(("CCMIAdapter[%p]::resetMixer()", this));
234 setUInt8Bit(REG_MIXER1
, EN_SPDI2DAC
);
237 void CCMIAdapter::resetController()
241 DBGPRINT(("CCMIAdapter[%p]::resetController()", this));
244 writeUInt32(REG_INTHLDCLR
, 0);
247 writeUInt32(REG_FUNCTRL0
, ADC_CH0
| (RST_CH0
| RST_CH1
));
248 writeUInt32(REG_FUNCTRL0
, ADC_CH0
& ~(RST_CH0
| RST_CH1
));
250 writeUInt32(REG_FUNCTRL0
, ADC_CH1
| (RST_CH0
| RST_CH1
));
251 writeUInt32(REG_FUNCTRL0
, ADC_CH1
& ~(RST_CH0
| RST_CH1
));
253 KeStallExecutionProcessor(100L);
255 writeUInt32(REG_FUNCTRL0
, 0);
256 writeUInt32(REG_FUNCTRL1
, 0);
258 writeUInt32(REG_CHFORMAT
, 0);
259 writeUInt32(REG_MISCCTRL
, EN_DBLDAC
);
261 setUInt32Bit(REG_MISCCTRL
, XCHG_DAC
);
264 setUInt32Bit(REG_FUNCTRL1
, BREQ
);
272 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::activateMPU(ULONG
* MPUBase
)
277 DBGPRINT(("CCMIAdapter[%p]::activateMPU(%X)", this, MPUBase
));
280 switch ((LONGLONG
)MPUBase
) {
281 case 0x300: LegacyCtrl
= UART_300
; break;
282 case 0x310: LegacyCtrl
= UART_310
; break;
283 case 0x320: LegacyCtrl
= UART_320
; break;
284 case 0x330: LegacyCtrl
= UART_330
; break; // UART_330 == 0
285 default: LegacyCtrl
= 0xFFFFFFFF; break;
287 if (LegacyCtrl
< 0xFFFFFFFF) {
288 cm
.MPUBase
= MPUBase
;
289 setUInt32Bit(REG_FUNCTRL1
, EN_UART
);
290 writeUInt32(REG_LEGACY
, LegacyCtrl
);
291 return STATUS_SUCCESS
;
294 return STATUS_UNSUCCESSFUL
;
297 // "The code for this method must reside in paged memory.", IID_IAdapterPowerManagement.PowerChangeState() docs
298 // XP's order of power states when going to hibernate: D3 -> D0, waking up: D0 -> D3.
299 STDMETHODIMP_(void) CCMIAdapter::PowerChangeState(POWER_STATE NewState
)
303 DBGPRINT(("CCMIAdapter[%p]::PowerChangeState(%p)", this, NewState
));
306 if (NewState
.DeviceState
== CurrentPowerState
) {
310 switch (NewState
.DeviceState
) {
311 case PowerDeviceD0
: // powering up, hardware access allowed
312 clearUInt32Bit(REG_MISCCTRL
, PWD_CHIP
);
313 cm
.WaveMiniport
->powerUp();
314 CurrentPowerState
= NewState
.DeviceState
;
317 case PowerDeviceD1
: // powering down, hardware access still allowed
318 setUInt32Bit(REG_MISCCTRL
, PWD_CHIP
);
319 CurrentPowerState
= NewState
.DeviceState
;
322 case PowerDeviceD2
: // sleep state - hardware access not allowed
323 case PowerDeviceD3
: // hibernation state - hardware access not allowed
324 if (CurrentPowerState
== PowerDeviceD0
) {
325 cm
.WaveMiniport
->powerDown();
326 setUInt32Bit(REG_MISCCTRL
, PWD_CHIP
);
328 CurrentPowerState
= NewState
.DeviceState
;
330 default: // unknown power state
335 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::QueryPowerChangeState(POWER_STATE NewStateQuery
)
339 DBGPRINT(("CCMIAdapter[%p]::QueryPowerChangeState(%p)", this, NewStateQuery
));
341 return STATUS_SUCCESS
;
344 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::QueryDeviceCapabilities(PDEVICE_CAPABILITIES PowerDeviceCaps
)
348 DBGPRINT(("CCMIAdapter[%p]::QueryDeviceCapabilities(%p)", this, PowerDeviceCaps
));
350 return STATUS_SUCCESS
;
353 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::loadSBMixerFromMemory()
355 UInt8 sbIndex
[] = { 0x04, 0x0A, 0x22, 0x28, 0x2E, 0x30, 0x31, 0x32, 0x33, 0x36, 0x37, 0x38,
356 0x39, 0x3A, 0x3C, 0x3D, 0x3E, 0xF0 };
360 DBGPRINT(("CCMIAdapter[%p]::loadSBMixerFromMemory()", this));
362 for ( UINT i
= 0; i
< (sizeof(sbIndex
)/sizeof(sbIndex
[0])); i
++ ) {
363 writeUInt8(REG_SBINDEX
, sbIndex
[i
]);
364 writeUInt8(REG_SBDATA
, mixerCache
[i
]);
367 return STATUS_SUCCESS
;
371 ** non-paged code below
374 #pragma code_seg() /* warning - ignored by GCC compiler */
377 STDMETHODIMP_(UInt8
) CCMIAdapter::readUInt8(UInt8 reg
)
379 return READ_PORT_UCHAR((PUCHAR
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + reg
));
382 STDMETHODIMP_(void) CCMIAdapter::writeUInt8(UInt8 cmd
, UInt8 value
)
384 WRITE_PORT_UCHAR((PUCHAR
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + cmd
), value
);
387 STDMETHODIMP_(void) CCMIAdapter::setUInt8Bit(UInt8 reg
, UInt8 flag
)
389 writeUInt8(reg
, readUInt8(reg
) | flag
);
392 STDMETHODIMP_(void) CCMIAdapter::clearUInt8Bit(UInt8 reg
, UInt8 flag
)
394 writeUInt8(reg
, readUInt8(reg
) & ~flag
);
397 STDMETHODIMP_(UInt16
) CCMIAdapter::readUInt16(UInt8 reg
)
399 return READ_PORT_USHORT((PUSHORT
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + reg
));
402 STDMETHODIMP_(void) CCMIAdapter::writeUInt16(UInt8 cmd
, UInt16 value
)
404 WRITE_PORT_USHORT((PUSHORT
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + cmd
), value
);
408 STDMETHODIMP_(UInt32
) CCMIAdapter::readUInt32(UInt8 reg
)
410 return READ_PORT_ULONG((PULONG
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + reg
));
413 STDMETHODIMP_(void) CCMIAdapter::writeUInt32(UInt8 cmd
, UInt32 value
)
415 WRITE_PORT_ULONG((PULONG
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + cmd
), value
);
418 STDMETHODIMP_(void) CCMIAdapter::setUInt32Bit(UInt8 reg
, UInt32 flag
)
420 writeUInt32(reg
, readUInt32(reg
) | flag
);
423 STDMETHODIMP_(void) CCMIAdapter::clearUInt32Bit(UInt8 reg
, UInt32 flag
)
425 writeUInt32(reg
, readUInt32(reg
) & ~flag
);
428 STDMETHODIMP_(UInt8
) CCMIAdapter::readMixer(UInt8 index
)
430 if (mixerCache
[index
] == 0xFF) {
431 writeUInt8(REG_SBINDEX
, index
);
432 mixerCache
[index
] = readUInt8(REG_SBDATA
);
434 return mixerCache
[index
];
437 STDMETHODIMP_(void) CCMIAdapter::writeMixer(UInt8 index
, UInt8 value
)
439 if (value
!= mixerCache
[index
]) {
440 mixerCache
[index
] = value
;
441 writeUInt8(REG_SBINDEX
, index
);
442 writeUInt8(REG_SBDATA
, value
);
446 STDMETHODIMP_(void) CCMIAdapter::setMixerBit(UInt8 index
, UInt8 flag
)
448 writeMixer(index
, readMixer(index
) | flag
);
451 STDMETHODIMP_(void) CCMIAdapter::clearMixerBit(UInt8 index
, UInt8 flag
)
453 writeMixer(index
, readMixer(index
) & ~flag
);
456 NTSTATUS NTAPI
CCMIAdapter::InterruptServiceRoutine(PINTERRUPTSYNC InterruptSync
, PVOID DynamicContext
)
458 UInt32 status
, mask
= 0;
460 CCMIAdapter
*CMIAdapter
= (CCMIAdapter
*)DynamicContext
;
463 //ASSERT(InterruptSync);
464 //ASSERT(DynamicContext);
467 if (!(CMIAdapter
->cm
.WaveMiniport
)) {
468 return STATUS_UNSUCCESSFUL
;
471 status
= CMIAdapter
->readUInt32(REG_INT_STAT
);
473 if ((!(status
& INT_PENDING
)) || (status
== 0xFFFFFFFF)) {
474 return STATUS_UNSUCCESSFUL
;
477 if (status
& INT_CH0
) {
480 CMIAdapter
->cm
.WaveMiniport
->ServiceWaveISR(PCM_OUT_STREAM
);
483 CMIAdapter
->cm
.WaveMiniport
->ServiceWaveISR(PCM_IN_STREAM
);
486 if (status
& INT_CH1
) {
489 CMIAdapter
->cm
.WaveMiniport
->ServiceWaveISR(PCM_OUT_STREAM
);
492 CMIAdapter
->cm
.WaveMiniport
->ServiceWaveISR(PCM_IN_STREAM
);
496 if (status
& INT_UART
) {
497 // the UART miniport should catch / have caught the interrupt
498 return STATUS_UNSUCCESSFUL
;
502 CMIAdapter
->clearUInt32Bit(REG_INTHLDCLR
, mask
);
503 CMIAdapter
->setUInt32Bit(REG_INTHLDCLR
, mask
);
505 return STATUS_SUCCESS
;