2 Copyright (c) 2006-2008 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")
34 NTSTATUS
NewCMIAdapter(PUNKNOWN
*Unknown
, REFCLSID
, PUNKNOWN UnknownOuter
, POOL_TYPE PoolType
)
37 DBGPRINT(("NewCMIAdapter()"));
39 STD_CREATE_BODY_(CCMIAdapter
, Unknown
, UnknownOuter
, PoolType
, PCMIADAPTER
);
43 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::init(PRESOURCELIST ResourceList
, PDEVICE_OBJECT aDeviceObject
)
47 ASSERT(aDeviceObject
);
48 ASSERT(ResourceList
->FindTranslatedPort(0));
49 DBGPRINT(("CCMIAdapter[%p]::init()", this));
51 NTSTATUS ntStatus
= STATUS_SUCCESS
;
53 RtlFillMemory(&mixerCache
, 0xFF, 0xFF);
54 RtlFillMemory(&cm
, sizeof(cm
), 0x00);
56 DeviceObject
= aDeviceObject
;
59 for (unsigned int i
=0;i
<ResourceList
->NumberOfPorts();i
++) {
60 if (ResourceList
->FindTranslatedPort(i
)->u
.Port
.Length
== 0x100) {
61 cm
.IOBase
= (UInt32
*)ResourceList
->FindTranslatedPort(i
)->u
.Port
.Start
.QuadPart
;
66 return STATUS_INSUFFICIENT_RESOURCES
;
71 INFOPRINT(("Driver Version: %s-WAVERT", CMIVERSION
));
73 INFOPRINT(("Driver Version: %s", CMIVERSION
));
75 INFOPRINT(("Configuration:"));
76 INFOPRINT((" IO Base: 0x%X", cm
.IOBase
));
77 INFOPRINT((" MPU Base: 0x%X", cm
.MPUBase
));
80 return STATUS_INSUFFICIENT_RESOURCES
;
83 INFOPRINT((" Chip Version: %d", cm
.chipVersion
));
84 INFOPRINT((" Max Channels: %d", cm
.maxChannels
));
85 INFOPRINT((" CanAC3HW: %d", cm
.canAC3HW
));
89 ntStatus
= PcNewInterruptSync(&(InterruptSync
), NULL
, ResourceList
, 0, InterruptSyncModeNormal
);
90 if (!NT_SUCCESS(ntStatus
) || !(InterruptSync
)) {
91 DBGPRINT(("Failed to create an interrupt sync!"));
92 return STATUS_INSUFFICIENT_RESOURCES
;
94 ntStatus
= InterruptSync
->RegisterServiceRoutine(InterruptServiceRoutine
, (PVOID
)this, FALSE
);
95 if (!NT_SUCCESS(ntStatus
)) {
96 DBGPRINT(("Failed to register ISR!"));
100 ntStatus
= InterruptSync
->Connect();
101 if (!NT_SUCCESS(ntStatus
)) {
102 DBGPRINT(("Failed to connect the ISR with InterruptSync!"));
106 // Initialize the device state.
107 CurrentPowerState
= PowerDeviceD0
;
113 CCMIAdapter::~CCMIAdapter()
116 DBGPRINT(("CCMIAdapter[%p]::~CCMIAdapter()", this));
119 InterruptSync
->Disconnect();
120 InterruptSync
->Release();
121 InterruptSync
= NULL
;
125 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::NonDelegatingQueryInterface(REFIID Interface
, PVOID
* Object
)
129 DBGPRINT(("CCMIAdapter[%p]::NonDelegatingQueryInterface()", this));
133 // Is it IID_IUnknown?
134 if (IsEqualGUIDAligned (Interface
, IID_IUnknown
)) {
135 *Object
= (PVOID
)(PUNKNOWN
)(PCMIADAPTER
)this;
138 // or IID_IAdapterCommon ...
139 if (IsEqualGUIDAligned (Interface
, IID_ICMIAdapter
)) {
140 *Object
= (PVOID
)(PCMIADAPTER
)this;
142 // or IID_IAdapterPowerManagement ...
143 if (IsEqualGUIDAligned (Interface
, IID_IAdapterPowerManagement
)) {
144 *Object
= (PVOID
)(PADAPTERPOWERMANAGEMENT
)this;
146 // nothing found, must be an unknown interface.
148 return STATUS_INVALID_PARAMETER
;
152 // We reference the interface for the caller.
154 ((PUNKNOWN
)*Object
)->AddRef();
155 return STATUS_SUCCESS
;
158 bool CCMIAdapter::queryChip()
161 DBGPRINT(("CCMIAdapter[%p]::queryChip()", this));
163 UInt32 version
= readUInt32(REG_INTHLDCLR
) & VERSION_MASK
;
164 if (version
== 0xFFFFFFFF) {
168 if (version
& VERSION_68
) {
172 cm
.hasDualDAC
= true;
173 cm
.canMultiChannel
= true;
176 if (version
& VERSION_55
) {
180 cm
.hasDualDAC
= true;
181 cm
.canMultiChannel
= true;
184 if (version
& VERSION_39
) {
186 if (version
& VERSION_39_6
) {
192 cm
.hasDualDAC
= true;
193 cm
.canMultiChannel
= true;
197 version
= readUInt32(REG_CHFORMAT
) & VERSION_37
;
206 cm
.hasDualDAC
= true;
219 void CCMIAdapter::resetMixer()
222 DBGPRINT(("CCMIAdapter[%p]::resetMixer()", this));
225 setUInt8Bit(REG_MIXER1
, EN_SPDI2DAC
);
228 void CCMIAdapter::resetController()
231 DBGPRINT(("CCMIAdapter[%p]::resetController()", this));
233 writeUInt32(REG_INTHLDCLR
, 0);
236 writeUInt32(REG_FUNCTRL0
, ADC_CH0
| (RST_CH0
| RST_CH1
));
237 writeUInt32(REG_FUNCTRL0
, ADC_CH0
& ~(RST_CH0
| RST_CH1
));
239 writeUInt32(REG_FUNCTRL0
, ADC_CH1
| (RST_CH0
| RST_CH1
));
240 writeUInt32(REG_FUNCTRL0
, ADC_CH1
& ~(RST_CH0
| RST_CH1
));
242 KeStallExecutionProcessor(100L);
244 writeUInt32(REG_FUNCTRL0
, 0);
245 writeUInt32(REG_FUNCTRL1
, 0);
247 writeUInt32(REG_CHFORMAT
, 0);
248 writeUInt32(REG_MISCCTRL
, EN_DBLDAC
);
250 setUInt32Bit(REG_MISCCTRL
, XCHG_DAC
);
253 setUInt32Bit(REG_FUNCTRL1
, BREQ
);
261 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::activateMPU(ULONG
* MPUBase
)
264 DBGPRINT(("CCMIAdapter[%p]::activateMPU(%X)", this, MPUBase
));
268 switch ((LONGLONG
)MPUBase
) {
269 case 0x300: LegacyCtrl
= UART_300
; break;
270 case 0x310: LegacyCtrl
= UART_310
; break;
271 case 0x320: LegacyCtrl
= UART_320
; break;
272 case 0x330: LegacyCtrl
= UART_330
; break; // UART_330 == 0
273 default: LegacyCtrl
= 0xFFFFFFFF; break;
275 if (LegacyCtrl
< 0xFFFFFFFF) {
276 cm
.MPUBase
= MPUBase
;
277 setUInt32Bit(REG_FUNCTRL1
, EN_UART
);
278 writeUInt32(REG_LEGACY
, LegacyCtrl
);
279 return STATUS_SUCCESS
;
282 return STATUS_UNSUCCESSFUL
;
285 // "The code for this method must reside in paged memory.", IID_IAdapterPowerManagement.PowerChangeState() docs
286 // XP's order of power states when going to hibernate: D3 -> D0, waking up: D0 -> D3.
287 STDMETHODIMP_(void) CCMIAdapter::PowerChangeState(POWER_STATE NewState
)
290 DBGPRINT(("CCMIAdapter[%p]::PowerChangeState(%p)", this, NewState
));
292 if (NewState
.DeviceState
== CurrentPowerState
) {
296 switch (NewState
.DeviceState
) {
297 case PowerDeviceD0
: // powering up, hardware access allowed
298 clearUInt32Bit(REG_MISCCTRL
, PWD_CHIP
);
299 cm
.WaveMiniport
->powerUp();
300 CurrentPowerState
= NewState
.DeviceState
;
303 case PowerDeviceD1
: // powering down, hardware access still allowed
304 setUInt32Bit(REG_MISCCTRL
, PWD_CHIP
);
305 CurrentPowerState
= NewState
.DeviceState
;
308 case PowerDeviceD2
: // sleep state - hardware access not allowed
309 case PowerDeviceD3
: // hibernation state - hardware access not allowed
310 if (CurrentPowerState
== PowerDeviceD0
) {
311 cm
.WaveMiniport
->powerDown();
312 setUInt32Bit(REG_MISCCTRL
, PWD_CHIP
);
314 CurrentPowerState
= NewState
.DeviceState
;
316 default: // unknown power state
321 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::QueryPowerChangeState(POWER_STATE NewStateQuery
)
324 DBGPRINT(("CCMIAdapter[%p]::QueryPowerChangeState(%p)", this, NewStateQuery
));
325 return STATUS_SUCCESS
;
328 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::QueryDeviceCapabilities(PDEVICE_CAPABILITIES PowerDeviceCaps
)
331 DBGPRINT(("CCMIAdapter[%p]::QueryDeviceCapabilities(%p)", this, PowerDeviceCaps
));
332 return STATUS_SUCCESS
;
335 STDMETHODIMP_(NTSTATUS
) CCMIAdapter::loadSBMixerFromMemory()
338 DBGPRINT(("CCMIAdapter[%p]::loadSBMixerFromMemory()", this));
339 UInt8 sbIndex
[] = { 0x04, 0x0A, 0x22, 0x28, 0x2E, 0x30, 0x31, 0x32, 0x33, 0x36, 0x37, 0x38,
340 0x39, 0x3A, 0x3C, 0x3D, 0x3E, 0xF0 };
342 for (unsigned int i
= 0; i
<(sizeof(sbIndex
)/sizeof(sbIndex
[0]));i
++) {
343 writeUInt8(REG_SBINDEX
, sbIndex
[i
]);
344 writeUInt8(REG_SBDATA
, mixerCache
[sbIndex
[i
]]);
347 return STATUS_SUCCESS
;
351 ** non-paged code below
357 STDMETHODIMP_(UInt8
) CCMIAdapter::readUInt8(UInt8 reg
)
359 return READ_PORT_UCHAR((PUCHAR
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + reg
));
362 STDMETHODIMP_(void) CCMIAdapter::writeUInt8(UInt8 cmd
, UInt8 value
)
364 WRITE_PORT_UCHAR((PUCHAR
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + cmd
), value
);
367 STDMETHODIMP_(void) CCMIAdapter::setUInt8Bit(UInt8 reg
, UInt8 flag
)
369 writeUInt8(reg
, readUInt8(reg
) | flag
);
372 STDMETHODIMP_(void) CCMIAdapter::clearUInt8Bit(UInt8 reg
, UInt8 flag
)
374 writeUInt8(reg
, readUInt8(reg
) & ~flag
);
377 STDMETHODIMP_(UInt16
) CCMIAdapter::readUInt16(UInt8 reg
)
379 return READ_PORT_USHORT((PUSHORT
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + reg
));
382 STDMETHODIMP_(void) CCMIAdapter::writeUInt16(UInt8 cmd
, UInt16 value
)
384 WRITE_PORT_USHORT((PUSHORT
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + cmd
), value
);
388 STDMETHODIMP_(UInt32
) CCMIAdapter::readUInt32(UInt8 reg
)
390 return READ_PORT_ULONG((PULONG
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + reg
));
393 STDMETHODIMP_(void) CCMIAdapter::writeUInt32(UInt8 cmd
, UInt32 value
)
395 WRITE_PORT_ULONG((PULONG
)(reinterpret_cast<PUCHAR
>(cm
.IOBase
) + cmd
), value
);
398 STDMETHODIMP_(void) CCMIAdapter::setUInt32Bit(UInt8 reg
, UInt32 flag
)
400 writeUInt32(reg
, readUInt32(reg
) | flag
);
403 STDMETHODIMP_(void) CCMIAdapter::clearUInt32Bit(UInt8 reg
, UInt32 flag
)
405 writeUInt32(reg
, readUInt32(reg
) & ~flag
);
408 STDMETHODIMP_(UInt8
) CCMIAdapter::readMixer(UInt8 index
)
410 if (mixerCache
[index
] == 0xFF) {
411 writeUInt8(REG_SBINDEX
, index
);
412 mixerCache
[index
] = readUInt8(REG_SBDATA
);
414 return mixerCache
[index
];
417 STDMETHODIMP_(void) CCMIAdapter::writeMixer(UInt8 index
, UInt8 value
)
419 if (value
!= mixerCache
[index
]) {
420 mixerCache
[index
] = value
;
421 writeUInt8(REG_SBINDEX
, index
);
422 writeUInt8(REG_SBDATA
, value
);
426 STDMETHODIMP_(void) CCMIAdapter::setMixerBit(UInt8 index
, UInt8 flag
)
428 writeMixer(index
, readMixer(index
) | flag
);
431 STDMETHODIMP_(void) CCMIAdapter::clearMixerBit(UInt8 index
, UInt8 flag
)
433 writeMixer(index
, readMixer(index
) & ~flag
);
436 NTSTATUS NTAPI
CCMIAdapter::InterruptServiceRoutine(PINTERRUPTSYNC InterruptSync
, PVOID DynamicContext
)
438 ASSERT(InterruptSync
);
439 ASSERT(DynamicContext
);
441 UInt32 status
, mask
= 0;
443 CCMIAdapter
*CMIAdapter
= (CCMIAdapter
*)DynamicContext
;
445 if (!(CMIAdapter
->cm
.WaveMiniport
)) {
446 return STATUS_UNSUCCESSFUL
;
449 status
= CMIAdapter
->readUInt32(REG_INT_STAT
);
451 if ((!(status
& INT_PENDING
)) || (status
== 0xFFFFFFFF)) {
452 return STATUS_UNSUCCESSFUL
;
455 if (status
& INT_CH0
) {
458 CMIAdapter
->cm
.WaveMiniport
->ServiceWaveISR(PCM_OUT_STREAM
);
461 CMIAdapter
->cm
.WaveMiniport
->ServiceWaveISR(PCM_IN_STREAM
);
464 if (status
& INT_CH1
) {
467 CMIAdapter
->cm
.WaveMiniport
->ServiceWaveISR(PCM_OUT_STREAM
);
470 CMIAdapter
->cm
.WaveMiniport
->ServiceWaveISR(PCM_IN_STREAM
);
474 if (status
& INT_UART
) {
475 // the UART miniport should catch / have caught the interrupt
476 return STATUS_UNSUCCESSFUL
;
480 CMIAdapter
->clearUInt32Bit(REG_INTHLDCLR
, mask
);
481 CMIAdapter
->setUInt32Bit(REG_INTHLDCLR
, mask
);
483 return STATUS_SUCCESS
;