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