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 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 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 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 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 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 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 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 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 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