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