Fix a memory leak if VideoPortInitialize is called more than once from the same miniport.
[reactos.git] / reactos / drivers / video / videoprt / dispatch.c
1 /*
2 * VideoPort driver
3 *
4 * Copyright (C) 2002, 2003, 2004 ReactOS Team
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; see the file COPYING.LIB.
18 * If not, write to the Free Software Foundation,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * $Id$
22 */
23
24 #include "videoprt.h"
25
26 /* EXTERNAL FUNCTIONS *********************************************************/
27
28 VOID NTAPI HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters);
29 VOID NTAPI HalReleaseDisplayOwnership();
30
31 /* GLOBAL VARIABLES ***********************************************************/
32
33 PVIDEO_PORT_DEVICE_EXTENSION ResetDisplayParametersDeviceExtension = NULL;
34
35 /* PRIVATE FUNCTIONS **********************************************************/
36
37 /*
38 * Reset display to blue screen
39 */
40
41 BOOLEAN NTAPI
42 IntVideoPortResetDisplayParameters(ULONG Columns, ULONG Rows)
43 {
44 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
45
46 if (ResetDisplayParametersDeviceExtension == NULL)
47 return FALSE;
48
49 DriverExtension = ResetDisplayParametersDeviceExtension->DriverExtension;
50
51 if (DriverExtension->InitializationData.HwResetHw != NULL)
52 {
53 if (DriverExtension->InitializationData.HwResetHw(
54 &ResetDisplayParametersDeviceExtension->MiniPortDeviceExtension,
55 Columns, Rows))
56 {
57 ResetDisplayParametersDeviceExtension = NULL;
58 return TRUE;
59 }
60 }
61
62 ResetDisplayParametersDeviceExtension = NULL;
63 return FALSE;
64 }
65
66 NTSTATUS NTAPI
67 IntVideoPortAddDevice(
68 IN PDRIVER_OBJECT DriverObject,
69 IN PDEVICE_OBJECT PhysicalDeviceObject)
70 {
71 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
72
73 /*
74 * Get the initialization data we saved in VideoPortInitialize.
75 */
76
77 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
78
79 /*
80 * Create adapter device object.
81 */
82
83 return IntVideoPortCreateAdapterDeviceObject(
84 DriverObject,
85 DriverExtension,
86 PhysicalDeviceObject,
87 NULL);
88 }
89
90 /*
91 * IntVideoPortDispatchOpen
92 *
93 * Answer requests for Open calls.
94 *
95 * Run Level
96 * PASSIVE_LEVEL
97 */
98
99 NTSTATUS NTAPI
100 IntVideoPortDispatchOpen(
101 IN PDEVICE_OBJECT DeviceObject,
102 IN PIRP Irp)
103 {
104 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
105 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
106
107 DPRINT("IntVideoPortDispatchOpen\n");
108
109 if (CsrssInitialized == FALSE)
110 {
111 /*
112 * We know the first open call will be from the CSRSS process
113 * to let us know its handle.
114 */
115
116 DPRINT("Referencing CSRSS\n");
117 Csrss = (PKPROCESS)PsGetCurrentProcess();
118 DPRINT("Csrss %p\n", Csrss);
119
120 CsrssInitialized = TRUE;
121
122 Irp->IoStatus.Information = FILE_OPENED;
123 IoCompleteRequest(Irp, IO_NO_INCREMENT);
124
125 return STATUS_SUCCESS;
126 }
127
128 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
129 DriverExtension = DeviceExtension->DriverExtension;
130
131 if (DriverExtension->InitializationData.HwInitialize(&DeviceExtension->MiniPortDeviceExtension))
132 {
133 Irp->IoStatus.Status = STATUS_SUCCESS;
134
135 InterlockedIncrement((PLONG)&DeviceExtension->DeviceOpened);
136
137 /*
138 * Storing the device extension pointer in a static variable is an
139 * ugly hack. Unfortunately, we need it in VideoPortResetDisplayParameters
140 * and HalAcquireDisplayOwnership doesn't allow us to pass a userdata
141 * parameter. On the bright side, the DISPLAY device is opened
142 * exclusively, so there can be only one device extension active at
143 * any point in time.
144 */
145
146 ResetDisplayParametersDeviceExtension = DeviceExtension;
147 HalAcquireDisplayOwnership(IntVideoPortResetDisplayParameters);
148 }
149 else
150 {
151 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
152 }
153
154 Irp->IoStatus.Information = FILE_OPENED;
155 IoCompleteRequest(Irp, IO_NO_INCREMENT);
156
157 return STATUS_SUCCESS;
158 }
159
160 /*
161 * IntVideoPortDispatchClose
162 *
163 * Answer requests for Close calls.
164 *
165 * Run Level
166 * PASSIVE_LEVEL
167 */
168
169 NTSTATUS NTAPI
170 IntVideoPortDispatchClose(
171 IN PDEVICE_OBJECT DeviceObject,
172 IN PIRP Irp)
173 {
174 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
175
176 DPRINT("IntVideoPortDispatchClose\n");
177
178 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
179 if (DeviceExtension->DeviceOpened >= 1 &&
180 InterlockedDecrement((PLONG)&DeviceExtension->DeviceOpened) == 0)
181 {
182 ResetDisplayParametersDeviceExtension = DeviceExtension;
183 HalReleaseDisplayOwnership();
184 }
185
186 Irp->IoStatus.Status = STATUS_SUCCESS;
187 IoCompleteRequest(Irp, IO_NO_INCREMENT);
188
189 return STATUS_SUCCESS;
190 }
191
192 /*
193 * IntVideoPortDispatchDeviceControl
194 *
195 * Answer requests for device control calls.
196 *
197 * Run Level
198 * PASSIVE_LEVEL
199 */
200
201 NTSTATUS NTAPI
202 IntVideoPortDispatchDeviceControl(
203 IN PDEVICE_OBJECT DeviceObject,
204 IN PIRP Irp)
205 {
206 PIO_STACK_LOCATION IrpStack;
207 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
208 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
209 PVIDEO_REQUEST_PACKET vrp;
210 NTSTATUS Status;
211
212 DPRINT("IntVideoPortDispatchDeviceControl\n");
213
214 IrpStack = IoGetCurrentIrpStackLocation(Irp);
215 DeviceExtension = DeviceObject->DeviceExtension;
216 DriverExtension = DeviceExtension->DriverExtension;
217
218 /* Translate the IRP to a VRP */
219 vrp = ExAllocatePool(NonPagedPool, sizeof(VIDEO_REQUEST_PACKET));
220 if (NULL == vrp)
221 {
222 return STATUS_NO_MEMORY;
223 }
224
225 vrp->StatusBlock = (PSTATUS_BLOCK)&(Irp->IoStatus);
226 vrp->IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
227
228 DPRINT("- IoControlCode: %x\n", vrp->IoControlCode);
229
230 /* We're assuming METHOD_BUFFERED */
231 vrp->InputBuffer = Irp->AssociatedIrp.SystemBuffer;
232 vrp->InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
233 vrp->OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
234 vrp->OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
235
236 /* Call the Miniport Driver with the VRP */
237 DriverExtension->InitializationData.HwStartIO(
238 &DeviceExtension->MiniPortDeviceExtension,
239 vrp);
240
241 /* Free the VRP */
242 ExFreePool(vrp);
243
244 DPRINT("- Returned status: %x\n", Irp->IoStatus.Status);
245
246 if (Irp->IoStatus.Status != STATUS_SUCCESS)
247 {
248 /* Map from win32 error codes to NT status values. */
249 switch (Irp->IoStatus.Status)
250 {
251 case ERROR_NOT_ENOUGH_MEMORY: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; break;
252 case ERROR_MORE_DATA: Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; break;
253 case ERROR_INVALID_FUNCTION: Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; break;
254 case ERROR_INVALID_PARAMETER: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; break;
255 case ERROR_INSUFFICIENT_BUFFER: Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; break;
256 case ERROR_DEV_NOT_EXIST: Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; break;
257 case ERROR_IO_PENDING: Irp->IoStatus.Status = STATUS_PENDING; break;
258 }
259 }
260
261 Status = Irp->IoStatus.Status;
262 IoCompleteRequest(Irp, IO_NO_INCREMENT);
263
264 return Status;
265 }
266
267 NTSTATUS NTAPI
268 IntVideoPortPnPStartDevice(
269 IN PDEVICE_OBJECT DeviceObject,
270 IN PIRP Irp)
271 {
272 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
273 PDRIVER_OBJECT DriverObject;
274 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
275 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
276 PCM_RESOURCE_LIST AllocatedResources;
277
278 /*
279 * Get the initialization data we saved in VideoPortInitialize.
280 */
281
282 DriverObject = DeviceObject->DriverObject;
283 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
284 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
285
286 /*
287 * Store some resources in the DeviceExtension.
288 */
289
290 AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources;
291 if (AllocatedResources != NULL)
292 {
293 CM_FULL_RESOURCE_DESCRIPTOR *FullList;
294 CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor;
295 ULONG ResourceCount;
296 ULONG ResourceListSize;
297
298 /* Save the resource list */
299 ResourceCount = AllocatedResources->List[0].PartialResourceList.Count;
300 ResourceListSize =
301 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
302 PartialDescriptors[ResourceCount]);
303 DeviceExtension->AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize);
304 if (DeviceExtension->AllocatedResources == NULL)
305 {
306 return STATUS_INSUFFICIENT_RESOURCES;
307 }
308
309 RtlCopyMemory(DeviceExtension->AllocatedResources,
310 AllocatedResources,
311 ResourceListSize);
312
313 /* Get the interrupt level/vector - needed by HwFindAdapter sometimes */
314 for (FullList = AllocatedResources->List;
315 FullList < AllocatedResources->List + AllocatedResources->Count;
316 FullList++)
317 {
318 /* FIXME: Is this ASSERT ok for resources from the PNP manager? */
319 ASSERT(FullList->InterfaceType == PCIBus &&
320 FullList->BusNumber == DeviceExtension->SystemIoBusNumber &&
321 1 == FullList->PartialResourceList.Version &&
322 1 == FullList->PartialResourceList.Revision);
323 for (Descriptor = FullList->PartialResourceList.PartialDescriptors;
324 Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count;
325 Descriptor++)
326 {
327 if (Descriptor->Type == CmResourceTypeInterrupt)
328 {
329 DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level;
330 DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector;
331 if (Descriptor->ShareDisposition == CmResourceShareShared)
332 DeviceExtension->InterruptShared = TRUE;
333 else
334 DeviceExtension->InterruptShared = FALSE;
335 }
336 }
337 }
338 }
339 DPRINT("Interrupt level: 0x%x Interrupt Vector: 0x%x\n",
340 DeviceExtension->InterruptLevel,
341 DeviceExtension->InterruptVector);
342
343 /*
344 * Create adapter device object.
345 */
346
347 return IntVideoPortFindAdapter(
348 DriverObject,
349 DriverExtension,
350 DeviceObject);
351 }
352
353
354 NTSTATUS
355 NTAPI
356 IntVideoPortForwardIrpAndWaitCompletionRoutine(
357 PDEVICE_OBJECT Fdo,
358 PIRP Irp,
359 PVOID Context)
360 {
361 PKEVENT Event = Context;
362
363 if (Irp->PendingReturned)
364 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
365
366 return STATUS_MORE_PROCESSING_REQUIRED;
367 }
368
369
370 NTSTATUS
371 NTAPI
372 IntVideoPortForwardIrpAndWait(PDEVICE_OBJECT DeviceObject, PIRP Irp)
373 {
374 KEVENT Event;
375 NTSTATUS Status;
376 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension =
377 (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
378
379 KeInitializeEvent(&Event, NotificationEvent, FALSE);
380 IoCopyCurrentIrpStackLocationToNext(Irp);
381 IoSetCompletionRoutine(Irp, IntVideoPortForwardIrpAndWaitCompletionRoutine,
382 &Event, TRUE, TRUE, TRUE);
383 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
384 if (Status == STATUS_PENDING)
385 {
386 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
387 Status = Irp->IoStatus.Status;
388 }
389 return Status;
390 }
391
392
393 NTSTATUS NTAPI
394 IntVideoPortDispatchPnp(
395 IN PDEVICE_OBJECT DeviceObject,
396 IN PIRP Irp)
397 {
398 PIO_STACK_LOCATION IrpSp;
399 NTSTATUS Status;
400
401 IrpSp = IoGetCurrentIrpStackLocation(Irp);
402
403 switch (IrpSp->MinorFunction)
404 {
405 case IRP_MN_START_DEVICE:
406 Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
407 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
408 Status = IntVideoPortPnPStartDevice(DeviceObject, Irp);
409 Irp->IoStatus.Status = Status;
410 Irp->IoStatus.Information = 0;
411 IoCompleteRequest(Irp, IO_NO_INCREMENT);
412 break;
413
414
415 case IRP_MN_REMOVE_DEVICE:
416 case IRP_MN_QUERY_REMOVE_DEVICE:
417 case IRP_MN_CANCEL_REMOVE_DEVICE:
418 case IRP_MN_SURPRISE_REMOVAL:
419
420 case IRP_MN_STOP_DEVICE:
421 Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
422 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
423 Status = STATUS_SUCCESS;
424 Irp->IoStatus.Status = Status;
425 Irp->IoStatus.Information = 0;
426 IoCompleteRequest(Irp, IO_NO_INCREMENT);
427 break;
428
429 case IRP_MN_QUERY_STOP_DEVICE:
430 case IRP_MN_CANCEL_STOP_DEVICE:
431 Status = STATUS_SUCCESS;
432 Irp->IoStatus.Status = STATUS_SUCCESS;
433 Irp->IoStatus.Information = 0;
434 IoCompleteRequest(Irp, IO_NO_INCREMENT);
435 break;
436
437 default:
438 return STATUS_NOT_IMPLEMENTED;
439 break;
440 }
441
442 return Status;
443 }
444
445 NTSTATUS NTAPI
446 IntVideoPortDispatchCleanup(
447 IN PDEVICE_OBJECT DeviceObject,
448 IN PIRP Irp)
449 {
450 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
451
452 DeviceExtension = DeviceObject->DeviceExtension;
453 RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
454
455 Irp->IoStatus.Status = STATUS_SUCCESS;
456 Irp->IoStatus.Information = 0;
457 IoCompleteRequest(Irp, IO_NO_INCREMENT);
458
459 return STATUS_SUCCESS;
460 }
461
462 NTSTATUS NTAPI
463 IntVideoPortDispatchPower(
464 IN PDEVICE_OBJECT DeviceObject,
465 IN PIRP Irp)
466 {
467 return STATUS_NOT_IMPLEMENTED;
468 }
469
470 VOID NTAPI
471 IntVideoPortUnload(PDRIVER_OBJECT DriverObject)
472 {
473 }