2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/api.cpp
5 * PURPOSE: Port Class driver / DriverEntry and IRP handlers
6 * PROGRAMMER: Andrew Greenwood
12 #include "private.hpp"
15 // This is called from DriverEntry so that PortCls can take care of some
16 // IRPs and map some others to the main KS driver. In most cases this will
17 // be the first function called by an audio driver.
19 // First 2 parameters are from DriverEntry.
21 // The AddDevice parameter is a driver-supplied pointer to a function which
22 // typically then calls PcAddAdapterDevice (see below.)
26 PcInitializeAdapterDriver(
27 IN PDRIVER_OBJECT DriverObject
,
28 IN PUNICODE_STRING RegistryPathName
,
29 IN PDRIVER_ADD_DEVICE AddDevice
)
31 DPRINT1("PcInitializeAdapterDriver\n");
32 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
35 DPRINT1("Setting IRP handlers\n");
36 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = PcDispatchIrp
;
37 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = PcDispatchIrp
;
38 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = PcDispatchIrp
;
39 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = PcDispatchIrp
;
40 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = PcDispatchIrp
;
42 // The driver-supplied AddDevice
43 DriverObject
->DriverExtension
->AddDevice
= AddDevice
;
46 DPRINT("Setting KS function handlers\n");
47 KsSetMajorFunctionHandler(DriverObject
, IRP_MJ_CLOSE
);
48 KsSetMajorFunctionHandler(DriverObject
, IRP_MJ_DEVICE_CONTROL
);
49 KsSetMajorFunctionHandler(DriverObject
, IRP_MJ_FLUSH_BUFFERS
);
50 KsSetMajorFunctionHandler(DriverObject
, IRP_MJ_QUERY_SECURITY
);
51 KsSetMajorFunctionHandler(DriverObject
, IRP_MJ_READ
);
52 KsSetMajorFunctionHandler(DriverObject
, IRP_MJ_SET_SECURITY
);
53 KsSetMajorFunctionHandler(DriverObject
, IRP_MJ_WRITE
);
55 DPRINT("PortCls has finished initializing the adapter driver\n");
57 return STATUS_SUCCESS
;
61 // Typically called by a driver's AddDevice function, which is set when
62 // calling PcInitializeAdapterDriver. This performs some common driver
63 // operations, such as creating a device extension.
65 // The StartDevice parameter is a driver-supplied function which gets
66 // called in response to IRP_MJ_PNP / IRP_MN_START_DEVICE.
71 IN PDRIVER_OBJECT DriverObject
,
72 IN PDEVICE_OBJECT PhysicalDeviceObject
,
73 IN PCPFNSTARTDEVICE StartDevice
,
75 IN ULONG DeviceExtensionSize
)
77 NTSTATUS status
= STATUS_UNSUCCESSFUL
;
79 PDEVICE_OBJECT PrevDeviceObject
;
80 PPCLASS_DEVICE_EXTENSION portcls_ext
= NULL
;
82 DPRINT1("PcAddAdapterDevice called\n");
83 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
85 if (!DriverObject
|| !PhysicalDeviceObject
|| !StartDevice
)
87 return STATUS_INVALID_PARAMETER
;
90 // check if the DeviceExtensionSize is provided
91 if ( DeviceExtensionSize
< PORT_CLASS_DEVICE_EXTENSION_SIZE
)
93 // driver does not need a device extension
94 if ( DeviceExtensionSize
!= 0 )
96 // DeviceExtensionSize must be zero
97 return STATUS_INVALID_PARAMETER
;
99 // set size to our extension size
100 DeviceExtensionSize
= PORT_CLASS_DEVICE_EXTENSION_SIZE
;
104 status
= IoCreateDevice(DriverObject
,
108 FILE_AUTOGENERATED_DEVICE_NAME
| FILE_DEVICE_SECURE_OPEN
,
112 if (!NT_SUCCESS(status
))
114 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", status
);
118 // Obtain the new device extension
119 portcls_ext
= (PPCLASS_DEVICE_EXTENSION
) fdo
->DeviceExtension
;
120 // initialize the device extension
121 RtlZeroMemory(portcls_ext
, DeviceExtensionSize
);
122 // allocate create item
123 portcls_ext
->CreateItems
= (PKSOBJECT_CREATE_ITEM
)AllocateItem(NonPagedPool
, MaxObjects
* sizeof(KSOBJECT_CREATE_ITEM
), TAG_PORTCLASS
);
125 if (!portcls_ext
->CreateItems
)
127 // not enough resources
128 status
= STATUS_INSUFFICIENT_RESOURCES
;
132 // store max subdevice count
133 portcls_ext
->MaxSubDevices
= MaxObjects
;
134 // store the physical device object
135 portcls_ext
->PhysicalDeviceObject
= PhysicalDeviceObject
;
136 // set up the start device function
137 portcls_ext
->StartDevice
= StartDevice
;
138 // initialize timer lock
139 KeInitializeSpinLock(&portcls_ext
->TimerListLock
);
140 // initialize timer list
141 InitializeListHead(&portcls_ext
->TimerList
);
142 // initialize io timer
143 IoInitializeTimer(fdo
, PcIoTimerRoutine
, NULL
);
144 // start the io timer
148 fdo
->Flags
|= DO_DIRECT_IO
| DO_POWER_PAGABLE
;
149 // clear initializing flag
150 fdo
->Flags
&= ~ DO_DEVICE_INITIALIZING
;
152 // allocate the device header
153 status
= KsAllocateDeviceHeader(&portcls_ext
->KsDeviceHeader
, MaxObjects
, portcls_ext
->CreateItems
);
155 if (!NT_SUCCESS(status
))
160 // attach device to device stack
161 PrevDeviceObject
= IoAttachDeviceToDeviceStack(fdo
, PhysicalDeviceObject
);
163 if (PrevDeviceObject
)
165 // store the device object in the device header
166 //KsSetDevicePnpBaseObject(portcls_ext->KsDeviceHeader, fdo, PrevDeviceObject);
167 portcls_ext
->PrevDeviceObject
= PrevDeviceObject
;
172 status
= STATUS_UNSUCCESSFUL
;
176 // register shutdown notification
177 IoRegisterShutdownNotification(PhysicalDeviceObject
);
183 if (portcls_ext
->KsDeviceHeader
)
185 // free the device header
186 KsFreeDeviceHeader(portcls_ext
->KsDeviceHeader
);
189 if (portcls_ext
->CreateItems
)
191 // free previously allocated create items
192 FreeItem(portcls_ext
->CreateItems
, TAG_PORTCLASS
);
195 // delete created fdo
205 IN PDEVICE_OBJECT DeviceObject
,
209 PPCLASS_DEVICE_EXTENSION DeviceExt
;
211 ISubdevice
*SubDevice
;
212 UNICODE_STRING SymbolicLinkName
;
213 PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor
;
215 UNICODE_STRING RefName
;
216 PSYMBOLICLINK_ENTRY SymEntry
;
218 DPRINT1("PcRegisterSubdevice DeviceObject %p Name %S Unknown %p\n", DeviceObject
, Name
, Unknown
);
220 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
222 // check if all parameters are valid
223 if (!DeviceObject
|| !Name
|| !Unknown
)
225 DPRINT("PcRegisterSubdevice invalid parameter\n");
226 return STATUS_INVALID_PARAMETER
;
229 // get device extension
230 DeviceExt
= (PPCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
236 return STATUS_UNSUCCESSFUL
;
239 // look up our undocumented interface
240 Status
= Unknown
->QueryInterface(IID_ISubdevice
, (LPVOID
*)&SubDevice
);
241 if (!NT_SUCCESS(Status
))
243 DPRINT1("No ISubdevice interface\n");
244 // the provided port driver doesnt support ISubdevice
245 return STATUS_INVALID_PARAMETER
;
248 // get the subdevice descriptor
249 Status
= SubDevice
->GetDescriptor(&SubDeviceDescriptor
);
250 if (!NT_SUCCESS(Status
))
252 DPRINT1("Failed to get subdevice descriptor %x\n", Status
);
253 SubDevice
->Release();
254 return STATUS_UNSUCCESSFUL
;
257 // add an create item to the device header
258 Status
= KsAddObjectCreateItemToDeviceHeader(DeviceExt
->KsDeviceHeader
, PcCreateItemDispatch
, (PVOID
)SubDevice
, Name
, NULL
);
259 if (!NT_SUCCESS(Status
))
262 SubDevice
->Release();
263 DPRINT1("KsAddObjectCreateItemToDeviceHeader failed with %x\n", Status
);
267 // initialize reference string
268 RtlInitUnicodeString(&RefName
, Name
);
269 RtlInitUnicodeString(&SubDeviceDescriptor
->RefString
, Name
);
271 for(Index
= 0; Index
< SubDeviceDescriptor
->InterfaceCount
; Index
++)
274 // check if reference string with that name already exists
276 Status
= IoRegisterDeviceInterface(DeviceExt
->PhysicalDeviceObject
,
277 &SubDeviceDescriptor
->Interfaces
[Index
],
281 if (NT_SUCCESS(Status
))
283 // activate device interface
284 IoSetDeviceInterfaceState(&SymbolicLinkName
, TRUE
);
285 // allocate symbolic link entry
286 SymEntry
= (PSYMBOLICLINK_ENTRY
)AllocateItem(NonPagedPool
, sizeof(SYMBOLICLINK_ENTRY
), TAG_PORTCLASS
);
289 // initialize symbolic link item
290 RtlInitUnicodeString(&SymEntry
->SymbolicLink
, SymbolicLinkName
.Buffer
);
292 InsertTailList(&SubDeviceDescriptor
->SymbolicLinkList
, &SymEntry
->Entry
);
297 RtlFreeUnicodeString(&SymbolicLinkName
);
302 // release SubDevice reference
303 SubDevice
->Release();
305 return STATUS_SUCCESS
;