4232d4a030af9a5e8cd0a5bd05b9fa40599a9e43
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / adapter.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/multimedia/portcls/adapter.c
5 * PURPOSE: Port Class driver / DriverEntry and IRP handlers
6 * PROGRAMMER: Andrew Greenwood
7 *
8 * HISTORY:
9 * 27 Jan 07 Created
10 */
11
12 #include "private.h"
13 #include <devguid.h>
14 #include <initguid.h>
15
16 /*
17 This is called from DriverEntry so that PortCls can take care of some
18 IRPs and map some others to the main KS driver. In most cases this will
19 be the first function called by an audio driver.
20
21 First 2 parameters are from DriverEntry.
22
23 The AddDevice parameter is a driver-supplied pointer to a function which
24 typically then calls PcAddAdapterDevice (see below.)
25 */
26 NTSTATUS NTAPI
27 PcInitializeAdapterDriver(
28 IN PDRIVER_OBJECT DriverObject,
29 IN PUNICODE_STRING RegistryPathName,
30 IN PDRIVER_ADD_DEVICE AddDevice)
31 {
32 /*
33 (* = implement here, otherwise KS default)
34 IRP_MJ_CLOSE
35 * IRP_MJ_CREATE
36 IRP_MJ_DEVICE_CONTROL
37 IRP_MJ_FLUSH_BUFFERS
38 * IRP_MJ_PNP
39 * IRP_MJ_POWER
40 IRP_MJ_QUERY_SECURITY
41 IRP_MJ_READ
42 IRP_MJ_SET_SECURITY
43 * IRP_MJ_SYSTEM_CONTROL
44 IRP_MJ_WRITE
45 */
46
47 //NTSTATUS status;
48 //ULONG i;
49
50 DPRINT1("PcInitializeAdapterDriver\n");
51
52 #if 0
53 /* Set default stub - is this a good idea? */
54 DPRINT1("Setting IRP stub\n");
55 for ( i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i ++ )
56 {
57 DriverObject->MajorFunction[i] = IrpStub;
58 }
59 #endif
60
61 /* Our IRP handlers */
62 DPRINT1("Setting IRP handlers\n");
63 DriverObject->MajorFunction[IRP_MJ_CREATE] = PcDispatchIrp;
64 DriverObject->MajorFunction[IRP_MJ_PNP] = PcDispatchIrp;
65 DriverObject->MajorFunction[IRP_MJ_POWER] = PcDispatchIrp;
66 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PcDispatchIrp;
67
68 /* The driver-supplied AddDevice */
69 DriverObject->DriverExtension->AddDevice = AddDevice;
70
71 /* KS handles these */
72 DPRINT1("Setting KS function handlers\n");
73 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE);
74 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL);
75 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_FLUSH_BUFFERS);
76 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_QUERY_SECURITY);
77 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_READ);
78 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_SET_SECURITY);
79 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_WRITE);
80
81 DPRINT1("PortCls has finished initializing the adapter driver\n");
82
83 return STATUS_SUCCESS;
84 }
85
86 /*
87 Typically called by a driver's AddDevice function, which is set when
88 calling PcInitializeAdapterDriver. This performs some common driver
89 operations, such as creating a device extension.
90
91 The StartDevice parameter is a driver-supplied function which gets
92 called in response to IRP_MJ_PNP / IRP_MN_START_DEVICE.
93 */
94 NTSTATUS NTAPI
95 PcAddAdapterDevice(
96 IN PDRIVER_OBJECT DriverObject,
97 IN PDEVICE_OBJECT PhysicalDeviceObject,
98 IN PCPFNSTARTDEVICE StartDevice,
99 IN ULONG MaxObjects,
100 IN ULONG DeviceExtensionSize)
101 {
102 NTSTATUS status = STATUS_UNSUCCESSFUL;
103 PDEVICE_OBJECT fdo = NULL;
104 PDEVICE_OBJECT PrevDeviceObject;
105 PCExtension* portcls_ext;
106
107 DPRINT1("PcAddAdapterDevice called\n");
108
109 if (!DriverObject || !PhysicalDeviceObject || !StartDevice)
110 {
111 return STATUS_INVALID_PARAMETER;
112 }
113
114 /* check if the DeviceExtensionSize is provided */
115 if ( DeviceExtensionSize < PORT_CLASS_DEVICE_EXTENSION_SIZE )
116 {
117 /* driver does not need a device extension */
118 if ( DeviceExtensionSize != 0 )
119 {
120 /* DeviceExtensionSize must be zero*/
121 return STATUS_INVALID_PARAMETER;
122 }
123 /* set size to our extension size */
124 DeviceExtensionSize = PORT_CLASS_DEVICE_EXTENSION_SIZE;
125 }
126
127 /* create the device */
128 status = IoCreateDevice(DriverObject,
129 DeviceExtensionSize,
130 NULL,
131 FILE_DEVICE_KS,
132 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
133 FALSE,
134 &fdo);
135
136 if (!NT_SUCCESS(status))
137 {
138 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", status);
139 return status;
140 }
141
142 /* Obtain the new device extension */
143 portcls_ext = (PCExtension*) fdo->DeviceExtension;
144 /* initialize the device extension */
145 RtlZeroMemory(portcls_ext, DeviceExtensionSize);
146 /* allocate create item */
147 portcls_ext->CreateItems = AllocateItem(NonPagedPool, MaxObjects * sizeof(KSOBJECT_CREATE_ITEM), TAG_PORTCLASS);
148
149 /* store the physical device object */
150 portcls_ext->PhysicalDeviceObject = PhysicalDeviceObject;
151 /* set up the start device function */
152 portcls_ext->StartDevice = StartDevice;
153 /* prepare the subdevice list */
154 InitializeListHead(&portcls_ext->SubDeviceList);
155 /* prepare the physical connection list */
156 InitializeListHead(&portcls_ext->PhysicalConnectionList);
157
158 /* set io flags */
159 fdo->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
160 /* clear initializing flag */
161 fdo->Flags &= ~ DO_DEVICE_INITIALIZING;
162
163 /* allocate the device header */
164 status = KsAllocateDeviceHeader(&portcls_ext->KsDeviceHeader, MaxObjects, portcls_ext->CreateItems);
165 /* did we succeed */
166 if (!NT_SUCCESS(status))
167 {
168 /* free previously allocated create items */
169 FreeItem(portcls_ext->CreateItems, TAG_PORTCLASS);
170 /* delete created fdo */
171 IoDeleteDevice(fdo);
172 /* return error code */
173 return status;
174 }
175
176 /* attach device to device stack */
177 PrevDeviceObject = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
178 /* did we succeed */
179 if (PrevDeviceObject)
180 {
181 /* store the device object in the device header */
182 //KsSetDevicePnpBaseObject(portcls_ext->KsDeviceHeader, PrevDeviceObject, fdo);
183 portcls_ext->PrevDeviceObject = PrevDeviceObject;
184 }
185 else
186 {
187 /* free the device header */
188 KsFreeDeviceHeader(portcls_ext->KsDeviceHeader);
189 /* free previously allocated create items */
190 FreeItem(portcls_ext->CreateItems, TAG_PORTCLASS);
191 /* delete created fdo */
192 IoDeleteDevice(fdo);
193 /* return error code */
194 return STATUS_UNSUCCESSFUL;
195 }
196
197
198
199 return status;
200 }
201
202 NTSTATUS
203 NTAPI
204 PciDriverDispatch(
205 IN PDEVICE_OBJECT DeviceObject,
206 IN PIRP Irp)
207 {
208 NTSTATUS Status;
209
210 ISubdevice * SubDevice;
211 PCExtension* DeviceExt;
212 SUBDEVICE_ENTRY * Entry;
213 KSDISPATCH_TABLE DispatchTable;
214
215 DPRINT1("PortClsSysControl called\n");
216
217 SubDevice = (ISubdevice*)Irp->Tail.Overlay.DriverContext[3];
218 DeviceExt = (PCExtension*)DeviceObject->DeviceExtension;
219
220 if (!SubDevice || !DeviceExt)
221 {
222 return STATUS_UNSUCCESSFUL;
223 }
224
225 Entry = AllocateItem(NonPagedPool, sizeof(SUBDEVICE_ENTRY), TAG_PORTCLASS);
226 if (!Entry)
227 return STATUS_INSUFFICIENT_RESOURCES;
228
229 /* initialize DispatchTable */
230 RtlZeroMemory(&DispatchTable, sizeof(KSDISPATCH_TABLE));
231 /* FIXME
232 * initialize DispatchTable pointer
233 * which call in turn ISubDevice
234 */
235
236
237 Status = KsAllocateObjectHeader(&Entry->ObjectHeader, 1, NULL, Irp, &DispatchTable);
238 if (!NT_SUCCESS(Status))
239 {
240 FreeItem(Entry, TAG_PORTCLASS);
241 return Status;
242 }
243
244
245 InsertTailList(&DeviceExt->SubDeviceList, &Entry->Entry);
246
247 Irp->IoStatus.Status = STATUS_SUCCESS;
248 Irp->IoStatus.Information = 0;
249 IoCompleteRequest(Irp, IO_NO_INCREMENT);
250
251 return STATUS_SUCCESS;
252 }
253
254 NTSTATUS NTAPI
255 PcRegisterSubdevice(
256 IN PDEVICE_OBJECT DeviceObject,
257 IN PWCHAR Name,
258 IN PUNKNOWN Unknown)
259 {
260 PCExtension* DeviceExt;
261 NTSTATUS Status;
262 ISubdevice *SubDevice;
263 UNICODE_STRING ReferenceString;
264 UNICODE_STRING SymbolicLinkName;
265
266 DPRINT1("PcRegisterSubdevice DeviceObject %p Name %S Unknown %p\n", DeviceObject, Name, Unknown);
267
268 if (!DeviceObject || !Name || !Unknown)
269 {
270 DPRINT("PcRegisterSubdevice invalid parameter\n");
271 return STATUS_INVALID_PARAMETER;
272 }
273
274 DeviceExt = (PCExtension*)DeviceObject->DeviceExtension;
275 if (!DeviceExt)
276 return STATUS_UNSUCCESSFUL;
277
278 Status = Unknown->lpVtbl->QueryInterface(Unknown, &IID_ISubdevice, (LPVOID)&SubDevice);
279 if (!NT_SUCCESS(Status))
280 {
281 DPRINT1("No ISubdevice interface\n");
282 /* the provided port driver doesnt support ISubdevice */
283 return STATUS_INVALID_PARAMETER;
284 }
285 #if KS_IMPLEMENTED
286 Status = KsAddObjectCreateItemToDeviceHeader(DeviceExt->KsDeviceHeader, PciDriverDispatch, (PVOID)SubDevice, Name, NULL);
287 if (!NT_SUCCESS(Status))
288 {
289 /* failed to attach */
290 SubDevice->lpVtbl->Release(SubDevice);
291 DPRINT1("KsAddObjectCreateItemToDeviceHeader failed with %x\n", Status);
292 return Status;
293 }
294 #endif
295
296 /* FIXME retrieve guid from subdescriptor */
297
298 RtlInitUnicodeString(&ReferenceString, Name);
299 /* register device interface */
300 Status = IoRegisterDeviceInterface(DeviceExt->PhysicalDeviceObject,
301 &GUID_DEVCLASS_SOUND, //FIXME
302 &ReferenceString,
303 &SymbolicLinkName);
304 if (NT_SUCCESS(Status))
305 {
306 Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
307 RtlFreeUnicodeString(&SymbolicLinkName);
308 }
309
310 DPRINT1("PcRegisterSubdevice Status %x\n", Status);
311
312 /// HACK
313 /// IoRegisterDeviceInterface fails with
314 /// STATUS_OBJECT_PATH_NOT_FOUND
315 /// return Status;
316 return STATUS_SUCCESS;
317 }