xref: /reactos/win32ss/drivers/videoprt/child.c (revision 9393fc32)
1 /*
2  * VideoPort driver
3  *
4  * Copyright (C) 2012 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 #include <stdio.h>
24 
25 #define NDEBUG
26 #include <debug.h>
27 
28 /* PRIVATE FUNCTIONS **********************************************************/
29 
30 BOOLEAN
31 NTAPI
IntVideoPortGetMonitorId(IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,IN OUT PWCHAR Buffer)32 IntVideoPortGetMonitorId(
33     IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,
34     IN OUT PWCHAR Buffer)
35 {
36     USHORT Manufacturer, Model;
37 
38     /* This must be valid to call this function */
39     ASSERT(ChildExtension->EdidValid);
40 
41     /* 3 letters 5-bit ANSI manufacturer code (big endian) */
42     /* Letters encoded as A=1 to Z=26 */
43     Manufacturer = ((USHORT)ChildExtension->ChildDescriptor[8] << 8) +
44                    (USHORT)ChildExtension->ChildDescriptor[9];
45 
46     /* Model number (16-bit little endian) */
47     Model = ((USHORT)ChildExtension->ChildDescriptor[11] << 8) +
48              (USHORT)ChildExtension->ChildDescriptor[10];
49 
50     /* Convert the Monitor ID to a readable form */
51     swprintf(Buffer,
52              L"%C%C%C%04hx",
53              (WCHAR)((Manufacturer >> 10 & 0x001F) + 'A' - 1),
54              (WCHAR)((Manufacturer >> 5 & 0x001F) + 'A' - 1),
55              (WCHAR)((Manufacturer & 0x001F) + 'A' - 1),
56              Model);
57 
58     /* And we're done */
59     return TRUE;
60 }
61 
62 BOOLEAN
63 NTAPI
IntVideoPortSearchDescriptor(IN PUCHAR Descriptor,IN UCHAR DescriptorID,OUT PUCHAR * pDescriptorData)64 IntVideoPortSearchDescriptor(
65     IN PUCHAR Descriptor,
66     IN UCHAR DescriptorID,
67     OUT PUCHAR* pDescriptorData)
68 {
69     if (Descriptor[0] != 0 || Descriptor[1] != 0 || Descriptor[2] != 0)
70         return FALSE;
71     if (Descriptor[3] != DescriptorID)
72         return FALSE;
73 
74     *pDescriptorData = Descriptor + 4;
75     return TRUE;
76 }
77 
78 BOOLEAN
79 NTAPI
IntVideoPortSearchDescriptors(IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,IN UCHAR DescriptorID,OUT PUCHAR * pDescriptorData)80 IntVideoPortSearchDescriptors(
81     IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,
82     IN UCHAR DescriptorID,
83     OUT PUCHAR* pDescriptorData)
84 {
85     if (!ChildExtension->EdidValid)
86         return FALSE;
87 
88     if (IntVideoPortSearchDescriptor(ChildExtension->ChildDescriptor + 0x36, DescriptorID, pDescriptorData))
89         return TRUE;
90     if (IntVideoPortSearchDescriptor(ChildExtension->ChildDescriptor + 0x48, DescriptorID, pDescriptorData))
91         return TRUE;
92     if (IntVideoPortSearchDescriptor(ChildExtension->ChildDescriptor + 0x5A, DescriptorID, pDescriptorData))
93         return TRUE;
94     if (IntVideoPortSearchDescriptor(ChildExtension->ChildDescriptor + 0x6C, DescriptorID, pDescriptorData))
95         return TRUE;
96 
97     /* FIXME: search in extension? */
98     return FALSE;
99 }
100 
101 BOOLEAN
102 NTAPI
IntVideoPortGetMonitorDescription(IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,OUT PCHAR * pMonitorDescription)103 IntVideoPortGetMonitorDescription(
104     IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,
105     OUT PCHAR* pMonitorDescription)
106 {
107     PUCHAR MonitorDescription;
108 
109     if (!IntVideoPortSearchDescriptors(ChildExtension, 0xFC, &MonitorDescription))
110         return FALSE;
111 
112     *pMonitorDescription = (PCHAR)MonitorDescription;
113     return TRUE;
114 }
115 
116 NTSTATUS NTAPI
IntVideoPortChildQueryId(IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)117 IntVideoPortChildQueryId(
118     IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,
119     IN PIRP Irp,
120     IN PIO_STACK_LOCATION IrpSp)
121 {
122     PWCHAR Buffer = NULL, StaticBuffer;
123     UNICODE_STRING UnicodeStr;
124 
125     switch (IrpSp->Parameters.QueryId.IdType)
126     {
127         case BusQueryDeviceID:
128             switch (ChildExtension->ChildType)
129             {
130                 case Monitor:
131                     if (ChildExtension->EdidValid)
132                     {
133                         StaticBuffer = L"DISPLAY\\";
134                         Buffer = ExAllocatePool(PagedPool, (wcslen(StaticBuffer) + 8) * sizeof(WCHAR));
135                         if (!Buffer) return STATUS_NO_MEMORY;
136 
137                         /* Write the static portion */
138                         RtlCopyMemory(Buffer, StaticBuffer, wcslen(StaticBuffer) * sizeof(WCHAR));
139 
140                         /* Add the dynamic portion */
141                         IntVideoPortGetMonitorId(ChildExtension,
142                                                  &Buffer[wcslen(StaticBuffer)]);
143                     }
144                     else
145                     {
146                         StaticBuffer = L"DISPLAY\\Default_Monitor";
147                         Buffer = ExAllocatePool(PagedPool, (wcslen(StaticBuffer) + 1) * sizeof(WCHAR));
148                         if (!Buffer) return STATUS_NO_MEMORY;
149 
150                         /* Copy the default id */
151                         RtlCopyMemory(Buffer, StaticBuffer, (wcslen(StaticBuffer) + 1) * sizeof(WCHAR));
152                     }
153                     break;
154                 default:
155                     ASSERT(FALSE);
156                     break;
157             }
158             break;
159         case BusQueryInstanceID:
160             Buffer = ExAllocatePool(PagedPool, 5 * sizeof(WCHAR));
161             if (!Buffer) return STATUS_NO_MEMORY;
162 
163             UnicodeStr.Buffer = Buffer;
164             UnicodeStr.Length = 0;
165             UnicodeStr.MaximumLength = 4 * sizeof(WCHAR);
166             RtlIntegerToUnicodeString(ChildExtension->ChildId, 16, &UnicodeStr);
167             break;
168         case BusQueryHardwareIDs:
169             switch (ChildExtension->ChildType)
170             {
171                 case Monitor:
172                     if (ChildExtension->EdidValid)
173                     {
174                         StaticBuffer = L"MONITOR\\";
175                         Buffer = ExAllocatePool(PagedPool, (wcslen(StaticBuffer) + 9) * sizeof(WCHAR));
176                         if (!Buffer) return STATUS_NO_MEMORY;
177 
178                         /* Write the static portion */
179                         RtlCopyMemory(Buffer, StaticBuffer, wcslen(StaticBuffer) * sizeof(WCHAR));
180 
181                         /* Add the dynamic portion */
182                         IntVideoPortGetMonitorId(ChildExtension,
183                                                  &Buffer[wcslen(StaticBuffer)]);
184 
185                         /* Add the second null termination char */
186                         Buffer[wcslen(StaticBuffer) + 8] = UNICODE_NULL;
187                     }
188                     else
189                     {
190                         StaticBuffer = L"MONITOR\\Default_Monitor";
191                         Buffer = ExAllocatePool(PagedPool, (wcslen(StaticBuffer) + 2) * sizeof(WCHAR));
192                         if (!Buffer) return STATUS_NO_MEMORY;
193 
194                         /* Copy the default id */
195                         RtlCopyMemory(Buffer, StaticBuffer, (wcslen(StaticBuffer) + 1) * sizeof(WCHAR));
196 
197                         /* Add the second null terminator */
198                         Buffer[wcslen(StaticBuffer) + 1] = UNICODE_NULL;
199                     }
200                     break;
201                 default:
202                     ASSERT(FALSE);
203                     break;
204             }
205             break;
206         case BusQueryCompatibleIDs:
207             switch (ChildExtension->ChildType)
208             {
209                 case Monitor:
210                     if (ChildExtension->EdidValid)
211                     {
212                         StaticBuffer = L"*PNP09FF";
213                         Buffer = ExAllocatePool(PagedPool, (wcslen(StaticBuffer) + 2) * sizeof(WCHAR));
214                         if (!Buffer) return STATUS_NO_MEMORY;
215 
216                         RtlCopyMemory(Buffer, StaticBuffer, (wcslen(StaticBuffer) + 1) * sizeof(WCHAR));
217 
218                         Buffer[wcslen(StaticBuffer)+1] = UNICODE_NULL;
219                     }
220                     else
221                     {
222                         /* No PNP ID for non-PnP monitors */
223                         return Irp->IoStatus.Status;
224                     }
225                     break;
226                 default:
227                     ASSERT(FALSE);
228                     break;
229             }
230             break;
231         default:
232             return Irp->IoStatus.Status;
233     }
234 
235     INFO_(VIDEOPRT, "Reporting ID: %S\n", Buffer);
236     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
237 
238     return STATUS_SUCCESS;
239 }
240 
241 NTSTATUS NTAPI
IntVideoPortChildQueryText(IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)242 IntVideoPortChildQueryText(
243     IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,
244     IN PIRP Irp,
245     IN PIO_STACK_LOCATION IrpSp)
246 {
247     ANSI_STRING StringA;
248     UNICODE_STRING StringU;
249     NTSTATUS Status;
250 
251     if (IrpSp->Parameters.QueryDeviceText.DeviceTextType != DeviceTextDescription)
252         return Irp->IoStatus.Status;
253 
254     switch (ChildExtension->ChildType)
255     {
256         case Monitor:
257             if (IntVideoPortGetMonitorDescription(ChildExtension,
258                                                   &StringA.Buffer))
259             {
260                 StringA.Buffer++; /* Skip reserved byte */
261                 StringA.MaximumLength = 13;
262                 for (StringA.Length = 0;
263                      StringA.Length < StringA.MaximumLength && StringA.Buffer[StringA.Length] != '\n';
264                      StringA.Length++)
265                     ;
266             }
267             else
268                 RtlInitAnsiString(&StringA, "Monitor");
269             break;
270 
271         case VideoChip:
272             /* FIXME: No idea what we return here */
273             RtlInitAnsiString(&StringA, "Video chip");
274             break;
275 
276         default: /* Other */
277             RtlInitAnsiString(&StringA, "Other device");
278             break;
279     }
280 
281     Status = RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
282     if (!NT_SUCCESS(Status))
283         return Status;
284 
285     INFO_(VIDEOPRT, "Reporting description: %S\n", StringU.Buffer);
286     Irp->IoStatus.Information = (ULONG_PTR)StringU.Buffer;
287 
288     return STATUS_SUCCESS;
289 }
290 
291 NTSTATUS NTAPI
IntVideoPortChildQueryRelations(IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)292 IntVideoPortChildQueryRelations(
293     IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,
294     IN PIRP Irp,
295     IN PIO_STACK_LOCATION IrpSp)
296 {
297     PDEVICE_RELATIONS DeviceRelations;
298 
299     if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
300     {
301         WARN_(VIDEOPRT, "Unsupported device relations type\n");
302         return Irp->IoStatus.Status;
303     }
304 
305     DeviceRelations = ExAllocatePool(NonPagedPool, sizeof(DEVICE_RELATIONS));
306     if (!DeviceRelations) return STATUS_NO_MEMORY;
307 
308     DeviceRelations->Count = 1;
309     DeviceRelations->Objects[0] = ChildExtension->PhysicalDeviceObject;
310 
311     ObReferenceObject(DeviceRelations->Objects[0]);
312 
313     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
314 
315     return STATUS_SUCCESS;
316 }
317 
318 NTSTATUS NTAPI
IntVideoPortChildQueryCapabilities(IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)319 IntVideoPortChildQueryCapabilities(
320     IN PVIDEO_PORT_CHILD_EXTENSION ChildExtension,
321     IN PIRP Irp,
322     IN PIO_STACK_LOCATION IrpSp)
323 {
324     PDEVICE_CAPABILITIES DeviceCaps = IrpSp->Parameters.DeviceCapabilities.Capabilities;
325     ULONG i;
326 
327     /* Set some values */
328     DeviceCaps->LockSupported = FALSE;
329     DeviceCaps->EjectSupported = FALSE;
330     DeviceCaps->DockDevice = FALSE;
331     DeviceCaps->UniqueID = FALSE;
332     DeviceCaps->RawDeviceOK = FALSE;
333     DeviceCaps->WakeFromD0 = FALSE;
334     DeviceCaps->WakeFromD1 = FALSE;
335     DeviceCaps->WakeFromD2 = FALSE;
336     DeviceCaps->WakeFromD3 = FALSE;
337     DeviceCaps->HardwareDisabled = FALSE;
338     DeviceCaps->NoDisplayInUI = FALSE;
339 
340     /* Address and UI number are set by default */
341 
342     DeviceCaps->DeviceState[PowerSystemWorking] = PowerDeviceD0;
343     for (i = 1; i < POWER_SYSTEM_MAXIMUM; i++)
344     {
345         DeviceCaps->DeviceState[i] = PowerDeviceD3;
346     }
347 
348     DeviceCaps->SystemWake = PowerSystemUnspecified;
349     DeviceCaps->DeviceWake = PowerDeviceUnspecified;
350 
351     /* FIXME: Device power states */
352     DeviceCaps->DeviceD1 = FALSE;
353     DeviceCaps->DeviceD2 = FALSE;
354     DeviceCaps->D1Latency = 0;
355     DeviceCaps->D2Latency = 0;
356     DeviceCaps->D3Latency = 0;
357 
358     switch (ChildExtension->ChildType)
359     {
360         case VideoChip:
361             /* FIXME: Copy capabilities from parent */
362             ASSERT(FALSE);
363             break;
364 
365         case NonPrimaryChip: /* Reserved */
366             ASSERT(FALSE);
367             break;
368 
369         case Monitor:
370             DeviceCaps->SilentInstall = TRUE;
371             DeviceCaps->Removable = TRUE;
372             DeviceCaps->SurpriseRemovalOK = TRUE;
373             break;
374 
375         default: /* Other */
376             DeviceCaps->SilentInstall = FALSE;
377             DeviceCaps->Removable = FALSE;
378             DeviceCaps->SurpriseRemovalOK = FALSE;
379             break;
380     }
381 
382     return STATUS_SUCCESS;
383 }
384 
385 NTSTATUS NTAPI
IntVideoPortDispatchPdoPnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)386 IntVideoPortDispatchPdoPnp(
387     IN PDEVICE_OBJECT DeviceObject,
388     IN PIRP Irp)
389 {
390     PIO_STACK_LOCATION IrpSp;
391     NTSTATUS Status = Irp->IoStatus.Status;
392 
393     IrpSp = IoGetCurrentIrpStackLocation(Irp);
394 
395     switch (IrpSp->MinorFunction)
396     {
397         case IRP_MN_START_DEVICE:
398         case IRP_MN_STOP_DEVICE:
399             /* Nothing to do */
400             Status = STATUS_SUCCESS;
401             break;
402 
403         case IRP_MN_QUERY_RESOURCES:
404         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
405             /* None (keep old status) */
406             break;
407 
408         case IRP_MN_QUERY_ID:
409             /* Call our helper */
410             Status = IntVideoPortChildQueryId(DeviceObject->DeviceExtension,
411                                               Irp,
412                                               IrpSp);
413             break;
414 
415         case IRP_MN_QUERY_CAPABILITIES:
416             /* Call our helper */
417             Status = IntVideoPortChildQueryCapabilities(DeviceObject->DeviceExtension,
418                                                         Irp,
419                                                         IrpSp);
420             break;
421 
422         case IRP_MN_SURPRISE_REMOVAL:
423         case IRP_MN_QUERY_REMOVE_DEVICE:
424             Status = STATUS_SUCCESS;
425             break;
426 
427         case IRP_MN_REMOVE_DEVICE:
428             Irp->IoStatus.Status = STATUS_SUCCESS;
429             IoCompleteRequest(Irp, IO_NO_INCREMENT);
430             IoDeleteDevice(DeviceObject);
431             return STATUS_SUCCESS;
432 
433         case IRP_MN_QUERY_DEVICE_RELATIONS:
434             /* Call our helper */
435             Status = IntVideoPortChildQueryRelations(DeviceObject->DeviceExtension,
436                                                      Irp,
437                                                      IrpSp);
438             break;
439 
440         case IRP_MN_QUERY_DEVICE_TEXT:
441             /* Call our helper */
442             Status = IntVideoPortChildQueryText(DeviceObject->DeviceExtension,
443                                                 Irp,
444                                                 IrpSp);
445             break;
446 
447         default:
448             break;
449     }
450 
451     Irp->IoStatus.Status = Status;
452 
453     IoCompleteRequest(Irp, IO_NO_INCREMENT);
454 
455     return Status;
456 }
457