mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1072 lines
30 KiB
1072 lines
30 KiB
/*****************************************************************************
|
|
* adapter.cpp - SB16 adapter driver implementation.
|
|
*****************************************************************************
|
|
* Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved.
|
|
*
|
|
* This files does setup and resource allocation/verification for the SB16
|
|
* card. It controls which miniports are started and which resources are
|
|
* given to each miniport. It also deals with interrupt sharing between
|
|
* miniports by hooking the interrupt and calling the correct DPC.
|
|
*/
|
|
|
|
//
|
|
// All the GUIDS for all the miniports end up in this object.
|
|
//
|
|
#define PUT_GUIDS_HERE
|
|
|
|
#define STR_MODULENAME "sb16Adapter: "
|
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Defines
|
|
*/
|
|
#define MAX_MINIPORTS 5
|
|
|
|
#if (DBG)
|
|
#define SUCCEEDS(s) ASSERT(NT_SUCCESS(s))
|
|
#else
|
|
#define SUCCEEDS(s) (s)
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Externals
|
|
*/
|
|
NTSTATUS
|
|
CreateMiniportWaveCyclicSB16
|
|
(
|
|
OUT PUNKNOWN * Unknown,
|
|
IN REFCLSID,
|
|
IN PUNKNOWN UnknownOuter OPTIONAL,
|
|
IN POOL_TYPE PoolType
|
|
);
|
|
NTSTATUS
|
|
CreateMiniportTopologySB16
|
|
(
|
|
OUT PUNKNOWN * Unknown,
|
|
IN REFCLSID,
|
|
IN PUNKNOWN UnknownOuter OPTIONAL,
|
|
IN POOL_TYPE PoolType
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Referenced forward
|
|
*/
|
|
extern "C"
|
|
NTSTATUS
|
|
AddDevice
|
|
(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
StartDevice
|
|
(
|
|
IN PDEVICE_OBJECT DeviceObject, // Device object.
|
|
IN PIRP Irp, // IO request packet.
|
|
IN PRESOURCELIST ResourceList // List of hardware resources.
|
|
);
|
|
|
|
NTSTATUS
|
|
AssignResources
|
|
(
|
|
IN PRESOURCELIST ResourceList, // All resources.
|
|
OUT PRESOURCELIST * ResourceListWave, // Wave resources.
|
|
OUT PRESOURCELIST * ResourceListWaveTable, // Wave table resources.
|
|
OUT PRESOURCELIST * ResourceListFmSynth, // FM synth resources.
|
|
OUT PRESOURCELIST * ResourceListUart, // UART resources.
|
|
OUT PRESOURCELIST * ResourceListAdapter // a copy needed by the adapter
|
|
);
|
|
|
|
#ifdef DO_RESOURCE_FILTERING
|
|
extern "C"
|
|
NTSTATUS
|
|
AdapterDispatchPnp
|
|
(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
);
|
|
#endif
|
|
|
|
DWORD DeterminePlatform(PPORTTOPOLOGY Port);
|
|
|
|
|
|
#pragma code_seg("INIT")
|
|
|
|
/*****************************************************************************
|
|
* DriverEntry()
|
|
*****************************************************************************
|
|
* This function is called by the operating system when the driver is loaded.
|
|
* All adapter drivers can use this code without change.
|
|
*/
|
|
extern "C"
|
|
NTSTATUS
|
|
DriverEntry
|
|
(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPathName
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Tell the class driver to initialize the driver.
|
|
//
|
|
NTSTATUS ntStatus = PcInitializeAdapterDriver( DriverObject,
|
|
RegistryPathName,
|
|
AddDevice );
|
|
|
|
#ifdef DO_RESOURCE_FILTERING
|
|
//
|
|
// We want to do resource filtering, so we'll install our own PnP IRP handler.
|
|
//
|
|
if(NT_SUCCESS(ntStatus))
|
|
{
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = AdapterDispatchPnp;
|
|
}
|
|
#endif
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
#pragma code_seg("PAGE")
|
|
/*****************************************************************************
|
|
* AddDevice()
|
|
*****************************************************************************
|
|
* This function is called by the operating system when the device is added.
|
|
* All adapter drivers can use this code without change.
|
|
*/
|
|
extern "C"
|
|
NTSTATUS
|
|
AddDevice
|
|
(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Tell the class driver to add the device.
|
|
//
|
|
return PcAddAdapterDevice( DriverObject,
|
|
PhysicalDeviceObject,
|
|
PCPFNSTARTDEVICE( StartDevice ),
|
|
MAX_MINIPORTS,
|
|
0 );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* InstallSubdevice()
|
|
*****************************************************************************
|
|
* This function creates and registers a subdevice consisting of a port
|
|
* driver, a minport driver and a set of resources bound together. It will
|
|
* also optionally place a pointer to an interface on the port driver in a
|
|
* specified location before initializing the port driver. This is done so
|
|
* that a common ISR can have access to the port driver during initialization,
|
|
* when the ISR might fire.
|
|
*/
|
|
NTSTATUS
|
|
InstallSubdevice
|
|
(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PWCHAR Name,
|
|
IN REFGUID PortClassId,
|
|
IN REFGUID MiniportClassId,
|
|
IN PFNCREATEINSTANCE MiniportCreate OPTIONAL,
|
|
IN PUNKNOWN UnknownAdapter OPTIONAL,
|
|
IN PRESOURCELIST ResourceList,
|
|
IN REFGUID PortInterfaceId,
|
|
OUT PUNKNOWN * OutPortInterface OPTIONAL,
|
|
OUT PUNKNOWN * OutPortUnknown OPTIONAL
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
_DbgPrintF(DEBUGLVL_VERBOSE, ("InstallSubdevice"));
|
|
|
|
ASSERT(DeviceObject);
|
|
ASSERT(Irp);
|
|
ASSERT(Name);
|
|
|
|
//
|
|
// Create the port driver object
|
|
//
|
|
PPORT port;
|
|
NTSTATUS ntStatus = PcNewPort(&port,PortClassId);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// Deposit the port somewhere if it's needed.
|
|
//
|
|
if (OutPortInterface)
|
|
{
|
|
//
|
|
// Failure here doesn't cause the entire routine to fail.
|
|
//
|
|
(void) port->QueryInterface
|
|
(
|
|
PortInterfaceId,
|
|
(PVOID *) OutPortInterface
|
|
);
|
|
}
|
|
|
|
PUNKNOWN miniport;
|
|
//
|
|
// Create the miniport object
|
|
//
|
|
if (MiniportCreate)
|
|
{
|
|
ntStatus = MiniportCreate
|
|
(
|
|
&miniport,
|
|
MiniportClassId,
|
|
NULL,
|
|
NonPagedPool
|
|
);
|
|
}
|
|
else
|
|
{
|
|
ntStatus = PcNewMiniport((PMINIPORT*) &miniport,MiniportClassId);
|
|
}
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// Init the port driver and miniport in one go.
|
|
//
|
|
ntStatus = port->Init( DeviceObject,
|
|
Irp,
|
|
miniport,
|
|
UnknownAdapter,
|
|
ResourceList );
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// Register the subdevice (port/miniport combination).
|
|
//
|
|
ntStatus = PcRegisterSubdevice( DeviceObject,
|
|
Name,
|
|
port );
|
|
if (!(NT_SUCCESS(ntStatus)))
|
|
{
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("StartDevice: PcRegisterSubdevice failed"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("InstallSubdevice: port->Init failed"));
|
|
}
|
|
|
|
//
|
|
// We don't need the miniport any more. Either the port has it,
|
|
// or we've failed, and it should be deleted.
|
|
//
|
|
miniport->Release();
|
|
}
|
|
else
|
|
{
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("InstallSubdevice: PcNewMiniport failed"));
|
|
}
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// Deposit the port as an unknown if it's needed.
|
|
//
|
|
if (OutPortUnknown)
|
|
{
|
|
//
|
|
// Failure here doesn't cause the entire routine to fail.
|
|
//
|
|
(void) port->QueryInterface
|
|
(
|
|
IID_IUnknown,
|
|
(PVOID *) OutPortUnknown
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Retract previously delivered port interface.
|
|
//
|
|
if (OutPortInterface && (*OutPortInterface))
|
|
{
|
|
(*OutPortInterface)->Release();
|
|
*OutPortInterface = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release the reference which existed when PcNewPort() gave us the
|
|
// pointer in the first place. This is the right thing to do
|
|
// regardless of the outcome.
|
|
//
|
|
port->Release();
|
|
}
|
|
else
|
|
{
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("InstallSubdevice: PcNewPort failed"));
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* StartDevice()
|
|
*****************************************************************************
|
|
* This function is called by the operating system when the device is started.
|
|
* It is responsible for starting the miniports. This code is specific to
|
|
* the adapter because it calls out miniports for functions that are specific
|
|
* to the adapter.
|
|
*/
|
|
NTSTATUS
|
|
StartDevice
|
|
(
|
|
IN PDEVICE_OBJECT DeviceObject, // Device object.
|
|
IN PIRP Irp, // IO request packet.
|
|
IN PRESOURCELIST ResourceList // List of hardware resources.
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
|
|
ASSERT(DeviceObject);
|
|
ASSERT(Irp);
|
|
ASSERT(ResourceList);
|
|
|
|
//
|
|
// These are the sub-lists of resources that will be handed to the
|
|
// miniports.
|
|
//
|
|
PRESOURCELIST resourceListWave = NULL;
|
|
PRESOURCELIST resourceListWaveTable = NULL;
|
|
PRESOURCELIST resourceListFmSynth = NULL;
|
|
PRESOURCELIST resourceListUart = NULL;
|
|
PRESOURCELIST resourceListAdapter = NULL;
|
|
|
|
//
|
|
// These are the port driver pointers we are keeping around for registering
|
|
// physical connections.
|
|
//
|
|
PUNKNOWN unknownTopology = NULL;
|
|
PUNKNOWN unknownWave = NULL;
|
|
PUNKNOWN unknownWaveTable = NULL;
|
|
PUNKNOWN unknownFmSynth = NULL;
|
|
|
|
//
|
|
// Assign resources to individual miniports. Each sub-list is a copy
|
|
// of the resources from the master list. Each sublist must be released.
|
|
//
|
|
NTSTATUS ntStatus = AssignResources( ResourceList,
|
|
&resourceListWave,
|
|
&resourceListWaveTable,
|
|
&resourceListFmSynth,
|
|
&resourceListUart,
|
|
&resourceListAdapter );
|
|
|
|
//
|
|
// if AssignResources succeeded...
|
|
//
|
|
if(NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// If the adapter has resources...
|
|
//
|
|
PADAPTERCOMMON pAdapterCommon = NULL;
|
|
if (resourceListAdapter)
|
|
{
|
|
PUNKNOWN pUnknownCommon;
|
|
|
|
// create a new adapter common object
|
|
ntStatus = NewAdapterCommon( &pUnknownCommon,
|
|
IID_IAdapterCommon,
|
|
NULL,
|
|
NonPagedPool );
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ASSERT( pUnknownCommon );
|
|
|
|
// query for the IAdapterCommon interface
|
|
ntStatus = pUnknownCommon->QueryInterface( IID_IAdapterCommon,
|
|
(PVOID *)&pAdapterCommon );
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
// Initialize the object
|
|
ntStatus = pAdapterCommon->Init( resourceListAdapter,
|
|
DeviceObject );
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
// register with PortCls for power-management services
|
|
ntStatus = PcRegisterAdapterPowerManagement( (PUNKNOWN)pAdapterCommon,
|
|
DeviceObject );
|
|
}
|
|
}
|
|
|
|
// release the IUnknown on adapter common
|
|
pUnknownCommon->Release();
|
|
}
|
|
|
|
// release the adapter common resource list
|
|
resourceListAdapter->Release();
|
|
}
|
|
|
|
//
|
|
// Start the topology miniport.
|
|
//
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus = InstallSubdevice( DeviceObject,
|
|
Irp,
|
|
L"Topology",
|
|
CLSID_PortTopology,
|
|
CLSID_PortTopology, // not used
|
|
CreateMiniportTopologySB16,
|
|
pAdapterCommon,
|
|
NULL,
|
|
GUID_NULL,
|
|
NULL,
|
|
&unknownTopology );
|
|
}
|
|
|
|
//
|
|
// Start the SB wave miniport if it exists.
|
|
//
|
|
if (resourceListWave)
|
|
{
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus = InstallSubdevice( DeviceObject,
|
|
Irp,
|
|
L"Wave",
|
|
CLSID_PortWaveCyclic,
|
|
CLSID_PortWaveCyclic, // not used
|
|
CreateMiniportWaveCyclicSB16,
|
|
pAdapterCommon,
|
|
resourceListWave,
|
|
IID_IPortWaveCyclic,
|
|
NULL,
|
|
&unknownWave );
|
|
}
|
|
|
|
// release the wave resource list
|
|
resourceListWave->Release();
|
|
}
|
|
|
|
// Start the wave table miniport if it exists.
|
|
if (resourceListWaveTable)
|
|
{
|
|
//
|
|
// NOTE: The wavetable is not currently supported in this sample driver.
|
|
//
|
|
|
|
// release the wavetable resource list
|
|
resourceListWaveTable->Release();
|
|
}
|
|
|
|
//
|
|
// Start the FM synth miniport if it exists.
|
|
//
|
|
if (resourceListFmSynth)
|
|
{
|
|
//
|
|
// Synth not working yet.
|
|
//
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// Failure here is not fatal.
|
|
//
|
|
InstallSubdevice( DeviceObject,
|
|
Irp,
|
|
L"FMSynth",
|
|
CLSID_PortMidi,
|
|
CLSID_MiniportDriverFmSynth,
|
|
NULL,
|
|
pAdapterCommon,
|
|
resourceListFmSynth,
|
|
GUID_NULL,
|
|
NULL,
|
|
&unknownFmSynth );
|
|
}
|
|
|
|
// release the FM synth resource list
|
|
resourceListFmSynth->Release();
|
|
}
|
|
|
|
//
|
|
// Start the UART miniport if it exists.
|
|
//
|
|
if (resourceListUart)
|
|
{
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// Failure here is not fatal.
|
|
//
|
|
InstallSubdevice( DeviceObject,
|
|
Irp,
|
|
L"Uart",
|
|
CLSID_PortDMus,
|
|
CLSID_MiniportDriverDMusUART,
|
|
NULL,
|
|
pAdapterCommon->GetInterruptSync(),
|
|
resourceListUart,
|
|
IID_IPortDMus,
|
|
NULL, // interface to port not needed
|
|
NULL ); // not physically connected to anything
|
|
}
|
|
|
|
resourceListUart->Release();
|
|
}
|
|
|
|
//
|
|
// Establish physical connections between filters as shown.
|
|
//
|
|
// +------+ +------+
|
|
// | Wave | | Topo |
|
|
// Capture <---|0 1|<===|6 2|<--- CD
|
|
// | | | |
|
|
// Render --->|2 3|===>|0 3|<--- Line In
|
|
// +------+ | |
|
|
// +------+ | 4|<--- Mic
|
|
// | FM | | |
|
|
// MIDI --->|0 1|===>|1 5|---> Line Out
|
|
// +------+ +------+
|
|
//
|
|
if (unknownTopology)
|
|
{
|
|
DWORD version = DeterminePlatform((PPORTTOPOLOGY)unknownTopology);
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Detected platform version 0x%02X",version));
|
|
|
|
if (unknownWave)
|
|
{
|
|
// register wave <=> topology connections
|
|
PcRegisterPhysicalConnection( (PDEVICE_OBJECT)DeviceObject,
|
|
unknownTopology,
|
|
6,
|
|
unknownWave,
|
|
1 );
|
|
PcRegisterPhysicalConnection( (PDEVICE_OBJECT)DeviceObject,
|
|
unknownWave,
|
|
3,
|
|
unknownTopology,
|
|
0 );
|
|
}
|
|
|
|
if (unknownFmSynth)
|
|
{
|
|
// register fmsynth <=> topology connection
|
|
PcRegisterPhysicalConnection( (PDEVICE_OBJECT)DeviceObject,
|
|
unknownFmSynth,
|
|
1,
|
|
unknownTopology,
|
|
1 );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release the adapter common object. It either has other references,
|
|
// or we need to delete it anyway.
|
|
//
|
|
if (pAdapterCommon)
|
|
{
|
|
pAdapterCommon->Release();
|
|
}
|
|
|
|
//
|
|
// Release the unknowns.
|
|
//
|
|
if (unknownTopology)
|
|
{
|
|
unknownTopology->Release();
|
|
}
|
|
if (unknownWave)
|
|
{
|
|
unknownWave->Release();
|
|
}
|
|
if (unknownWaveTable)
|
|
{
|
|
unknownWaveTable->Release();
|
|
}
|
|
if (unknownFmSynth)
|
|
{
|
|
unknownFmSynth->Release();
|
|
}
|
|
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* AssignResources()
|
|
*****************************************************************************
|
|
* This function assigns the list of resources to the various functions on
|
|
* the card. This code is specific to the adapter. All the non-NULL resource
|
|
* lists handed back must be released by the caller.
|
|
*/
|
|
NTSTATUS
|
|
AssignResources
|
|
(
|
|
IN PRESOURCELIST ResourceList, // All resources.
|
|
OUT PRESOURCELIST * ResourceListWave, // Wave resources.
|
|
OUT PRESOURCELIST * ResourceListWaveTable, // Wave table resources.
|
|
OUT PRESOURCELIST * ResourceListFmSynth, // FM synth resources.
|
|
OUT PRESOURCELIST * ResourceListUart, // Uart resources.
|
|
OUT PRESOURCELIST * ResourceListAdapter // For the adapter
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
BOOLEAN detectedWaveTable = FALSE;
|
|
BOOLEAN detectedUart = FALSE;
|
|
BOOLEAN detectedFmSynth = FALSE;
|
|
|
|
//
|
|
// Get counts for the types of resources.
|
|
//
|
|
ULONG countIO = ResourceList->NumberOfPorts();
|
|
ULONG countIRQ = ResourceList->NumberOfInterrupts();
|
|
ULONG countDMA = ResourceList->NumberOfDmas();
|
|
|
|
//
|
|
// Determine the type of card based on port resources.
|
|
// TODO: Detect wave table.
|
|
//
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
switch (countIO)
|
|
{
|
|
case 1:
|
|
//
|
|
// No FM synth or UART.
|
|
//
|
|
if ( (ResourceList->FindTranslatedPort(0)->u.Port.Length < 16)
|
|
|| (countIRQ < 1)
|
|
|| (countDMA < 1)
|
|
)
|
|
{
|
|
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
//
|
|
// MPU-401 or FM synth, not both.
|
|
//
|
|
if ( (ResourceList->FindTranslatedPort(0)->u.Port.Length < 16)
|
|
|| (countIRQ < 1)
|
|
|| (countDMA < 1)
|
|
)
|
|
{
|
|
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Length of second port indicates which function.
|
|
//
|
|
switch (ResourceList->FindTranslatedPort(1)->u.Port.Length)
|
|
{
|
|
case 2:
|
|
detectedUart = TRUE;
|
|
break;
|
|
|
|
case 4:
|
|
detectedFmSynth = TRUE;
|
|
break;
|
|
|
|
default:
|
|
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
//
|
|
// Both MPU-401 and FM synth.
|
|
//
|
|
if ( (ResourceList->FindTranslatedPort(0)->u.Port.Length < 16)
|
|
|| (ResourceList->FindTranslatedPort(1)->u.Port.Length != 2)
|
|
|| (ResourceList->FindTranslatedPort(2)->u.Port.Length != 4)
|
|
|| (countIRQ < 1)
|
|
|| (countDMA < 1)
|
|
)
|
|
{
|
|
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
|
|
}
|
|
else
|
|
{
|
|
detectedUart = TRUE;
|
|
detectedFmSynth = TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Build the resource list for the SB wave I/O.
|
|
//
|
|
*ResourceListWave = NULL;
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus =
|
|
PcNewResourceSublist
|
|
(
|
|
ResourceListWave,
|
|
NULL,
|
|
PagedPool,
|
|
ResourceList,
|
|
countDMA + countIRQ + 1
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ULONG i;
|
|
|
|
//
|
|
// Add the base address
|
|
//
|
|
ntStatus = (*ResourceListWave)->
|
|
AddPortFromParent(ResourceList,0);
|
|
|
|
//
|
|
// Add the DMA channel(s).
|
|
//
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
for (i = 0; i < countDMA; i++)
|
|
{
|
|
ntStatus = (*ResourceListWave)->
|
|
AddDmaFromParent(ResourceList,i);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the IRQ lines.
|
|
//
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
for (i = 0; i < countIRQ; i++)
|
|
{
|
|
SUCCEEDS((*ResourceListWave)->
|
|
AddInterruptFromParent(ResourceList,i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Build list of resources for wave table.
|
|
//
|
|
*ResourceListWaveTable = NULL;
|
|
if (NT_SUCCESS(ntStatus) && detectedWaveTable)
|
|
{
|
|
//
|
|
// TODO: Assign wave table resources.
|
|
//
|
|
}
|
|
|
|
//
|
|
// Build list of resources for UART.
|
|
//
|
|
*ResourceListUart = NULL;
|
|
if (NT_SUCCESS(ntStatus) && detectedUart)
|
|
{
|
|
ntStatus =
|
|
PcNewResourceSublist
|
|
(
|
|
ResourceListUart,
|
|
NULL,
|
|
PagedPool,
|
|
ResourceList,
|
|
2
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus = (*ResourceListUart)->
|
|
AddPortFromParent(ResourceList,1);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus = (*ResourceListUart)->
|
|
AddInterruptFromParent(ResourceList,0);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Build list of resources for FM synth.
|
|
//
|
|
*ResourceListFmSynth = NULL;
|
|
if (NT_SUCCESS(ntStatus) && detectedFmSynth)
|
|
{
|
|
ntStatus =
|
|
PcNewResourceSublist
|
|
(
|
|
ResourceListFmSynth,
|
|
NULL,
|
|
PagedPool,
|
|
ResourceList,
|
|
1
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus = (*ResourceListFmSynth)->
|
|
AddPortFromParent(ResourceList,detectedUart ? 2 : 1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Build list of resources for the adapter.
|
|
//
|
|
*ResourceListAdapter = NULL;
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus =
|
|
PcNewResourceSublist
|
|
(
|
|
ResourceListAdapter,
|
|
NULL,
|
|
PagedPool,
|
|
ResourceList,
|
|
3
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// The interrupt to share.
|
|
//
|
|
ntStatus = (*ResourceListAdapter)->
|
|
AddInterruptFromParent(ResourceList,0);
|
|
|
|
//
|
|
// The base IO port (to tell who's interrupt it is)
|
|
//
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus = (*ResourceListAdapter)->
|
|
AddPortFromParent(ResourceList,0);
|
|
}
|
|
|
|
if (detectedUart && NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// The Uart port
|
|
//
|
|
ntStatus = (*ResourceListAdapter)->
|
|
AddPortFromParent(ResourceList,1);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean up if failure occurred.
|
|
//
|
|
if (! NT_SUCCESS(ntStatus))
|
|
{
|
|
if (*ResourceListWave)
|
|
{
|
|
(*ResourceListWave)->Release();
|
|
*ResourceListWave = NULL;
|
|
}
|
|
if (*ResourceListWaveTable)
|
|
{
|
|
(*ResourceListWaveTable)->Release();
|
|
*ResourceListWaveTable = NULL;
|
|
}
|
|
if (*ResourceListUart)
|
|
{
|
|
(*ResourceListUart)->Release();
|
|
*ResourceListUart = NULL;
|
|
}
|
|
if (*ResourceListFmSynth)
|
|
{
|
|
(*ResourceListFmSynth)->Release();
|
|
*ResourceListFmSynth = NULL;
|
|
}
|
|
if(*ResourceListAdapter)
|
|
{
|
|
(*ResourceListAdapter)->Release();
|
|
*ResourceListAdapter = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
#ifdef DO_RESOURCE_FILTERING
|
|
|
|
/*****************************************************************************
|
|
* AdapterDispatchPnp()
|
|
*****************************************************************************
|
|
* Supplying your PnP resource filtering needs.
|
|
*/
|
|
extern "C"
|
|
NTSTATUS
|
|
AdapterDispatchPnp
|
|
(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
ASSERT(pDeviceObject);
|
|
ASSERT(pIrp);
|
|
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
PIO_STACK_LOCATION pIrpStack =
|
|
IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
if( pIrpStack->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS )
|
|
{
|
|
//
|
|
// Do your resource requirements filtering here!!
|
|
//
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("[AdapterDispatchPnp] - IRP_MN_FILTER_RESOURCE_REQUIREMENTS"));
|
|
|
|
// set the return status
|
|
pIrp->IoStatus.Status = ntStatus;
|
|
|
|
}
|
|
|
|
//
|
|
// Pass the IRPs on to PortCls
|
|
//
|
|
ntStatus = PcDispatchIrp( pDeviceObject,
|
|
pIrp );
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*****************************************************************************
|
|
* DeterminePlatform()
|
|
*****************************************************************************
|
|
* Figure out which WDM platform we are currently running on.
|
|
* Note: the Port parameter could be WAVECYCLIC, WAVEPCI, DMUS or MIDI instead.
|
|
*
|
|
* TODO: Make this work on old DDK.
|
|
*
|
|
*/
|
|
DWORD DeterminePlatform(PPORTTOPOLOGY Port)
|
|
{
|
|
PAGED_CODE();
|
|
ASSERT(Port);
|
|
|
|
//
|
|
// The generally accepted way of determining audio stack vintage:
|
|
//
|
|
PPORTCLSVERSION pPortClsVersion;
|
|
PDRMPORT pDrmPort;
|
|
PPORTEVENTS pPortEvents;
|
|
DWORD dwVersion;
|
|
|
|
(void) Port->QueryInterface( IID_IPortClsVersion, (PVOID *) &pPortClsVersion);
|
|
(void) Port->QueryInterface( IID_IDrmPort, (PVOID *) &pDrmPort);
|
|
(void) Port->QueryInterface( IID_IPortEvents, (PVOID *) &pPortEvents);
|
|
|
|
//
|
|
// Try for the exact release (Win98SE QFE3, WinME QFE, Win2KSP2, WinXP, or later).
|
|
//
|
|
if (pPortClsVersion)
|
|
{
|
|
dwVersion = pPortClsVersion->GetVersion();
|
|
pPortClsVersion->Release();
|
|
}
|
|
//
|
|
// Try for WinME
|
|
//
|
|
else if (pDrmPort)
|
|
{
|
|
dwVersion = kVersionWinME;
|
|
ASSERT(IoIsWdmVersionAvailable(0x01,0x05));
|
|
//
|
|
// TODO: Look for registry entries that denote WinME QFEs
|
|
// HKLM\Software\Microsoft\Windows\CurrentVersion\Setup\Updates\..., etc.
|
|
//
|
|
}
|
|
//
|
|
// Try for Win2K family.
|
|
// Note that SP1 contains no real audio stack changes,
|
|
// while SP2 contains non-PCM support and other fixes.
|
|
//
|
|
else if (IoIsWdmVersionAvailable(0x01,0x10))
|
|
{
|
|
dwVersion = kVersionWin2K;
|
|
//
|
|
// TODO: Detect whether SP1 or earlier.
|
|
//
|
|
}
|
|
//
|
|
// Must be Win98 or Win98SE.
|
|
// IPortEvents was new in Win98SE.
|
|
//
|
|
else if (pPortEvents)
|
|
{
|
|
dwVersion = kVersionWin98SE; // or older QFEs
|
|
//
|
|
// TODO: Look for registry entries that denote older Win98SE QFEs
|
|
// HKLM\Software\Microsoft\Windows\CurrentVersion\Setup\Updates\W98.SE\UPD\269601, etc.
|
|
//
|
|
}
|
|
//
|
|
// Process of elimination tells us it is Win98.
|
|
//
|
|
else
|
|
{
|
|
dwVersion = kVersionWin98;
|
|
//
|
|
// TODO: Look for registry entries that denote older Win98 QFEs
|
|
// HKLM\Software\Microsoft\Windows\CurrentVersion\Setup\Updates\..., etc.
|
|
//
|
|
}
|
|
// dwVersion contains enum with version of audio stack
|
|
|
|
return dwVersion;
|
|
}
|
|
|
|
#pragma code_seg()
|
|
|
|
/*****************************************************************************
|
|
* _purecall()
|
|
*****************************************************************************
|
|
* The C++ compiler loves me.
|
|
* TODO: Figure out how to put this into portcls.sys
|
|
*/
|
|
int __cdecl
|
|
_purecall( void )
|
|
{
|
|
ASSERT( !"Pure virutal function called" );
|
|
return 0;
|
|
}
|