Inform HAL about the switch to graphics mode as late as possible. Fixes bug 880.
[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 */
22
23 #include "videoprt.h"
24
25 /* EXTERNAL FUNCTIONS *********************************************************/
26
27 VOID NTAPI HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters);
28 VOID NTAPI HalReleaseDisplayOwnership();
29
30 /* GLOBAL VARIABLES ***********************************************************/
31
32 PVIDEO_PORT_DEVICE_EXTENSION ResetDisplayParametersDeviceExtension = NULL;
33
34 /* PRIVATE FUNCTIONS **********************************************************/
35
36 /*
37 * Reset display to blue screen
38 */
39
40 BOOLEAN NTAPI
41 IntVideoPortResetDisplayParameters(ULONG Columns, ULONG Rows)
42 {
43 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
44
45 if (ResetDisplayParametersDeviceExtension == NULL)
46 return FALSE;
47
48 DriverExtension = ResetDisplayParametersDeviceExtension->DriverExtension;
49
50 if (DriverExtension->InitializationData.HwResetHw != NULL)
51 {
52 if (DriverExtension->InitializationData.HwResetHw(
53 &ResetDisplayParametersDeviceExtension->MiniPortDeviceExtension,
54 Columns, Rows))
55 {
56 ResetDisplayParametersDeviceExtension = NULL;
57 return TRUE;
58 }
59 }
60
61 ResetDisplayParametersDeviceExtension = NULL;
62 return FALSE;
63 }
64
65 NTSTATUS NTAPI
66 IntVideoPortAddDevice(
67 IN PDRIVER_OBJECT DriverObject,
68 IN PDEVICE_OBJECT PhysicalDeviceObject)
69 {
70 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
71
72 /*
73 * Get the initialization data we saved in VideoPortInitialize.
74 */
75
76 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
77
78 /*
79 * Create adapter device object.
80 */
81
82 return IntVideoPortCreateAdapterDeviceObject(
83 DriverObject,
84 DriverExtension,
85 PhysicalDeviceObject,
86 NULL);
87 }
88
89 /*
90 * IntVideoPortDispatchOpen
91 *
92 * Answer requests for Open calls.
93 *
94 * Run Level
95 * PASSIVE_LEVEL
96 */
97
98 NTSTATUS NTAPI
99 IntVideoPortDispatchOpen(
100 IN PDEVICE_OBJECT DeviceObject,
101 IN PIRP Irp)
102 {
103 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
104 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
105
106 DPRINT("IntVideoPortDispatchOpen\n");
107
108 if (CsrssInitialized == FALSE)
109 {
110 /*
111 * We know the first open call will be from the CSRSS process
112 * to let us know its handle.
113 */
114
115 DPRINT("Referencing CSRSS\n");
116 Csrss = (PKPROCESS)PsGetCurrentProcess();
117 DPRINT("Csrss %p\n", Csrss);
118
119 CsrssInitialized = TRUE;
120
121 Irp->IoStatus.Information = FILE_OPENED;
122 IoCompleteRequest(Irp, IO_NO_INCREMENT);
123
124 return STATUS_SUCCESS;
125 }
126
127 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
128 DriverExtension = DeviceExtension->DriverExtension;
129
130 if (DriverExtension->InitializationData.HwInitialize(&DeviceExtension->MiniPortDeviceExtension))
131 {
132 Irp->IoStatus.Status = STATUS_SUCCESS;
133
134 InterlockedIncrement((PLONG)&DeviceExtension->DeviceOpened);
135 }
136 else
137 {
138 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
139 }
140
141 Irp->IoStatus.Information = FILE_OPENED;
142 IoCompleteRequest(Irp, IO_NO_INCREMENT);
143
144 return STATUS_SUCCESS;
145 }
146
147 /*
148 * IntVideoPortDispatchClose
149 *
150 * Answer requests for Close calls.
151 *
152 * Run Level
153 * PASSIVE_LEVEL
154 */
155
156 NTSTATUS NTAPI
157 IntVideoPortDispatchClose(
158 IN PDEVICE_OBJECT DeviceObject,
159 IN PIRP Irp)
160 {
161 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
162
163 DPRINT("IntVideoPortDispatchClose\n");
164
165 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
166 if (DeviceExtension->DeviceOpened >= 1 &&
167 InterlockedDecrement((PLONG)&DeviceExtension->DeviceOpened) == 0)
168 {
169 ResetDisplayParametersDeviceExtension = DeviceExtension;
170 HalReleaseDisplayOwnership();
171 }
172
173 Irp->IoStatus.Status = STATUS_SUCCESS;
174 IoCompleteRequest(Irp, IO_NO_INCREMENT);
175
176 return STATUS_SUCCESS;
177 }
178
179 /*
180 * IntVideoPortDispatchDeviceControl
181 *
182 * Answer requests for device control calls.
183 *
184 * Run Level
185 * PASSIVE_LEVEL
186 */
187
188 NTSTATUS NTAPI
189 IntVideoPortDispatchDeviceControl(
190 IN PDEVICE_OBJECT DeviceObject,
191 IN PIRP Irp)
192 {
193 PIO_STACK_LOCATION IrpStack;
194 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
195 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
196 PVIDEO_REQUEST_PACKET vrp;
197 NTSTATUS Status;
198
199 DPRINT("IntVideoPortDispatchDeviceControl\n");
200
201 IrpStack = IoGetCurrentIrpStackLocation(Irp);
202 DeviceExtension = DeviceObject->DeviceExtension;
203 DriverExtension = DeviceExtension->DriverExtension;
204
205 /* Translate the IRP to a VRP */
206 vrp = ExAllocatePool(NonPagedPool, sizeof(VIDEO_REQUEST_PACKET));
207 if (NULL == vrp)
208 {
209 return STATUS_NO_MEMORY;
210 }
211
212 vrp->StatusBlock = (PSTATUS_BLOCK)&(Irp->IoStatus);
213 vrp->IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
214
215 DPRINT("- IoControlCode: %x\n", vrp->IoControlCode);
216
217 /* We're assuming METHOD_BUFFERED */
218 vrp->InputBuffer = Irp->AssociatedIrp.SystemBuffer;
219 vrp->InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
220 vrp->OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
221 vrp->OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
222
223 /* Call the Miniport Driver with the VRP */
224 DriverExtension->InitializationData.HwStartIO(
225 &DeviceExtension->MiniPortDeviceExtension,
226 vrp);
227
228 /* Free the VRP */
229 ExFreePool(vrp);
230
231 DPRINT("- Returned status: %x\n", Irp->IoStatus.Status);
232
233 if (Irp->IoStatus.Status != STATUS_SUCCESS)
234 {
235 /* Map from win32 error codes to NT status values. */
236 switch (Irp->IoStatus.Status)
237 {
238 case ERROR_NOT_ENOUGH_MEMORY: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; break;
239 case ERROR_MORE_DATA: Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; break;
240 case ERROR_INVALID_FUNCTION: Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; break;
241 case ERROR_INVALID_PARAMETER: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; break;
242 case ERROR_INSUFFICIENT_BUFFER: Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; break;
243 case ERROR_DEV_NOT_EXIST: Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; break;
244 case ERROR_IO_PENDING: Irp->IoStatus.Status = STATUS_PENDING; break;
245 }
246 }
247
248 Status = Irp->IoStatus.Status;
249 IoCompleteRequest(Irp, IO_NO_INCREMENT);
250
251 return Status;
252 }
253
254 /*
255 * IntVideoPortWrite
256 *
257 * This is a bit of a hack. We want to take ownership of the display as late
258 * as possible, just before the switch to graphics mode. Win32k knows when
259 * this happens, we don't. So we need Win32k to inform us. This could be done
260 * using an IOCTL, but there's no way of knowing which IOCTL codes are unused
261 * in the communication between GDI driver and miniport driver. So we use
262 * IRP_MJ_WRITE as the signal that win32k is ready to switch to graphics mode,
263 * since we know for certain that there is no read/write activity going on
264 * between GDI and miniport drivers.
265 * We don't actually need the data that is passed, we just trigger on the fact
266 * that an IRP_MJ_WRITE was sent.
267 *
268 * Run Level
269 * PASSIVE_LEVEL
270 */
271
272 NTSTATUS NTAPI
273 IntVideoPortDispatchWrite(
274 IN PDEVICE_OBJECT DeviceObject,
275 IN PIRP Irp)
276 {
277 PIO_STACK_LOCATION piosStack = IoGetCurrentIrpStackLocation(Irp);
278 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
279 NTSTATUS nErrCode;
280
281 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
282
283 /*
284 * Storing the device extension pointer in a static variable is an
285 * ugly hack. Unfortunately, we need it in VideoPortResetDisplayParameters
286 * and HalAcquireDisplayOwnership doesn't allow us to pass a userdata
287 * parameter. On the bright side, the DISPLAY device is opened
288 * exclusively, so there can be only one device extension active at
289 * any point in time.
290 */
291
292 ResetDisplayParametersDeviceExtension = DeviceExtension;
293 HalAcquireDisplayOwnership(IntVideoPortResetDisplayParameters);
294
295 nErrCode = STATUS_SUCCESS;
296 Irp->IoStatus.Information = piosStack->Parameters.Write.Length;
297 Irp->IoStatus.Status = nErrCode;
298 IoCompleteRequest(Irp, IO_NO_INCREMENT);
299
300 return nErrCode;
301 }
302
303
304 NTSTATUS NTAPI
305 IntVideoPortPnPStartDevice(
306 IN PDEVICE_OBJECT DeviceObject,
307 IN PIRP Irp)
308 {
309 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
310 PDRIVER_OBJECT DriverObject;
311 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
312 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
313 PCM_RESOURCE_LIST AllocatedResources;
314
315 /*
316 * Get the initialization data we saved in VideoPortInitialize.
317 */
318
319 DriverObject = DeviceObject->DriverObject;
320 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
321 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
322
323 /*
324 * Store some resources in the DeviceExtension.
325 */
326
327 AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources;
328 if (AllocatedResources != NULL)
329 {
330 CM_FULL_RESOURCE_DESCRIPTOR *FullList;
331 CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor;
332 ULONG ResourceCount;
333 ULONG ResourceListSize;
334
335 /* Save the resource list */
336 ResourceCount = AllocatedResources->List[0].PartialResourceList.Count;
337 ResourceListSize =
338 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
339 PartialDescriptors[ResourceCount]);
340 DeviceExtension->AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize);
341 if (DeviceExtension->AllocatedResources == NULL)
342 {
343 return STATUS_INSUFFICIENT_RESOURCES;
344 }
345
346 RtlCopyMemory(DeviceExtension->AllocatedResources,
347 AllocatedResources,
348 ResourceListSize);
349
350 /* Get the interrupt level/vector - needed by HwFindAdapter sometimes */
351 for (FullList = AllocatedResources->List;
352 FullList < AllocatedResources->List + AllocatedResources->Count;
353 FullList++)
354 {
355 /* FIXME: Is this ASSERT ok for resources from the PNP manager? */
356 ASSERT(FullList->InterfaceType == PCIBus &&
357 FullList->BusNumber == DeviceExtension->SystemIoBusNumber &&
358 1 == FullList->PartialResourceList.Version &&
359 1 == FullList->PartialResourceList.Revision);
360 for (Descriptor = FullList->PartialResourceList.PartialDescriptors;
361 Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count;
362 Descriptor++)
363 {
364 if (Descriptor->Type == CmResourceTypeInterrupt)
365 {
366 DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level;
367 DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector;
368 if (Descriptor->ShareDisposition == CmResourceShareShared)
369 DeviceExtension->InterruptShared = TRUE;
370 else
371 DeviceExtension->InterruptShared = FALSE;
372 }
373 }
374 }
375 }
376 DPRINT("Interrupt level: 0x%x Interrupt Vector: 0x%x\n",
377 DeviceExtension->InterruptLevel,
378 DeviceExtension->InterruptVector);
379
380 /*
381 * Create adapter device object.
382 */
383
384 return IntVideoPortFindAdapter(
385 DriverObject,
386 DriverExtension,
387 DeviceObject);
388 }
389
390
391 NTSTATUS
392 NTAPI
393 IntVideoPortForwardIrpAndWaitCompletionRoutine(
394 PDEVICE_OBJECT Fdo,
395 PIRP Irp,
396 PVOID Context)
397 {
398 PKEVENT Event = Context;
399
400 if (Irp->PendingReturned)
401 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
402
403 return STATUS_MORE_PROCESSING_REQUIRED;
404 }
405
406
407 NTSTATUS
408 NTAPI
409 IntVideoPortForwardIrpAndWait(PDEVICE_OBJECT DeviceObject, PIRP Irp)
410 {
411 KEVENT Event;
412 NTSTATUS Status;
413 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension =
414 (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
415
416 KeInitializeEvent(&Event, NotificationEvent, FALSE);
417 IoCopyCurrentIrpStackLocationToNext(Irp);
418 IoSetCompletionRoutine(Irp, IntVideoPortForwardIrpAndWaitCompletionRoutine,
419 &Event, TRUE, TRUE, TRUE);
420 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
421 if (Status == STATUS_PENDING)
422 {
423 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
424 Status = Irp->IoStatus.Status;
425 }
426 return Status;
427 }
428
429
430 NTSTATUS NTAPI
431 IntVideoPortDispatchPnp(
432 IN PDEVICE_OBJECT DeviceObject,
433 IN PIRP Irp)
434 {
435 PIO_STACK_LOCATION IrpSp;
436 NTSTATUS Status;
437
438 IrpSp = IoGetCurrentIrpStackLocation(Irp);
439
440 switch (IrpSp->MinorFunction)
441 {
442 case IRP_MN_START_DEVICE:
443 Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
444 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
445 Status = IntVideoPortPnPStartDevice(DeviceObject, Irp);
446 Irp->IoStatus.Status = Status;
447 Irp->IoStatus.Information = 0;
448 IoCompleteRequest(Irp, IO_NO_INCREMENT);
449 break;
450
451
452 case IRP_MN_REMOVE_DEVICE:
453 case IRP_MN_QUERY_REMOVE_DEVICE:
454 case IRP_MN_CANCEL_REMOVE_DEVICE:
455 case IRP_MN_SURPRISE_REMOVAL:
456
457 case IRP_MN_STOP_DEVICE:
458 Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
459 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
460 Status = STATUS_SUCCESS;
461 Irp->IoStatus.Status = Status;
462 Irp->IoStatus.Information = 0;
463 IoCompleteRequest(Irp, IO_NO_INCREMENT);
464 break;
465
466 case IRP_MN_QUERY_STOP_DEVICE:
467 case IRP_MN_CANCEL_STOP_DEVICE:
468 Status = STATUS_SUCCESS;
469 Irp->IoStatus.Status = STATUS_SUCCESS;
470 Irp->IoStatus.Information = 0;
471 IoCompleteRequest(Irp, IO_NO_INCREMENT);
472 break;
473
474 default:
475 return STATUS_NOT_IMPLEMENTED;
476 break;
477 }
478
479 return Status;
480 }
481
482 NTSTATUS NTAPI
483 IntVideoPortDispatchCleanup(
484 IN PDEVICE_OBJECT DeviceObject,
485 IN PIRP Irp)
486 {
487 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
488
489 DeviceExtension = DeviceObject->DeviceExtension;
490 RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
491
492 Irp->IoStatus.Status = STATUS_SUCCESS;
493 Irp->IoStatus.Information = 0;
494 IoCompleteRequest(Irp, IO_NO_INCREMENT);
495
496 return STATUS_SUCCESS;
497 }
498
499 NTSTATUS NTAPI
500 IntVideoPortDispatchPower(
501 IN PDEVICE_OBJECT DeviceObject,
502 IN PIRP Irp)
503 {
504 return STATUS_NOT_IMPLEMENTED;
505 }
506
507 VOID NTAPI
508 IntVideoPortUnload(PDRIVER_OBJECT DriverObject)
509 {
510 }