mirror of
https://github.com/reactos/reactos.git
synced 2024-07-10 22:55:05 +00:00
[HDAUDBUS]
- move code - set FILE_AUTOGENERATED_DEVICE_NAME for pdos. Hint by ThFabba - driver now gets further svn path=/trunk/; revision=68320
This commit is contained in:
parent
6faf4f830e
commit
a91363bc5d
|
@ -5,7 +5,10 @@ remove_definitions(-D_WIN32_WINNT=0x502)
|
|||
add_definitions(-D_WIN32_WINNT=0x600)
|
||||
|
||||
list(APPEND SOURCE
|
||||
hdaudbus.cpp)
|
||||
hdaudbus.cpp
|
||||
fdo.cpp
|
||||
pdo.cpp
|
||||
businterface.cpp)
|
||||
|
||||
add_library(hdaudbus SHARED ${SOURCE})
|
||||
set_module_type(hdaudbus kernelmodedriver)
|
||||
|
|
23
reactos/drivers/wdm/audio/hdaudbus/businterface.cpp
Normal file
23
reactos/drivers/wdm/audio/hdaudbus/businterface.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel Streaming
|
||||
* FILE: drivers/wdm/audio/hdaudbus/hdaudbus.cpp
|
||||
* PURPOSE: HDA Driver Entry
|
||||
* PROGRAMMER: Johannes Anderwald
|
||||
*/
|
||||
#include "hdaudbus.h"
|
||||
|
||||
NTSTATUS
|
||||
HDA_PDOHandleQueryInterface(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
UNICODE_STRING GuidString;
|
||||
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
RtlStringFromGUID(*IoStack->Parameters.QueryInterface.InterfaceType, &GuidString);
|
||||
|
||||
DPRINT1("hda: requesting interface %wZ Version %u Size %u", &GuidString, IoStack->Parameters.QueryInterface.Version, IoStack->Parameters.QueryInterface.Size);
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
688
reactos/drivers/wdm/audio/hdaudbus/fdo.cpp
Normal file
688
reactos/drivers/wdm/audio/hdaudbus/fdo.cpp
Normal file
|
@ -0,0 +1,688 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel Streaming
|
||||
* FILE: drivers/wdm/audio/hdaudbus/fdo.cpp
|
||||
* PURPOSE: HDA Driver Entry
|
||||
* PROGRAMMER: Johannes Anderwald
|
||||
*/
|
||||
#include "hdaudbus.h"
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
HDA_InterruptService(
|
||||
IN PKINTERRUPT Interrupt,
|
||||
IN PVOID ServiceContext)
|
||||
{
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG InterruptStatus, Response, ResponseFlags, Cad;
|
||||
UCHAR RirbStatus, CorbStatus;
|
||||
USHORT WritePos;
|
||||
PHDA_CODEC_ENTRY Codec;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)ServiceContext;
|
||||
ASSERT(DeviceExtension->IsFDO == TRUE);
|
||||
|
||||
// Check if this interrupt is ours
|
||||
InterruptStatus = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_STATUS));
|
||||
|
||||
DPRINT1("HDA_InterruptService %lx\n", InterruptStatus);
|
||||
if ((InterruptStatus & INTR_STATUS_GLOBAL) == 0)
|
||||
return FALSE;
|
||||
|
||||
// Controller or stream related?
|
||||
if (InterruptStatus & INTR_STATUS_CONTROLLER) {
|
||||
RirbStatus = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_STATUS);
|
||||
CorbStatus = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS);
|
||||
|
||||
// Check for incoming responses
|
||||
if (RirbStatus) {
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_STATUS, RirbStatus);
|
||||
|
||||
if (DeviceExtension->RirbLength == 0)
|
||||
{
|
||||
/* HACK: spurious interrupt */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((RirbStatus & RIRB_STATUS_RESPONSE) != 0) {
|
||||
WritePos = (READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) + 1) % DeviceExtension->RirbLength;
|
||||
|
||||
for (; DeviceExtension->RirbReadPos != WritePos; DeviceExtension->RirbReadPos = (DeviceExtension->RirbReadPos + 1) % DeviceExtension->RirbLength)
|
||||
{
|
||||
|
||||
Response = DeviceExtension->RirbBase[DeviceExtension->RirbReadPos].response;
|
||||
ResponseFlags = DeviceExtension->RirbBase[DeviceExtension->RirbReadPos].flags;
|
||||
Cad = ResponseFlags & RESPONSE_FLAGS_CODEC_MASK;
|
||||
DPRINT1("Response %lx ResponseFlags %lx Cad %lx\n", Response, ResponseFlags, Cad);
|
||||
|
||||
/* get codec */
|
||||
Codec = DeviceExtension->Codecs[Cad];
|
||||
if (Codec == NULL)
|
||||
{
|
||||
DPRINT1("hda: response for unknown codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check response count */
|
||||
if (Codec->ResponseCount >= MAX_CODEC_RESPONSES)
|
||||
{
|
||||
DPRINT1("too many responses for codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME handle unsolicited responses
|
||||
ASSERT((ResponseFlags & RESPONSE_FLAGS_UNSOLICITED) == 0);
|
||||
|
||||
/* store response */
|
||||
Codec->Responses[Codec->ResponseCount] = Response;
|
||||
Codec->ResponseCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((RirbStatus & RIRB_STATUS_OVERRUN) != 0)
|
||||
DPRINT1("hda: RIRB Overflow\n");
|
||||
}
|
||||
|
||||
// Check for sending errors
|
||||
if (CorbStatus) {
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS, CorbStatus);
|
||||
|
||||
if ((CorbStatus & CORB_STATUS_MEMORY_ERROR) != 0)
|
||||
DPRINT1("hda: CORB Memory Error!\n");
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if ((intrStatus & INTR_STATUS_STREAM_MASK) != 0) {
|
||||
for (uint32 index = 0; index < HDA_MAX_STREAMS; index++) {
|
||||
if ((intrStatus & (1 << index)) != 0) {
|
||||
if (controller->streams[index]) {
|
||||
if (stream_handle_interrupt(controller,
|
||||
controller->streams[index], index)) {
|
||||
handled = B_INVOKE_SCHEDULER;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dprintf("hda: Stream interrupt for unconfigured stream "
|
||||
"%ld!\n", index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
HDA_SendVerbs(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PHDA_CODEC_ENTRY Codec,
|
||||
IN PULONG Verbs,
|
||||
OUT PULONG Responses,
|
||||
IN ULONG Count)
|
||||
{
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG Sent = 0, ReadPosition, WritePosition, Queued;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
/* reset response count */
|
||||
Codec->ResponseCount = 0;
|
||||
|
||||
while (Sent < Count) {
|
||||
ReadPosition = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
|
||||
|
||||
Queued = 0;
|
||||
|
||||
while (Sent < Count) {
|
||||
WritePosition = (DeviceExtension->CorbWritePos + 1) % DeviceExtension->CorbLength;
|
||||
|
||||
if (WritePosition == ReadPosition) {
|
||||
// There is no space left in the ring buffer; execute the
|
||||
// queued commands and wait until
|
||||
break;
|
||||
}
|
||||
|
||||
DeviceExtension->CorbBase[WritePosition] = Verbs[Sent++];
|
||||
DeviceExtension->CorbWritePos = WritePosition;
|
||||
|
||||
// FIXME HACK
|
||||
// do proper synchronization
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
|
||||
KeStallExecutionProcessor(30);
|
||||
Queued++;
|
||||
}
|
||||
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
|
||||
}
|
||||
|
||||
if (Responses != NULL) {
|
||||
memcpy(Responses, Codec->Responses, Codec->ResponseCount * sizeof(ULONG));
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
HDA_InitCodec(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN ULONG codecAddress)
|
||||
{
|
||||
PHDA_CODEC_ENTRY Entry;
|
||||
ULONG verbs[3];
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
CODEC_RESPONSE Response;
|
||||
ULONG NodeId, GroupType;
|
||||
NTSTATUS Status;
|
||||
PHDA_CODEC_AUDIO_GROUP AudioGroup;
|
||||
PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
|
||||
|
||||
/* lets allocate the entry */
|
||||
Entry = (PHDA_CODEC_ENTRY)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_ENTRY));
|
||||
if (!Entry)
|
||||
{
|
||||
DPRINT1("hda: failed to allocate memory");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* init codec */
|
||||
Entry->Addr = codecAddress;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
/* store codec */
|
||||
DeviceExtension->Codecs[codecAddress] = Entry;
|
||||
|
||||
verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID);
|
||||
verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID);
|
||||
verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUB_NODE_COUNT);
|
||||
|
||||
/* get basic info */
|
||||
HDA_SendVerbs(DeviceObject, Entry, verbs, (PULONG)&Response, 3);
|
||||
|
||||
/* store codec details */
|
||||
Entry->Major = Response.major;
|
||||
Entry->Minor = Response.minor;
|
||||
Entry->ProductId = Response.device;
|
||||
Entry->Revision = Response.revision;
|
||||
Entry->Stepping = Response.stepping;
|
||||
Entry->VendorId = Response.vendor;
|
||||
|
||||
DPRINT1("hda Codec %ld Vendor: %04lx Product: %04lx, Revision: %lu.%lu.%lu.%lu NodeStart %u NodeCount %u \n", codecAddress, Response.vendor,
|
||||
Response.device, Response.major, Response.minor, Response.revision, Response.stepping, Response.start, Response.count);
|
||||
|
||||
for (NodeId = Response.start; NodeId < Response.start + Response.count; NodeId++) {
|
||||
|
||||
/* get function type */
|
||||
verbs[0] = MAKE_VERB(codecAddress, NodeId, VID_GET_PARAMETER, PID_FUNCTION_GROUP_TYPE);
|
||||
|
||||
HDA_SendVerbs(DeviceObject, Entry, verbs, &GroupType, 1);
|
||||
DPRINT1("NodeId %u GroupType %x\n", NodeId, GroupType);
|
||||
|
||||
if ((GroupType & FUNCTION_GROUP_NODETYPE_MASK) == FUNCTION_GROUP_NODETYPE_AUDIO) {
|
||||
|
||||
AudioGroup = (PHDA_CODEC_AUDIO_GROUP)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_AUDIO_GROUP));
|
||||
if (!AudioGroup)
|
||||
{
|
||||
DPRINT1("hda: insufficient memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* init audio group */
|
||||
AudioGroup->NodeId = NodeId;
|
||||
AudioGroup->FunctionGroup = FUNCTION_GROUP_NODETYPE_AUDIO;
|
||||
|
||||
// Found an Audio Function Group!
|
||||
DPRINT1("NodeId %x found an audio function group!\n");
|
||||
|
||||
Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(HDA_PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_SOUND, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &AudioGroup->ChildPDO);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
FreeItem(AudioGroup);
|
||||
DPRINT1("hda failed to create device object %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* init child pdo*/
|
||||
ChildDeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)AudioGroup->ChildPDO->DeviceExtension;
|
||||
ChildDeviceExtension->IsFDO = FALSE;
|
||||
ChildDeviceExtension->Codec = Entry;
|
||||
ChildDeviceExtension->AudioGroup = AudioGroup;
|
||||
|
||||
/* setup flags */
|
||||
AudioGroup->ChildPDO->Flags |= DO_POWER_PAGABLE;
|
||||
AudioGroup->ChildPDO->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||
|
||||
/* add audio group*/
|
||||
Entry->AudioGroups[Entry->AudioGroupCount] = AudioGroup;
|
||||
Entry->AudioGroupCount++;
|
||||
}
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_InitCorbRirbPos(
|
||||
IN PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
UCHAR corbSize, value, rirbSize;
|
||||
PHYSICAL_ADDRESS HighestPhysicalAddress, CorbPhysicalAddress;
|
||||
ULONG Index;
|
||||
USHORT corbReadPointer, rirbWritePointer, interruptValue, corbControl, rirbControl;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
// Determine and set size of CORB
|
||||
corbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE);
|
||||
if ((corbSize & CORB_SIZE_CAP_256_ENTRIES) != 0) {
|
||||
DeviceExtension->CorbLength = 256;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & HDAC_CORB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_256_ENTRIES);
|
||||
}
|
||||
else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
|
||||
DeviceExtension->CorbLength = 16;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & HDAC_CORB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_16_ENTRIES);
|
||||
}
|
||||
else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
|
||||
DeviceExtension->CorbLength = 2;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & HDAC_CORB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_2_ENTRIES);
|
||||
}
|
||||
|
||||
// Determine and set size of RIRB
|
||||
rirbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE);
|
||||
if (rirbSize & RIRB_SIZE_CAP_256_ENTRIES) {
|
||||
DeviceExtension->RirbLength = 256;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & HDAC_RIRB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_256_ENTRIES);
|
||||
}
|
||||
else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
|
||||
DeviceExtension->RirbLength = 16;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & HDAC_RIRB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_16_ENTRIES);
|
||||
}
|
||||
else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
|
||||
DeviceExtension->RirbLength = 2;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & HDAC_RIRB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_2_ENTRIES);
|
||||
}
|
||||
|
||||
/* init corb */
|
||||
HighestPhysicalAddress.QuadPart = 0x00000000FFFFFFFF;
|
||||
DeviceExtension->CorbBase = (PULONG)MmAllocateContiguousMemory(PAGE_SIZE * 3, HighestPhysicalAddress);
|
||||
ASSERT(DeviceExtension->CorbBase != NULL);
|
||||
|
||||
// FIXME align rirb 128bytes
|
||||
ASSERT(DeviceExtension->CorbLength == 256);
|
||||
ASSERT(DeviceExtension->RirbLength == 256);
|
||||
|
||||
CorbPhysicalAddress = MmGetPhysicalAddress(DeviceExtension->CorbBase);
|
||||
ASSERT(CorbPhysicalAddress.QuadPart != 0LL);
|
||||
|
||||
// Program CORB/RIRB for these locations
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_LOWER), CorbPhysicalAddress.LowPart);
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_UPPER), CorbPhysicalAddress.HighPart);
|
||||
|
||||
DeviceExtension->RirbBase = (PRIRB_RESPONSE)((ULONG_PTR)DeviceExtension->CorbBase + PAGE_SIZE);
|
||||
CorbPhysicalAddress.QuadPart += PAGE_SIZE;
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_LOWER), CorbPhysicalAddress.LowPart);
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_UPPER), CorbPhysicalAddress.HighPart);
|
||||
|
||||
// Program DMA position update
|
||||
DeviceExtension->StreamPositions = (PVOID)((ULONG_PTR)DeviceExtension->RirbBase + PAGE_SIZE);
|
||||
CorbPhysicalAddress.QuadPart += PAGE_SIZE;
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), CorbPhysicalAddress.LowPart);
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), CorbPhysicalAddress.HighPart);
|
||||
|
||||
value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS)) & HDAC_CORB_WRITE_POS_MASK;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), value);
|
||||
|
||||
// Reset CORB read pointer. Preseve bits marked as RsvdP.
|
||||
// After setting the reset bit, we must wait for the hardware
|
||||
// to acknowledge it, then manually unset it and wait for that
|
||||
// to be acknowledged as well.
|
||||
corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
|
||||
|
||||
corbReadPointer |= CORB_READ_POS_RESET;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
|
||||
|
||||
for (Index = 0; Index < 100; Index++) {
|
||||
KeStallExecutionProcessor(10);
|
||||
corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) != 0)
|
||||
break;
|
||||
}
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) == 0) {
|
||||
DPRINT1("hda: CORB read pointer reset not acknowledged\n");
|
||||
|
||||
// According to HDA spec v1.0a ch3.3.21, software must read the
|
||||
// bit as 1 to verify that the reset completed. However, at least
|
||||
// some nVidia HDA controllers do not update the bit after reset.
|
||||
// Thus don't fail here on nVidia controllers.
|
||||
//if (controller->pci_info.vendor_id != PCI_VENDOR_NVIDIA)
|
||||
// return B_BUSY;
|
||||
}
|
||||
|
||||
corbReadPointer &= ~CORB_READ_POS_RESET;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
|
||||
for (Index = 0; Index < 10; Index++) {
|
||||
KeStallExecutionProcessor(10);
|
||||
corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) == 0)
|
||||
break;
|
||||
}
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) != 0) {
|
||||
DPRINT1("hda: CORB read pointer reset failed\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// Reset RIRB write pointer
|
||||
rirbWritePointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) & RIRB_WRITE_POS_RESET;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS), rirbWritePointer | RIRB_WRITE_POS_RESET);
|
||||
|
||||
// Generate interrupt for every response
|
||||
interruptValue = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT)) & HDAC_RESPONSE_INTR_COUNT_MASK;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT), interruptValue | 1);
|
||||
|
||||
// Setup cached read/write indices
|
||||
DeviceExtension->RirbReadPos = 1;
|
||||
DeviceExtension->CorbWritePos = 0;
|
||||
|
||||
// Gentlemen, start your engines...
|
||||
corbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL)) &HDAC_CORB_CONTROL_MASK;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL), corbControl | CORB_CONTROL_RUN | CORB_CONTROL_MEMORY_ERROR_INTR);
|
||||
|
||||
rirbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL)) & HDAC_RIRB_CONTROL_MASK;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL), rirbControl | RIRB_CONTROL_DMA_ENABLE | RIRB_CONTROL_OVERRUN_INTR | RIRB_CONTROL_RESPONSE_INTR);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_ResetController(
|
||||
IN PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
USHORT ValCapabilities;
|
||||
ULONG Index;
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG InputStreams, OutputStreams, BiDirStreams, Control;
|
||||
UCHAR corbControl, rirbControl;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
/* read caps */
|
||||
ValCapabilities = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_GLOBAL_CAP));
|
||||
|
||||
InputStreams = GLOBAL_CAP_INPUT_STREAMS(ValCapabilities);
|
||||
OutputStreams = GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities);
|
||||
BiDirStreams = GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities);
|
||||
|
||||
DPRINT1("NumInputStreams %u\n", InputStreams);
|
||||
DPRINT1("NumOutputStreams %u\n", OutputStreams);
|
||||
DPRINT1("NumBiDirStreams %u\n", BiDirStreams);
|
||||
|
||||
/* stop all streams */
|
||||
for (Index = 0; Index < InputStreams; Index++)
|
||||
{
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_INPUT_STREAM_OFFSET(Index), 0);
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_INPUT_STREAM_OFFSET(Index), 0);
|
||||
}
|
||||
|
||||
for (Index = 0; Index < OutputStreams; Index++) {
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_OUTPUT_STREAM_OFFSET(InputStreams, Index), 0);
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_OUTPUT_STREAM_OFFSET(InputStreams, Index), 0);
|
||||
}
|
||||
|
||||
for (Index = 0; Index < BiDirStreams; Index++) {
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
|
||||
}
|
||||
|
||||
// stop DMA
|
||||
Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL) & HDAC_CORB_CONTROL_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL, Control);
|
||||
|
||||
Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL) & HDAC_RIRB_CONTROL_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL, Control);
|
||||
|
||||
for (int timeout = 0; timeout < 10; timeout++) {
|
||||
KeStallExecutionProcessor(10);
|
||||
|
||||
corbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL);
|
||||
rirbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL);
|
||||
if (corbControl == 0 && rirbControl == 0)
|
||||
break;
|
||||
}
|
||||
if (corbControl != 0 || rirbControl != 0) {
|
||||
DPRINT1("hda: unable to stop dma\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// reset DMA position buffer
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), 0);
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), 0);
|
||||
|
||||
// Set reset bit - it must be asserted for at least 100us
|
||||
Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control & ~GLOBAL_CONTROL_RESET);
|
||||
|
||||
for (int timeout = 0; timeout < 10; timeout++) {
|
||||
KeStallExecutionProcessor(10);
|
||||
|
||||
Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
|
||||
if ((Control & GLOBAL_CONTROL_RESET) == 0)
|
||||
break;
|
||||
}
|
||||
if ((Control & GLOBAL_CONTROL_RESET) != 0)
|
||||
{
|
||||
DPRINT1("hda: unable to reset controller\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// Unset reset bit
|
||||
Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control | GLOBAL_CONTROL_RESET);
|
||||
|
||||
for (int timeout = 0; timeout < 10; timeout++) {
|
||||
KeStallExecutionProcessor(10);
|
||||
|
||||
Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
|
||||
if ((Control & GLOBAL_CONTROL_RESET) != 0)
|
||||
break;
|
||||
}
|
||||
if ((Control & GLOBAL_CONTROL_RESET) == 0) {
|
||||
DPRINT1("hda: unable to exit reset\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// Wait for codecs to finish their own reset (apparently needs more
|
||||
// time than documented in the specs)
|
||||
KeStallExecutionProcessor(100);
|
||||
|
||||
// Enable unsolicited responses
|
||||
Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control | GLOBAL_CONTROL_UNSOLICITED);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_FDOStartDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
PCM_RESOURCE_LIST Resources;
|
||||
ULONG Index;
|
||||
USHORT Value;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ASSERT(DeviceExtension->IsFDO == TRUE);
|
||||
|
||||
/* forward irp to lower device */
|
||||
Status = HDA_SyncForwardIrp(DeviceExtension->LowerDevice, Irp);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
// failed to start
|
||||
DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* get current irp stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
Resources = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
|
||||
for (Index = 0; Index < Resources->List[0].PartialResourceList.Count; Index++)
|
||||
{
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &Resources->List[0].PartialResourceList.PartialDescriptors[Index];
|
||||
|
||||
if (Descriptor->Type == CmResourceTypeMemory)
|
||||
{
|
||||
DeviceExtension->RegBase = (PUCHAR)MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached);
|
||||
if (DeviceExtension->RegBase == NULL)
|
||||
{
|
||||
DPRINT1("[HDAB] Failed to map registers\n");
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Descriptor->Type == CmResourceTypeInterrupt)
|
||||
{
|
||||
Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
|
||||
HDA_InterruptService,
|
||||
(PVOID)DeviceExtension,
|
||||
NULL,
|
||||
Descriptor->u.Interrupt.Vector,
|
||||
Descriptor->u.Interrupt.Level,
|
||||
Descriptor->u.Interrupt.Level,
|
||||
(KINTERRUPT_MODE)(Descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED),
|
||||
(Descriptor->ShareDisposition != CmResourceShareDeviceExclusive),
|
||||
Descriptor->u.Interrupt.Affinity,
|
||||
FALSE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("[HDAB] Failed to connect interrupt\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
// Get controller into valid state
|
||||
Status = HDA_ResetController(DeviceObject);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
// Setup CORB/RIRB/DMA POS
|
||||
Status = HDA_InitCorbRirbPos(DeviceObject);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
|
||||
// Don't enable codec state change interrupts. We don't handle
|
||||
// them, as we want to use the STATE_STATUS register to identify
|
||||
// available codecs. We'd have to clear that register in the interrupt
|
||||
// handler to 'ack' the codec change.
|
||||
Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE)) & HDAC_WAKE_ENABLE_MASK;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE), Value);
|
||||
|
||||
// Enable controller interrupts
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_CONTROL), INTR_CONTROL_GLOBAL_ENABLE | INTR_CONTROL_CONTROLLER_ENABLE);
|
||||
|
||||
KeStallExecutionProcessor(100);
|
||||
|
||||
Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS));
|
||||
if (!Value) {
|
||||
DPRINT1("hda: bad codec status\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS), Value);
|
||||
|
||||
// Create codecs
|
||||
DPRINT1("Codecs %lx\n", Value);
|
||||
for (Index = 0; Index < HDA_MAX_CODECS; Index++) {
|
||||
if ((Value & (1 << Index)) != 0) {
|
||||
HDA_InitCodec(DeviceObject, Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_FDOQueryBusRelations(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
ULONG DeviceCount, CodecIndex, AFGIndex;
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
PHDA_CODEC_ENTRY Codec;
|
||||
PDEVICE_RELATIONS DeviceRelations;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ASSERT(DeviceExtension->IsFDO == TRUE);
|
||||
|
||||
DeviceCount = 0;
|
||||
for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
|
||||
{
|
||||
if (DeviceExtension->Codecs[CodecIndex] == NULL)
|
||||
continue;
|
||||
|
||||
Codec = DeviceExtension->Codecs[CodecIndex];
|
||||
DeviceCount += Codec->AudioGroupCount;
|
||||
}
|
||||
|
||||
if (DeviceCount == 0)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? sizeof(PDEVICE_OBJECT) * (DeviceCount - 1) : 0));
|
||||
if (!DeviceRelations)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DeviceCount = 0;
|
||||
for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
|
||||
{
|
||||
if (DeviceExtension->Codecs[CodecIndex] == NULL)
|
||||
continue;
|
||||
|
||||
Codec = DeviceExtension->Codecs[CodecIndex];
|
||||
for (AFGIndex = 0; AFGIndex < Codec->AudioGroupCount; AFGIndex++)
|
||||
{
|
||||
DeviceRelations->Objects[DeviceRelations->Count] = Codec->AudioGroups[AFGIndex]->ChildPDO;
|
||||
ObReferenceObject(Codec->AudioGroups[AFGIndex]->ChildPDO);
|
||||
DeviceRelations->Count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME handle existing device relations */
|
||||
ASSERT(Irp->IoStatus.Information == 0);
|
||||
|
||||
/* store device relations */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -5,15 +5,13 @@
|
|||
* PURPOSE: HDA Driver Entry
|
||||
* PROGRAMMER: Johannes Anderwald
|
||||
*/
|
||||
|
||||
|
||||
#include "hdaudbus.h"
|
||||
|
||||
|
||||
PVOID
|
||||
AllocateItem(
|
||||
IN POOL_TYPE PoolType,
|
||||
IN SIZE_T NumberOfBytes)
|
||||
IN POOL_TYPE PoolType,
|
||||
IN SIZE_T NumberOfBytes)
|
||||
{
|
||||
PVOID Item = ExAllocatePoolWithTag(PoolType, NumberOfBytes, TAG_HDA);
|
||||
if (!Item)
|
||||
|
@ -84,881 +82,6 @@ HDA_SyncForwardIrp(
|
|||
return Status;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
HDA_InterruptService(
|
||||
IN PKINTERRUPT Interrupt,
|
||||
IN PVOID ServiceContext)
|
||||
{
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG InterruptStatus, Response, ResponseFlags, Cad;
|
||||
UCHAR RirbStatus, CorbStatus;
|
||||
USHORT WritePos;
|
||||
PHDA_CODEC_ENTRY Codec;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)ServiceContext;
|
||||
|
||||
// Check if this interrupt is ours
|
||||
InterruptStatus = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_STATUS));
|
||||
|
||||
DPRINT1("HDA_InterruptService %lx\n", InterruptStatus);
|
||||
if ((InterruptStatus & INTR_STATUS_GLOBAL) == 0)
|
||||
return FALSE;
|
||||
|
||||
// Controller or stream related?
|
||||
if (InterruptStatus & INTR_STATUS_CONTROLLER) {
|
||||
RirbStatus = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_STATUS);
|
||||
CorbStatus = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS);
|
||||
|
||||
// Check for incoming responses
|
||||
if (RirbStatus) {
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_STATUS, RirbStatus);
|
||||
|
||||
if (DeviceExtension->RirbLength == 0)
|
||||
{
|
||||
/* HACK: spurious interrupt */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((RirbStatus & RIRB_STATUS_RESPONSE) != 0) {
|
||||
WritePos = (READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) + 1) % DeviceExtension->RirbLength;
|
||||
|
||||
for (; DeviceExtension->RirbReadPos != WritePos; DeviceExtension->RirbReadPos = (DeviceExtension->RirbReadPos + 1) % DeviceExtension->RirbLength)
|
||||
{
|
||||
|
||||
Response = DeviceExtension->RirbBase[DeviceExtension->RirbReadPos].response;
|
||||
ResponseFlags = DeviceExtension->RirbBase[DeviceExtension->RirbReadPos].flags;
|
||||
Cad = ResponseFlags & RESPONSE_FLAGS_CODEC_MASK;
|
||||
DPRINT1("Response %lx ResponseFlags %lx Cad %lx\n", Response, ResponseFlags, Cad);
|
||||
|
||||
/* get codec */
|
||||
Codec = DeviceExtension->Codecs[Cad];
|
||||
if (Codec == NULL)
|
||||
{
|
||||
DPRINT1("hda: response for unknown codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check response count */
|
||||
if (Codec->ResponseCount >= MAX_CODEC_RESPONSES)
|
||||
{
|
||||
DPRINT1("too many responses for codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME handle unsolicited responses
|
||||
ASSERT((ResponseFlags & RESPONSE_FLAGS_UNSOLICITED) == 0);
|
||||
|
||||
/* store response */
|
||||
Codec->Responses[Codec->ResponseCount] = Response;
|
||||
Codec->ResponseCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((RirbStatus & RIRB_STATUS_OVERRUN) != 0)
|
||||
DPRINT1("hda: RIRB Overflow\n");
|
||||
}
|
||||
|
||||
// Check for sending errors
|
||||
if (CorbStatus) {
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS, CorbStatus);
|
||||
|
||||
if ((CorbStatus & CORB_STATUS_MEMORY_ERROR) != 0)
|
||||
DPRINT1("hda: CORB Memory Error!\n");
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if ((intrStatus & INTR_STATUS_STREAM_MASK) != 0) {
|
||||
for (uint32 index = 0; index < HDA_MAX_STREAMS; index++) {
|
||||
if ((intrStatus & (1 << index)) != 0) {
|
||||
if (controller->streams[index]) {
|
||||
if (stream_handle_interrupt(controller,
|
||||
controller->streams[index], index)) {
|
||||
handled = B_INVOKE_SCHEDULER;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dprintf("hda: Stream interrupt for unconfigured stream "
|
||||
"%ld!\n", index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
HDA_SendVerbs(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PHDA_CODEC_ENTRY Codec,
|
||||
IN PULONG Verbs,
|
||||
OUT PULONG Responses,
|
||||
IN ULONG Count)
|
||||
{
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG Sent = 0, ReadPosition, WritePosition, Queued;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
/* reset response count */
|
||||
Codec->ResponseCount = 0;
|
||||
|
||||
while (Sent < Count) {
|
||||
ReadPosition = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
|
||||
|
||||
Queued = 0;
|
||||
|
||||
while (Sent < Count) {
|
||||
WritePosition = (DeviceExtension->CorbWritePos + 1) % DeviceExtension->CorbLength;
|
||||
|
||||
if (WritePosition == ReadPosition) {
|
||||
// There is no space left in the ring buffer; execute the
|
||||
// queued commands and wait until
|
||||
break;
|
||||
}
|
||||
|
||||
DeviceExtension->CorbBase[WritePosition] = Verbs[Sent++];
|
||||
DeviceExtension->CorbWritePos = WritePosition;
|
||||
|
||||
// FIXME HACK
|
||||
// do proper synchronization
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
|
||||
KeStallExecutionProcessor(30);
|
||||
Queued++;
|
||||
}
|
||||
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
|
||||
}
|
||||
|
||||
if (Responses != NULL) {
|
||||
memcpy(Responses, Codec->Responses, Codec->ResponseCount * sizeof(ULONG));
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
HDA_InitCodec(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN ULONG codecAddress)
|
||||
{
|
||||
PHDA_CODEC_ENTRY Entry;
|
||||
ULONG verbs[3];
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
CODEC_RESPONSE Response;
|
||||
ULONG NodeId, GroupType;
|
||||
NTSTATUS Status;
|
||||
PHDA_CODEC_AUDIO_GROUP AudioGroup;
|
||||
PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
|
||||
|
||||
/* lets allocate the entry */
|
||||
Entry = (PHDA_CODEC_ENTRY)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_ENTRY));
|
||||
if (!Entry)
|
||||
{
|
||||
DPRINT1("hda: failed to allocate memory");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* init codec */
|
||||
Entry->Addr = codecAddress;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
/* store codec */
|
||||
DeviceExtension->Codecs[codecAddress] = Entry;
|
||||
|
||||
verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID);
|
||||
verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID);
|
||||
verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUB_NODE_COUNT);
|
||||
|
||||
/* get basic info */
|
||||
HDA_SendVerbs(DeviceObject, Entry, verbs, (PULONG)&Response, 3);
|
||||
|
||||
/* store codec details */
|
||||
Entry->Major = Response.major;
|
||||
Entry->Minor = Response.minor;
|
||||
Entry->ProductId = Response.device;
|
||||
Entry->Revision = Response.revision;
|
||||
Entry->Stepping = Response.stepping;
|
||||
Entry->VendorId = Response.vendor;
|
||||
|
||||
DPRINT1("hda Codec %ld Vendor: %04lx Product: %04lx, Revision: %lu.%lu.%lu.%lu NodeStart %u NodeCount %u \n", codecAddress, Response.vendor,
|
||||
Response.device, Response.major, Response.minor, Response.revision, Response.stepping, Response.start, Response.count);
|
||||
|
||||
for (NodeId = Response.start; NodeId < Response.start + Response.count; NodeId++) {
|
||||
|
||||
/* get function type */
|
||||
verbs[0] = MAKE_VERB(codecAddress, NodeId, VID_GET_PARAMETER, PID_FUNCTION_GROUP_TYPE);
|
||||
|
||||
HDA_SendVerbs(DeviceObject, Entry, verbs, &GroupType, 1);
|
||||
DPRINT1("NodeId %u GroupType %x\n", NodeId, GroupType);
|
||||
|
||||
if ((GroupType & FUNCTION_GROUP_NODETYPE_MASK) == FUNCTION_GROUP_NODETYPE_AUDIO) {
|
||||
|
||||
AudioGroup = (PHDA_CODEC_AUDIO_GROUP)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_AUDIO_GROUP));
|
||||
if (!AudioGroup)
|
||||
{
|
||||
DPRINT1("hda: insufficient memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* init audio group */
|
||||
AudioGroup->NodeId = NodeId;
|
||||
AudioGroup->FunctionGroup = FUNCTION_GROUP_NODETYPE_AUDIO;
|
||||
|
||||
// Found an Audio Function Group!
|
||||
DPRINT1("NodeId %x found an audio function group!\n");
|
||||
|
||||
Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(HDA_PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_SOUND, 0, FALSE, &AudioGroup->ChildPDO);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
FreeItem(AudioGroup);
|
||||
DPRINT1("hda failed to create device object %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* init child pdo*/
|
||||
ChildDeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)AudioGroup->ChildPDO->DeviceExtension;
|
||||
ChildDeviceExtension->IsFDO = FALSE;
|
||||
ChildDeviceExtension->Codec = Entry;
|
||||
ChildDeviceExtension->AudioGroup = AudioGroup;
|
||||
|
||||
/* setup flags */
|
||||
AudioGroup->ChildPDO->Flags |= DO_POWER_PAGABLE;
|
||||
AudioGroup->ChildPDO->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||
|
||||
/* add audio group*/
|
||||
Entry->AudioGroups[Entry->AudioGroupCount] = AudioGroup;
|
||||
Entry->AudioGroupCount++;
|
||||
}
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_InitCorbRirbPos(
|
||||
IN PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
UCHAR corbSize, value, rirbSize;
|
||||
PHYSICAL_ADDRESS HighestPhysicalAddress, CorbPhysicalAddress;
|
||||
ULONG Index;
|
||||
USHORT corbReadPointer, rirbWritePointer, interruptValue, corbControl, rirbControl;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
// Determine and set size of CORB
|
||||
corbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE);
|
||||
if ((corbSize & CORB_SIZE_CAP_256_ENTRIES) != 0) {
|
||||
DeviceExtension->CorbLength = 256;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & HDAC_CORB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_256_ENTRIES);
|
||||
}
|
||||
else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
|
||||
DeviceExtension->CorbLength = 16;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & HDAC_CORB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_16_ENTRIES);
|
||||
}
|
||||
else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
|
||||
DeviceExtension->CorbLength = 2;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & HDAC_CORB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_2_ENTRIES);
|
||||
}
|
||||
|
||||
// Determine and set size of RIRB
|
||||
rirbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE);
|
||||
if (rirbSize & RIRB_SIZE_CAP_256_ENTRIES) {
|
||||
DeviceExtension->RirbLength = 256;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & HDAC_RIRB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_256_ENTRIES);
|
||||
}
|
||||
else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
|
||||
DeviceExtension->RirbLength = 16;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & HDAC_RIRB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_16_ENTRIES);
|
||||
}
|
||||
else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
|
||||
DeviceExtension->RirbLength = 2;
|
||||
|
||||
value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & HDAC_RIRB_SIZE_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_2_ENTRIES);
|
||||
}
|
||||
|
||||
/* init corb */
|
||||
HighestPhysicalAddress.QuadPart = 0x00000000FFFFFFFF;
|
||||
DeviceExtension->CorbBase = (PULONG)MmAllocateContiguousMemory(PAGE_SIZE * 3, HighestPhysicalAddress);
|
||||
ASSERT(DeviceExtension->CorbBase != NULL);
|
||||
|
||||
// FIXME align rirb 128bytes
|
||||
ASSERT(DeviceExtension->CorbLength == 256);
|
||||
ASSERT(DeviceExtension->RirbLength == 256);
|
||||
|
||||
CorbPhysicalAddress = MmGetPhysicalAddress(DeviceExtension->CorbBase);
|
||||
ASSERT(CorbPhysicalAddress.QuadPart != 0LL);
|
||||
|
||||
// Program CORB/RIRB for these locations
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_LOWER), CorbPhysicalAddress.LowPart);
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_UPPER), CorbPhysicalAddress.HighPart);
|
||||
|
||||
DeviceExtension->RirbBase = (PRIRB_RESPONSE)((ULONG_PTR)DeviceExtension->CorbBase + PAGE_SIZE);
|
||||
CorbPhysicalAddress.QuadPart += PAGE_SIZE;
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_LOWER), CorbPhysicalAddress.LowPart);
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_UPPER), CorbPhysicalAddress.HighPart);
|
||||
|
||||
// Program DMA position update
|
||||
DeviceExtension->StreamPositions = (PVOID)((ULONG_PTR)DeviceExtension->RirbBase + PAGE_SIZE);
|
||||
CorbPhysicalAddress.QuadPart += PAGE_SIZE;
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), CorbPhysicalAddress.LowPart);
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), CorbPhysicalAddress.HighPart);
|
||||
|
||||
value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS)) & HDAC_CORB_WRITE_POS_MASK;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), value);
|
||||
|
||||
// Reset CORB read pointer. Preseve bits marked as RsvdP.
|
||||
// After setting the reset bit, we must wait for the hardware
|
||||
// to acknowledge it, then manually unset it and wait for that
|
||||
// to be acknowledged as well.
|
||||
corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
|
||||
|
||||
corbReadPointer |= CORB_READ_POS_RESET;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
|
||||
|
||||
for (Index = 0; Index < 100; Index++) {
|
||||
KeStallExecutionProcessor(10);
|
||||
corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) != 0)
|
||||
break;
|
||||
}
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) == 0) {
|
||||
DPRINT1("hda: CORB read pointer reset not acknowledged\n");
|
||||
|
||||
// According to HDA spec v1.0a ch3.3.21, software must read the
|
||||
// bit as 1 to verify that the reset completed. However, at least
|
||||
// some nVidia HDA controllers do not update the bit after reset.
|
||||
// Thus don't fail here on nVidia controllers.
|
||||
//if (controller->pci_info.vendor_id != PCI_VENDOR_NVIDIA)
|
||||
// return B_BUSY;
|
||||
}
|
||||
|
||||
corbReadPointer &= ~CORB_READ_POS_RESET;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
|
||||
for (Index = 0; Index < 10; Index++) {
|
||||
KeStallExecutionProcessor(10);
|
||||
corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) == 0)
|
||||
break;
|
||||
}
|
||||
if ((corbReadPointer & CORB_READ_POS_RESET) != 0) {
|
||||
DPRINT1("hda: CORB read pointer reset failed\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// Reset RIRB write pointer
|
||||
rirbWritePointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) & RIRB_WRITE_POS_RESET;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS), rirbWritePointer | RIRB_WRITE_POS_RESET);
|
||||
|
||||
// Generate interrupt for every response
|
||||
interruptValue = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT)) & HDAC_RESPONSE_INTR_COUNT_MASK;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT), interruptValue | 1);
|
||||
|
||||
// Setup cached read/write indices
|
||||
DeviceExtension->RirbReadPos = 1;
|
||||
DeviceExtension->CorbWritePos = 0;
|
||||
|
||||
// Gentlemen, start your engines...
|
||||
corbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL)) &HDAC_CORB_CONTROL_MASK;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL), corbControl | CORB_CONTROL_RUN | CORB_CONTROL_MEMORY_ERROR_INTR);
|
||||
|
||||
rirbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL)) & HDAC_RIRB_CONTROL_MASK;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL), rirbControl | RIRB_CONTROL_DMA_ENABLE | RIRB_CONTROL_OVERRUN_INTR | RIRB_CONTROL_RESPONSE_INTR);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_ResetController(
|
||||
IN PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
USHORT ValCapabilities;
|
||||
ULONG Index;
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG InputStreams, OutputStreams, BiDirStreams, Control;
|
||||
UCHAR corbControl, rirbControl;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
/* read caps */
|
||||
ValCapabilities = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_GLOBAL_CAP));
|
||||
|
||||
InputStreams = GLOBAL_CAP_INPUT_STREAMS(ValCapabilities);
|
||||
OutputStreams = GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities);
|
||||
BiDirStreams = GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities);
|
||||
|
||||
DPRINT1("NumInputStreams %u\n", InputStreams);
|
||||
DPRINT1("NumOutputStreams %u\n", OutputStreams);
|
||||
DPRINT1("NumBiDirStreams %u\n", BiDirStreams);
|
||||
|
||||
/* stop all streams */
|
||||
for (Index = 0; Index < InputStreams; Index++)
|
||||
{
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_INPUT_STREAM_OFFSET(Index), 0);
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_INPUT_STREAM_OFFSET(Index), 0);
|
||||
}
|
||||
|
||||
for (Index = 0; Index < OutputStreams; Index++) {
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_OUTPUT_STREAM_OFFSET(InputStreams, Index), 0);
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_OUTPUT_STREAM_OFFSET(InputStreams, Index), 0);
|
||||
}
|
||||
|
||||
for (Index = 0; Index < BiDirStreams; Index++) {
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
|
||||
}
|
||||
|
||||
// stop DMA
|
||||
Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL) & HDAC_CORB_CONTROL_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL, Control);
|
||||
|
||||
Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL) & HDAC_RIRB_CONTROL_MASK;
|
||||
WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL, Control);
|
||||
|
||||
for (int timeout = 0; timeout < 10; timeout++) {
|
||||
KeStallExecutionProcessor(10);
|
||||
|
||||
corbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL);
|
||||
rirbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL);
|
||||
if (corbControl == 0 && rirbControl == 0)
|
||||
break;
|
||||
}
|
||||
if (corbControl != 0 || rirbControl != 0) {
|
||||
DPRINT1("hda: unable to stop dma\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// reset DMA position buffer
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), 0);
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), 0);
|
||||
|
||||
// Set reset bit - it must be asserted for at least 100us
|
||||
Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control & ~GLOBAL_CONTROL_RESET);
|
||||
|
||||
for (int timeout = 0; timeout < 10; timeout++) {
|
||||
KeStallExecutionProcessor(10);
|
||||
|
||||
Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
|
||||
if ((Control & GLOBAL_CONTROL_RESET) == 0)
|
||||
break;
|
||||
}
|
||||
if ((Control & GLOBAL_CONTROL_RESET) != 0)
|
||||
{
|
||||
DPRINT1("hda: unable to reset controller\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// Unset reset bit
|
||||
Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control | GLOBAL_CONTROL_RESET);
|
||||
|
||||
for (int timeout = 0; timeout < 10; timeout++) {
|
||||
KeStallExecutionProcessor(10);
|
||||
|
||||
Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
|
||||
if ((Control & GLOBAL_CONTROL_RESET) != 0)
|
||||
break;
|
||||
}
|
||||
if ((Control & GLOBAL_CONTROL_RESET) == 0) {
|
||||
DPRINT1("hda: unable to exit reset\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// Wait for codecs to finish their own reset (apparently needs more
|
||||
// time than documented in the specs)
|
||||
KeStallExecutionProcessor(100);
|
||||
|
||||
// Enable unsolicited responses
|
||||
Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control | GLOBAL_CONTROL_UNSOLICITED);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_QueryId(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
WCHAR DeviceName[200];
|
||||
PHDA_PDO_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG Length;
|
||||
LPWSTR Device;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ASSERT(DeviceExtension->IsFDO == FALSE);
|
||||
|
||||
/* get current irp stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
|
||||
// FIXME
|
||||
swprintf(DeviceName, L"%08x", 1);
|
||||
Length = wcslen(DeviceName) + 20;
|
||||
|
||||
/* allocate result buffer*/
|
||||
Device = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
|
||||
if (!Device)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
swprintf(Device, L"%08x", 1);
|
||||
|
||||
DPRINT1("ID: %S\n", Device);
|
||||
/* store result */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Device;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID ||
|
||||
IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
|
||||
{
|
||||
|
||||
/* calculate size */
|
||||
swprintf(DeviceName, L"HDAUDIO\\FUNC_%02X&VEN_%04X&DEV_%04X&SUBSYS_%08X", DeviceExtension->AudioGroup->FunctionGroup, DeviceExtension->Codec->VendorId, DeviceExtension->Codec->ProductId, DeviceExtension->Codec->VendorId << 16 | DeviceExtension->Codec->ProductId);
|
||||
Length = wcslen(DeviceName) + 20;
|
||||
|
||||
/* allocate result buffer*/
|
||||
Device = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
|
||||
if (!Device)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
wcscpy(Device, DeviceName);
|
||||
|
||||
DPRINT1("ID: %S\n", Device);
|
||||
/* store result */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Device;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
|
||||
{
|
||||
RtlZeroMemory(DeviceName, sizeof(DeviceName));
|
||||
Length = swprintf(DeviceName, L"HDAUDIO\\FUNC_%02X&VEN_%04X&DEV_%04X&REV_%04X", DeviceExtension->AudioGroup->FunctionGroup, DeviceExtension->Codec->VendorId, DeviceExtension->Codec->ProductId, DeviceExtension->Codec->Major << 12 | DeviceExtension->Codec->Minor << 8 | DeviceExtension->Codec->Revision) + 1;
|
||||
Length += swprintf(&DeviceName[Length], L"HDAUDIO\\FUNC_%02X&VEN_%04X&DEV_%04X", DeviceExtension->AudioGroup->FunctionGroup, DeviceExtension->Codec->VendorId, DeviceExtension->Codec->ProductId) + 1;
|
||||
Length += swprintf(&DeviceName[Length], L"HDAUDIO\\FUNC_%02X&VEN_%04X", DeviceExtension->AudioGroup->FunctionGroup, DeviceExtension->Codec->VendorId) + 1;
|
||||
Length += swprintf(&DeviceName[Length], L"HDAUDIO\\FUNC_%02X&VEN_%04X", DeviceExtension->AudioGroup->FunctionGroup) + 2;
|
||||
|
||||
/* allocate result buffer*/
|
||||
Device = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
|
||||
if (!Device)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
RtlCopyMemory(Device, DeviceName, Length * sizeof(WCHAR));
|
||||
|
||||
DPRINT1("ID: %S\n", Device);
|
||||
/* store result */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Device;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("QueryID Type %x not implemented\n", IoStack->Parameters.QueryId.IdType);
|
||||
return Irp->IoStatus.Status;
|
||||
}
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_StartDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
PCM_RESOURCE_LIST Resources;
|
||||
ULONG Index;
|
||||
USHORT Value;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ASSERT(DeviceExtension->IsFDO == TRUE);
|
||||
|
||||
/* forward irp to lower device */
|
||||
Status = HDA_SyncForwardIrp(DeviceExtension->LowerDevice, Irp);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
// failed to start
|
||||
DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* get current irp stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
Resources = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
|
||||
for (Index = 0; Index < Resources->List[0].PartialResourceList.Count; Index++)
|
||||
{
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &Resources->List[0].PartialResourceList.PartialDescriptors[Index];
|
||||
|
||||
if (Descriptor->Type == CmResourceTypeMemory)
|
||||
{
|
||||
DeviceExtension->RegBase = (PUCHAR)MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached);
|
||||
if (DeviceExtension->RegBase == NULL)
|
||||
{
|
||||
DPRINT1("[HDAB] Failed to map registers\n");
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Descriptor->Type == CmResourceTypeInterrupt)
|
||||
{
|
||||
Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
|
||||
HDA_InterruptService,
|
||||
(PVOID)DeviceExtension,
|
||||
NULL,
|
||||
Descriptor->u.Interrupt.Vector,
|
||||
Descriptor->u.Interrupt.Level,
|
||||
Descriptor->u.Interrupt.Level,
|
||||
(KINTERRUPT_MODE)(Descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED),
|
||||
(Descriptor->ShareDisposition != CmResourceShareDeviceExclusive),
|
||||
Descriptor->u.Interrupt.Affinity,
|
||||
FALSE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("[HDAB] Failed to connect interrupt\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
// Get controller into valid state
|
||||
Status = HDA_ResetController(DeviceObject);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
// Setup CORB/RIRB/DMA POS
|
||||
Status = HDA_InitCorbRirbPos(DeviceObject);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
|
||||
// Don't enable codec state change interrupts. We don't handle
|
||||
// them, as we want to use the STATE_STATUS register to identify
|
||||
// available codecs. We'd have to clear that register in the interrupt
|
||||
// handler to 'ack' the codec change.
|
||||
Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE)) & HDAC_WAKE_ENABLE_MASK;
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE), Value);
|
||||
|
||||
// Enable controller interrupts
|
||||
WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_CONTROL), INTR_CONTROL_GLOBAL_ENABLE | INTR_CONTROL_CONTROLLER_ENABLE);
|
||||
|
||||
KeStallExecutionProcessor(100);
|
||||
|
||||
Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS));
|
||||
if (!Value) {
|
||||
DPRINT1("hda: bad codec status\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS), Value);
|
||||
|
||||
// Create codecs
|
||||
DPRINT1("Codecs %lx\n", Value);
|
||||
for (Index = 0; Index < HDA_MAX_CODECS; Index++) {
|
||||
if ((Value & (1 << Index)) != 0) {
|
||||
HDA_InitCodec(DeviceObject, Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_QueryBusRelations(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
ULONG DeviceCount, CodecIndex, AFGIndex;
|
||||
PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
|
||||
PHDA_CODEC_ENTRY Codec;
|
||||
PDEVICE_RELATIONS DeviceRelations;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ASSERT(DeviceExtension->IsFDO == TRUE);
|
||||
|
||||
DeviceCount = 0;
|
||||
for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
|
||||
{
|
||||
if (DeviceExtension->Codecs[CodecIndex] == NULL)
|
||||
continue;
|
||||
|
||||
Codec = DeviceExtension->Codecs[CodecIndex];
|
||||
DeviceCount += Codec->AudioGroupCount;
|
||||
}
|
||||
|
||||
if (DeviceCount == 0)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? sizeof(PDEVICE_OBJECT) * (DeviceCount - 1) : 0));
|
||||
if (!DeviceRelations)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DeviceCount = 0;
|
||||
for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
|
||||
{
|
||||
if (DeviceExtension->Codecs[CodecIndex] == NULL)
|
||||
continue;
|
||||
|
||||
Codec = DeviceExtension->Codecs[CodecIndex];
|
||||
for (AFGIndex = 0; AFGIndex < Codec->AudioGroupCount; AFGIndex++)
|
||||
{
|
||||
DeviceRelations->Objects[DeviceRelations->Count] = Codec->AudioGroups[AFGIndex]->ChildPDO;
|
||||
ObReferenceObject(Codec->AudioGroups[AFGIndex]->ChildPDO);
|
||||
DeviceRelations->Count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME handle existing device relations */
|
||||
ASSERT(Irp->IoStatus.Information == 0);
|
||||
|
||||
/* store device relations */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
HDA_QueryBusInformation(
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PPNP_BUS_INFORMATION BusInformation;
|
||||
|
||||
/* allocate bus information */
|
||||
BusInformation = (PPNP_BUS_INFORMATION)AllocateItem(PagedPool, sizeof(PNP_BUS_INFORMATION));
|
||||
|
||||
if (!BusInformation)
|
||||
{
|
||||
/* no memory */
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* return info */
|
||||
BusInformation->BusNumber = 0;
|
||||
BusInformation->LegacyBusType = PCIBus;
|
||||
RtlMoveMemory(&BusInformation->BusTypeGuid, &GUID_HDAUDIO_BUS_INTERFACE, sizeof(GUID));
|
||||
|
||||
/* store result */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
HDA_QueryBusDeviceCapabilities(
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PDEVICE_CAPABILITIES Capabilities;
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
|
||||
/* get stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
/* get capabilities */
|
||||
Capabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
|
||||
|
||||
RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
|
||||
|
||||
/* setup capabilities */
|
||||
Capabilities->UniqueID = TRUE;
|
||||
Capabilities->SilentInstall = TRUE;
|
||||
Capabilities->SurpriseRemovalOK = TRUE;
|
||||
Capabilities->Address = 0;
|
||||
Capabilities->UINumber = 0;
|
||||
Capabilities->SystemWake = PowerSystemWorking; /* FIXME common device extension */
|
||||
Capabilities->DeviceWake = PowerDeviceD0;
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
HDA_QueryBusDevicePnpState(
|
||||
IN PIRP Irp)
|
||||
{
|
||||
/* set device flags */
|
||||
Irp->IoStatus.Information = PNP_DEVICE_DONT_DISPLAY_IN_UI | PNP_DEVICE_NOT_DISABLEABLE;
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
HDA_PdoHandleQueryDeviceText(
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
LPWSTR Buffer;
|
||||
static WCHAR DeviceText[] = L"Audio Device on High Definition Audio Bus";
|
||||
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
if (IoStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription)
|
||||
{
|
||||
DPRINT("HDA_PdoHandleQueryDeviceText DeviceTextDescription\n");
|
||||
|
||||
Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
|
||||
if (!Buffer)
|
||||
{
|
||||
Irp->IoStatus.Information = 0;
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
wcscpy(Buffer, DeviceText);
|
||||
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("HDA_PdoHandleQueryDeviceText DeviceTextLocationInformation\n");
|
||||
|
||||
Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
|
||||
if (!Buffer)
|
||||
{
|
||||
Irp->IoStatus.Information = 0;
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
wcscpy(Buffer, DeviceText);
|
||||
|
||||
/* save result */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_Pnp(
|
||||
|
@ -982,7 +105,7 @@ HDA_Pnp(
|
|||
if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
|
||||
{
|
||||
DPRINT1("IRP_MN_START_DEVICE\n");
|
||||
Status = HDA_StartDevice(DeviceObject, Irp);
|
||||
Status = HDA_FDOStartDevice(DeviceObject, Irp);
|
||||
}
|
||||
else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS)
|
||||
{
|
||||
|
@ -990,7 +113,7 @@ HDA_Pnp(
|
|||
/* handle bus device relations */
|
||||
if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations)
|
||||
{
|
||||
Status = HDA_QueryBusRelations(DeviceObject, Irp);
|
||||
Status = HDA_FDOQueryBusRelations(DeviceObject, Irp);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1015,13 +138,13 @@ HDA_Pnp(
|
|||
{
|
||||
DPRINT1("IRP_MN_QUERY_BUS_INFORMATION\n");
|
||||
/* query bus information */
|
||||
Status = HDA_QueryBusInformation(Irp);
|
||||
Status = HDA_PDOQueryBusInformation(Irp);
|
||||
}
|
||||
else if (IoStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
|
||||
{
|
||||
DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE\n");
|
||||
/* query pnp state */
|
||||
Status = HDA_QueryBusDevicePnpState(Irp);
|
||||
Status = HDA_PDOQueryBusDevicePnpState(Irp);
|
||||
}
|
||||
else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS)
|
||||
{
|
||||
|
@ -1059,7 +182,7 @@ HDA_Pnp(
|
|||
{
|
||||
DPRINT1("IRP_MN_QUERY_CAPABILITIES\n");
|
||||
/* query capabilities */
|
||||
Status = HDA_QueryBusDeviceCapabilities(Irp);
|
||||
Status = HDA_PDOQueryBusDeviceCapabilities(Irp);
|
||||
}
|
||||
else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
|
||||
{
|
||||
|
@ -1067,15 +190,26 @@ HDA_Pnp(
|
|||
/* no op */
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCES)
|
||||
{
|
||||
DPRINT1("IRP_MN_QUERY_RESOURCES\n");
|
||||
/* no op */
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
else if (IoStack->MinorFunction == IRP_MN_QUERY_ID)
|
||||
{
|
||||
DPRINT1("IRP_MN_QUERY_ID\n");
|
||||
Status = HDA_QueryId(DeviceObject, Irp);
|
||||
Status = HDA_PDOQueryId(DeviceObject, Irp);
|
||||
}
|
||||
else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_TEXT)
|
||||
{
|
||||
DPRINT1("IRP_MN_QUERY_DEVICE_TEXT\n");
|
||||
Status = HDA_PdoHandleQueryDeviceText(Irp);
|
||||
Status = HDA_PDOHandleQueryDeviceText(Irp);
|
||||
}
|
||||
else if (IoStack->MinorFunction == IRP_MN_QUERY_INTERFACE)
|
||||
{
|
||||
DPRINT1("IRP_MN_QUERY_INTERFACE\n");
|
||||
Status = HDA_PDOHandleQueryInterface(DeviceObject, Irp);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1120,7 +254,6 @@ IN PDEVICE_OBJECT PhysicalDeviceObject)
|
|||
DeviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
|
||||
RtlZeroMemory(DeviceExtension->Codecs, sizeof(PHDA_CODEC_ENTRY) * (HDA_MAX_CODECS + 1));
|
||||
|
||||
|
||||
/* set device flags */
|
||||
DeviceObject->Flags |= DO_POWER_PAGABLE;
|
||||
|
||||
|
|
|
@ -101,3 +101,72 @@ typedef struct {
|
|||
ULONG start : 8;
|
||||
ULONG _reserved2 : 8;
|
||||
}CODEC_RESPONSE, *PCODEC_RESPONSE;
|
||||
|
||||
|
||||
PVOID
|
||||
AllocateItem(
|
||||
IN POOL_TYPE PoolType,
|
||||
IN SIZE_T NumberOfBytes);
|
||||
|
||||
VOID
|
||||
FreeItem(
|
||||
IN PVOID Item);
|
||||
|
||||
/* fdo.cpp */
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
HDA_InterruptService(
|
||||
IN PKINTERRUPT Interrupt,
|
||||
IN PVOID ServiceContext);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_FDOStartDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_FDOQueryBusRelations(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
/* pdo.cpp*/
|
||||
|
||||
NTSTATUS
|
||||
HDA_PDOQueryBusInformation(
|
||||
IN PIRP Irp);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_PDOQueryId(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
NTSTATUS
|
||||
HDA_PDOHandleQueryDeviceText(
|
||||
IN PIRP Irp);
|
||||
|
||||
NTSTATUS
|
||||
HDA_PDOQueryBusDeviceCapabilities(
|
||||
IN PIRP Irp);
|
||||
|
||||
NTSTATUS
|
||||
HDA_PDOQueryBusDevicePnpState(
|
||||
IN PIRP Irp);
|
||||
|
||||
/* businterface.cpp */
|
||||
|
||||
NTSTATUS
|
||||
HDA_PDOHandleQueryInterface(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
/* hdaudbus.cpp*/
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_SyncForwardIrp(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
|
|
208
reactos/drivers/wdm/audio/hdaudbus/pdo.cpp
Normal file
208
reactos/drivers/wdm/audio/hdaudbus/pdo.cpp
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel Streaming
|
||||
* FILE: drivers/wdm/audio/hdaudbus/pdo.cpp
|
||||
* PURPOSE: HDA Driver Entry
|
||||
* PROGRAMMER: Johannes Anderwald
|
||||
*/
|
||||
#include "hdaudbus.h"
|
||||
|
||||
NTSTATUS
|
||||
HDA_PDOQueryBusInformation(
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PPNP_BUS_INFORMATION BusInformation;
|
||||
|
||||
/* allocate bus information */
|
||||
BusInformation = (PPNP_BUS_INFORMATION)AllocateItem(PagedPool, sizeof(PNP_BUS_INFORMATION));
|
||||
|
||||
if (!BusInformation)
|
||||
{
|
||||
/* no memory */
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* return info */
|
||||
BusInformation->BusNumber = 0;
|
||||
BusInformation->LegacyBusType = PCIBus;
|
||||
RtlMoveMemory(&BusInformation->BusTypeGuid, &GUID_HDAUDIO_BUS_INTERFACE, sizeof(GUID));
|
||||
|
||||
/* store result */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
HDA_PDOQueryId(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
WCHAR DeviceName[200];
|
||||
PHDA_PDO_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG Length;
|
||||
LPWSTR Device;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ASSERT(DeviceExtension->IsFDO == FALSE);
|
||||
|
||||
/* get current irp stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
|
||||
// FIXME
|
||||
swprintf(DeviceName, L"%08x", 1);
|
||||
Length = wcslen(DeviceName) + 20;
|
||||
|
||||
/* allocate result buffer*/
|
||||
Device = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
|
||||
if (!Device)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
swprintf(Device, L"%08x", 1);
|
||||
|
||||
DPRINT1("ID: %S\n", Device);
|
||||
/* store result */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Device;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID ||
|
||||
IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
|
||||
{
|
||||
|
||||
/* calculate size */
|
||||
swprintf(DeviceName, L"HDAUDIO\\FUNC_%02X&VEN_%04X&DEV_%04X&SUBSYS_%08X", DeviceExtension->AudioGroup->FunctionGroup, DeviceExtension->Codec->VendorId, DeviceExtension->Codec->ProductId, DeviceExtension->Codec->VendorId << 16 | DeviceExtension->Codec->ProductId);
|
||||
Length = wcslen(DeviceName) + 20;
|
||||
|
||||
/* allocate result buffer*/
|
||||
Device = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
|
||||
if (!Device)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
wcscpy(Device, DeviceName);
|
||||
|
||||
DPRINT1("ID: %S\n", Device);
|
||||
/* store result */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Device;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
|
||||
{
|
||||
RtlZeroMemory(DeviceName, sizeof(DeviceName));
|
||||
Length = swprintf(DeviceName, L"HDAUDIO\\FUNC_%02X&VEN_%04X&DEV_%04X&REV_%04X", DeviceExtension->AudioGroup->FunctionGroup, DeviceExtension->Codec->VendorId, DeviceExtension->Codec->ProductId, DeviceExtension->Codec->Major << 12 | DeviceExtension->Codec->Minor << 8 | DeviceExtension->Codec->Revision) + 1;
|
||||
Length += swprintf(&DeviceName[Length], L"HDAUDIO\\FUNC_%02X&VEN_%04X&DEV_%04X", DeviceExtension->AudioGroup->FunctionGroup, DeviceExtension->Codec->VendorId, DeviceExtension->Codec->ProductId) + 1;
|
||||
Length += swprintf(&DeviceName[Length], L"HDAUDIO\\FUNC_%02X&VEN_%04X", DeviceExtension->AudioGroup->FunctionGroup, DeviceExtension->Codec->VendorId) + 1;
|
||||
Length += swprintf(&DeviceName[Length], L"HDAUDIO\\FUNC_%02X&VEN_%04X", DeviceExtension->AudioGroup->FunctionGroup) + 2;
|
||||
|
||||
/* allocate result buffer*/
|
||||
Device = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
|
||||
if (!Device)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
RtlCopyMemory(Device, DeviceName, Length * sizeof(WCHAR));
|
||||
|
||||
DPRINT1("ID: %S\n", Device);
|
||||
/* store result */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Device;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("QueryID Type %x not implemented\n", IoStack->Parameters.QueryId.IdType);
|
||||
return Irp->IoStatus.Status;
|
||||
}
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
HDA_PDOHandleQueryDeviceText(
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
LPWSTR Buffer;
|
||||
static WCHAR DeviceText[] = L"Audio Device on High Definition Audio Bus";
|
||||
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
if (IoStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription)
|
||||
{
|
||||
DPRINT("HDA_PdoHandleQueryDeviceText DeviceTextDescription\n");
|
||||
|
||||
Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
|
||||
if (!Buffer)
|
||||
{
|
||||
Irp->IoStatus.Information = 0;
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
wcscpy(Buffer, DeviceText);
|
||||
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("HDA_PdoHandleQueryDeviceText DeviceTextLocationInformation\n");
|
||||
|
||||
Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
|
||||
if (!Buffer)
|
||||
{
|
||||
Irp->IoStatus.Information = 0;
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
wcscpy(Buffer, DeviceText);
|
||||
|
||||
/* save result */
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
HDA_PDOQueryBusDeviceCapabilities(
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PDEVICE_CAPABILITIES Capabilities;
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
|
||||
/* get stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
/* get capabilities */
|
||||
Capabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
|
||||
|
||||
RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
|
||||
|
||||
/* setup capabilities */
|
||||
Capabilities->UniqueID = TRUE;
|
||||
Capabilities->SilentInstall = TRUE;
|
||||
Capabilities->SurpriseRemovalOK = TRUE;
|
||||
Capabilities->Address = 0;
|
||||
Capabilities->UINumber = 0;
|
||||
Capabilities->SystemWake = PowerSystemWorking; /* FIXME common device extension */
|
||||
Capabilities->DeviceWake = PowerDeviceD0;
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
HDA_PDOQueryBusDevicePnpState(
|
||||
IN PIRP Irp)
|
||||
{
|
||||
/* set device flags */
|
||||
Irp->IoStatus.Information = PNP_DEVICE_DONT_DISPLAY_IN_UI | PNP_DEVICE_NOT_DISABLEABLE;
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
Loading…
Reference in a new issue