- Fix debugging flood #2
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / adapter.cpp
1 /*
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
7 * Johannes Anderwald
8 * HISTORY:
9 * 27 Jan 07 Created
10 */
11
12 #include "private.hpp"
13
14 //
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.
18 //
19 // First 2 parameters are from DriverEntry.
20 //
21 // The AddDevice parameter is a driver-supplied pointer to a function which
22 // typically then calls PcAddAdapterDevice (see below.)
23 //
24 NTSTATUS
25 NTAPI
26 PcInitializeAdapterDriver(
27 IN PDRIVER_OBJECT DriverObject,
28 IN PUNICODE_STRING RegistryPathName,
29 IN PDRIVER_ADD_DEVICE AddDevice)
30 {
31 DPRINT1("PcInitializeAdapterDriver\n");
32 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
33
34 // Our IRP handlers
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;
41
42 // The driver-supplied AddDevice
43 DriverObject->DriverExtension->AddDevice = AddDevice;
44
45 // KS handles these
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);
54
55 DPRINT("PortCls has finished initializing the adapter driver\n");
56
57 return STATUS_SUCCESS;
58 }
59
60 //
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.
64 //
65 // The StartDevice parameter is a driver-supplied function which gets
66 // called in response to IRP_MJ_PNP / IRP_MN_START_DEVICE.
67 //
68 NTSTATUS
69 NTAPI
70 PcAddAdapterDevice(
71 IN PDRIVER_OBJECT DriverObject,
72 IN PDEVICE_OBJECT PhysicalDeviceObject,
73 IN PCPFNSTARTDEVICE StartDevice,
74 IN ULONG MaxObjects,
75 IN ULONG DeviceExtensionSize)
76 {
77 NTSTATUS status = STATUS_UNSUCCESSFUL;
78 PDEVICE_OBJECT fdo;
79 PDEVICE_OBJECT PrevDeviceObject;
80 PPCLASS_DEVICE_EXTENSION portcls_ext = NULL;
81
82 DPRINT1("PcAddAdapterDevice called\n");
83 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
84
85 if (!DriverObject || !PhysicalDeviceObject || !StartDevice)
86 {
87 return STATUS_INVALID_PARAMETER;
88 }
89
90 // check if the DeviceExtensionSize is provided
91 if ( DeviceExtensionSize < PORT_CLASS_DEVICE_EXTENSION_SIZE )
92 {
93 // driver does not need a device extension
94 if ( DeviceExtensionSize != 0 )
95 {
96 // DeviceExtensionSize must be zero
97 return STATUS_INVALID_PARAMETER;
98 }
99 // set size to our extension size
100 DeviceExtensionSize = PORT_CLASS_DEVICE_EXTENSION_SIZE;
101 }
102
103 // create the device
104 status = IoCreateDevice(DriverObject,
105 DeviceExtensionSize,
106 NULL,
107 FILE_DEVICE_KS,
108 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
109 FALSE,
110 &fdo);
111
112 if (!NT_SUCCESS(status))
113 {
114 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", status);
115 return status;
116 }
117
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);
124
125 if (!portcls_ext->CreateItems)
126 {
127 // not enough resources
128 status = STATUS_INSUFFICIENT_RESOURCES;
129 goto cleanup;
130 }
131
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
145 IoStartTimer(fdo);
146
147 // set io flags
148 fdo->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
149 // clear initializing flag
150 fdo->Flags &= ~ DO_DEVICE_INITIALIZING;
151
152 // allocate the device header
153 status = KsAllocateDeviceHeader(&portcls_ext->KsDeviceHeader, MaxObjects, portcls_ext->CreateItems);
154 // did we succeed
155 if (!NT_SUCCESS(status))
156 {
157 goto cleanup;
158 }
159
160 // attach device to device stack
161 PrevDeviceObject = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
162 // did we succeed
163 if (PrevDeviceObject)
164 {
165 // store the device object in the device header
166 //KsSetDevicePnpBaseObject(portcls_ext->KsDeviceHeader, fdo, PrevDeviceObject);
167 portcls_ext->PrevDeviceObject = PrevDeviceObject;
168 }
169 else
170 {
171 // return error code
172 status = STATUS_UNSUCCESSFUL;
173 goto cleanup;
174 }
175
176 // register shutdown notification
177 IoRegisterShutdownNotification(PhysicalDeviceObject);
178
179 return status;
180
181 cleanup:
182
183 if (portcls_ext->KsDeviceHeader)
184 {
185 // free the device header
186 KsFreeDeviceHeader(portcls_ext->KsDeviceHeader);
187 }
188
189 if (portcls_ext->CreateItems)
190 {
191 // free previously allocated create items
192 FreeItem(portcls_ext->CreateItems, TAG_PORTCLASS);
193 }
194
195 // delete created fdo
196 IoDeleteDevice(fdo);
197
198
199 return status;
200 }
201
202 NTSTATUS
203 NTAPI
204 PcRegisterSubdevice(
205 IN PDEVICE_OBJECT DeviceObject,
206 IN PWCHAR Name,
207 IN PUNKNOWN Unknown)
208 {
209 PPCLASS_DEVICE_EXTENSION DeviceExt;
210 NTSTATUS Status;
211 ISubdevice *SubDevice;
212 UNICODE_STRING SymbolicLinkName;
213 PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor;
214 ULONG Index;
215 UNICODE_STRING RefName;
216 PSYMBOLICLINK_ENTRY SymEntry;
217
218 DPRINT1("PcRegisterSubdevice DeviceObject %p Name %S Unknown %p\n", DeviceObject, Name, Unknown);
219
220 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
221
222 // check if all parameters are valid
223 if (!DeviceObject || !Name || !Unknown)
224 {
225 DPRINT("PcRegisterSubdevice invalid parameter\n");
226 return STATUS_INVALID_PARAMETER;
227 }
228
229 // get device extension
230 DeviceExt = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
231
232 if (!DeviceExt)
233 {
234 // should not happen
235 KeBugCheck(0);
236 return STATUS_UNSUCCESSFUL;
237 }
238
239 // look up our undocumented interface
240 Status = Unknown->QueryInterface(IID_ISubdevice, (LPVOID*)&SubDevice);
241 if (!NT_SUCCESS(Status))
242 {
243 DPRINT1("No ISubdevice interface\n");
244 // the provided port driver doesnt support ISubdevice
245 return STATUS_INVALID_PARAMETER;
246 }
247
248 // get the subdevice descriptor
249 Status = SubDevice->GetDescriptor(&SubDeviceDescriptor);
250 if (!NT_SUCCESS(Status))
251 {
252 DPRINT1("Failed to get subdevice descriptor %x\n", Status);
253 SubDevice->Release();
254 return STATUS_UNSUCCESSFUL;
255 }
256
257 // add an create item to the device header
258 Status = KsAddObjectCreateItemToDeviceHeader(DeviceExt->KsDeviceHeader, PcCreateItemDispatch, (PVOID)SubDevice, Name, NULL);
259 if (!NT_SUCCESS(Status))
260 {
261 // failed to attach
262 SubDevice->Release();
263 DPRINT1("KsAddObjectCreateItemToDeviceHeader failed with %x\n", Status);
264 return Status;
265 }
266
267 // initialize reference string
268 RtlInitUnicodeString(&RefName, Name);
269 RtlInitUnicodeString(&SubDeviceDescriptor->RefString, Name);
270
271 for(Index = 0; Index < SubDeviceDescriptor->InterfaceCount; Index++)
272 {
273 // FIXME
274 // check if reference string with that name already exists
275
276 Status = IoRegisterDeviceInterface(DeviceExt->PhysicalDeviceObject,
277 &SubDeviceDescriptor->Interfaces[Index],
278 &RefName,
279 &SymbolicLinkName);
280
281 if (NT_SUCCESS(Status))
282 {
283 // activate device interface
284 IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
285 // allocate symbolic link entry
286 SymEntry = (PSYMBOLICLINK_ENTRY)AllocateItem(NonPagedPool, sizeof(SYMBOLICLINK_ENTRY), TAG_PORTCLASS);
287 if (SymEntry)
288 {
289 // initialize symbolic link item
290 RtlInitUnicodeString(&SymEntry->SymbolicLink, SymbolicLinkName.Buffer);
291 // store item
292 InsertTailList(&SubDeviceDescriptor->SymbolicLinkList, &SymEntry->Entry);
293 }
294 else
295 {
296 // allocating failed
297 RtlFreeUnicodeString(&SymbolicLinkName);
298 }
299 }
300 }
301
302 // release SubDevice reference
303 SubDevice->Release();
304
305 return STATUS_SUCCESS;
306 }