1 /* 2 * PROJECT: ReactOS VT100 emulator 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: drivers/base/green/pnp.c 5 * PURPOSE: IRP_MJ_PNP operations 6 * PROGRAMMERS: Copyright 2005-2006 Herv� Poussineau (hpoussin@reactos.org) 7 */ 8 9 #include "green.h" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 static NTSTATUS 15 CreateGreenFdo( 16 IN PDRIVER_OBJECT DriverObject, 17 IN PDEVICE_OBJECT GreenPdo) 18 { 19 PGREEN_DRIVER_EXTENSION DriverExtension = NULL; 20 PGREEN_DEVICE_EXTENSION DeviceExtension = NULL; 21 OBJECT_ATTRIBUTES ObjectAttributes; 22 ULONG Fcr; 23 HANDLE LocalHandle = 0; 24 ACCESS_MASK DesiredAccess = FILE_ANY_ACCESS; 25 NTSTATUS Status; 26 27 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); 28 29 Status = IoCreateDevice( 30 DriverObject, 31 sizeof(GREEN_DEVICE_EXTENSION), 32 NULL, 33 FILE_DEVICE_TERMSRV, 34 FILE_DEVICE_SECURE_OPEN, 35 FALSE, 36 &DriverExtension->GreenMainDO); 37 if (!NT_SUCCESS(Status)) 38 { 39 DPRINT("IoCreateDevice() failed with status %08lx\n", Status); 40 goto cleanup; 41 } 42 43 DeviceExtension = (PGREEN_DEVICE_EXTENSION)DriverExtension->GreenMainDO->DeviceExtension; 44 RtlZeroMemory(DeviceExtension, sizeof(GREEN_DEVICE_EXTENSION)); 45 DeviceExtension->Common.Type = GreenFDO; 46 DriverExtension->GreenMainDO->Flags |= DO_POWER_PAGABLE; 47 DriverExtension->LowerDevice = IoAttachDeviceToDeviceStack(DriverExtension->GreenMainDO, GreenPdo); 48 49 /* Initialize serial port */ 50 InitializeObjectAttributes(&ObjectAttributes, &DriverExtension->AttachedDeviceName, OBJ_KERNEL_HANDLE, NULL, NULL); 51 Status = ObOpenObjectByName( 52 &ObjectAttributes, 53 *IoFileObjectType, 54 KernelMode, 55 NULL, 56 DesiredAccess, 57 NULL, 58 &LocalHandle); 59 if (!NT_SUCCESS(Status)) 60 { 61 DPRINT("ObOpenObjectByName() failed with status %08lx\n", Status); 62 goto cleanup; 63 } 64 Status = ObReferenceObjectByHandle( 65 LocalHandle, 66 DesiredAccess, 67 NULL, 68 KernelMode, 69 (PVOID*)&DeviceExtension->Serial, 70 NULL); 71 if (!NT_SUCCESS(Status)) 72 { 73 DPRINT("ObReferenceObjectByHandle() failed with status %08lx\n", Status); 74 goto cleanup; 75 } 76 Fcr = 0; 77 Status = GreenDeviceIoControl(DeviceExtension->Serial, IOCTL_SERIAL_SET_FIFO_CONTROL, 78 &Fcr, sizeof(Fcr), NULL, NULL); 79 if (!NT_SUCCESS(Status)) 80 { 81 DPRINT("GreenDeviceIoControl() failed with status %08lx\n", Status); 82 goto cleanup; 83 } 84 Status = GreenDeviceIoControl(DeviceExtension->Serial, IOCTL_SERIAL_SET_BAUD_RATE, 85 &DriverExtension->SampleRate, sizeof(DriverExtension->SampleRate), NULL, NULL); 86 if (!NT_SUCCESS(Status)) 87 { 88 DPRINT("GreenDeviceIoControl() failed with status %08lx\n", Status); 89 goto cleanup; 90 } 91 DeviceExtension->LineControl.WordLength = 8; 92 DeviceExtension->LineControl.Parity = NO_PARITY; 93 DeviceExtension->LineControl.StopBits = STOP_BIT_1; 94 Status = GreenDeviceIoControl(DeviceExtension->Serial, IOCTL_SERIAL_SET_LINE_CONTROL, 95 &DeviceExtension->LineControl, sizeof(SERIAL_LINE_CONTROL), NULL, NULL); 96 if (!NT_SUCCESS(Status)) 97 { 98 DPRINT("GreenDeviceIoControl() failed with status %08lx\n", Status); 99 goto cleanup; 100 } 101 RtlZeroMemory(&DeviceExtension->Timeouts, sizeof(SERIAL_TIMEOUTS)); 102 DeviceExtension->Timeouts.ReadIntervalTimeout = 100; 103 Status = GreenDeviceIoControl(DeviceExtension->Serial, IOCTL_SERIAL_SET_TIMEOUTS, 104 &DeviceExtension->Timeouts, sizeof(SERIAL_TIMEOUTS), NULL, NULL); 105 if (!NT_SUCCESS(Status)) 106 { 107 DPRINT("GreenDeviceIoControl() failed with status %08lx\n", Status); 108 goto cleanup; 109 } 110 111 DriverExtension->GreenMainDO->Flags |= DO_BUFFERED_IO; 112 DriverExtension->GreenMainDO->Flags &= ~DO_DEVICE_INITIALIZING; 113 114 Status = STATUS_SUCCESS; 115 116 cleanup: 117 if (LocalHandle != 0) 118 ZwClose(LocalHandle); 119 if (!NT_SUCCESS(Status)) 120 { 121 if (DeviceExtension && DeviceExtension->Serial) 122 ObDereferenceObject(DeviceExtension->Serial); 123 if (DriverExtension) 124 { 125 if (DriverExtension->LowerDevice) 126 { 127 IoDetachDevice(DriverExtension->LowerDevice); 128 DriverExtension->LowerDevice = NULL; 129 } 130 if (DriverExtension->GreenMainDO) 131 { 132 IoDeleteDevice(DriverExtension->GreenMainDO); 133 DriverExtension->GreenMainDO = NULL; 134 } 135 } 136 } 137 return Status; 138 } 139 140 static NTSTATUS 141 ReportGreenPdo( 142 IN PDRIVER_OBJECT DriverObject, 143 IN PGREEN_DRIVER_EXTENSION DriverExtension) 144 { 145 PDEVICE_OBJECT GreenPdo = NULL; 146 NTSTATUS Status; 147 148 /* Create green PDO */ 149 Status = IoReportDetectedDevice( 150 DriverObject, 151 InterfaceTypeUndefined, -1, -1, 152 NULL, NULL, TRUE, 153 &GreenPdo); 154 if (!NT_SUCCESS(Status)) 155 { 156 DPRINT("IoReportDetectedDevice() failed with status 0x%lx\n", Status); 157 goto cleanup; 158 } 159 160 /* Create green FDO */ 161 Status = CreateGreenFdo(DriverObject, GreenPdo); 162 163 IoInvalidateDeviceRelations(GreenPdo, BusRelations); 164 165 /* FIXME: Update registry, set "DeviceReported" to 1 */ 166 167 Status = STATUS_SUCCESS; 168 169 cleanup: 170 if (!NT_SUCCESS(Status)) 171 { 172 if (DriverExtension->GreenMainDO) 173 IoDeleteDevice(DriverExtension->GreenMainDO); 174 } 175 return Status; 176 } 177 178 NTSTATUS NTAPI 179 GreenAddDevice( 180 IN PDRIVER_OBJECT DriverObject, 181 IN PDEVICE_OBJECT Pdo) 182 { 183 PGREEN_DRIVER_EXTENSION DriverExtension; 184 185 DPRINT("AddDevice(DriverObject %p, Pdo %p)\n", DriverObject, Pdo); 186 187 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); 188 189 if (Pdo == NULL) 190 { 191 if (DriverExtension->DeviceReported) 192 /* Green Pdo has already been reported during a previous boot. 193 * We will get another AddDevice call soon. 194 */ 195 return STATUS_SUCCESS; 196 else 197 return ReportGreenPdo(DriverObject, DriverExtension); 198 } 199 else if (DriverExtension->GreenMainDO == NULL) 200 { 201 return CreateGreenFdo(DriverObject, Pdo); 202 } 203 else 204 { 205 PGREEN_DEVICE_EXTENSION GreenDeviceExtension; 206 207 GreenDeviceExtension = (PGREEN_DEVICE_EXTENSION)DriverExtension->GreenMainDO->DeviceExtension; 208 if (Pdo == GreenDeviceExtension->KeyboardPdo) 209 return KeyboardAddDevice(DriverObject, Pdo); 210 else if (Pdo == GreenDeviceExtension->ScreenPdo) 211 return ScreenAddDevice(DriverObject, Pdo); 212 else 213 /* Strange PDO. We don't know it */ 214 ASSERT(FALSE); 215 return STATUS_UNSUCCESSFUL; 216 } 217 } 218 219 static NTSTATUS 220 GreenQueryBusRelations( 221 IN PDEVICE_OBJECT DeviceObject, 222 OUT PDEVICE_RELATIONS* pDeviceRelations) 223 { 224 PGREEN_DEVICE_EXTENSION DeviceExtension; 225 PDEVICE_RELATIONS DeviceRelations = NULL; 226 NTSTATUS Status; 227 228 DeviceExtension = (PGREEN_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 229 230 /* Create PDOs for keyboard and screen */ 231 if (DeviceExtension->KeyboardPdo == NULL) 232 { 233 Status = IoCreateDevice( 234 DeviceObject->DriverObject, 235 sizeof(COMMON_DEVICE_EXTENSION), 236 NULL, 237 FILE_DEVICE_KEYBOARD, 238 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, 239 FALSE, 240 &DeviceExtension->KeyboardPdo); 241 if (!NT_SUCCESS(Status)) 242 { 243 DPRINT("IoCreateDevice() failed with status 0x%lx\n", Status); 244 goto cleanup; 245 } 246 ((PCOMMON_DEVICE_EXTENSION)DeviceExtension->KeyboardPdo->DeviceExtension)->Type = KeyboardPDO; 247 DeviceExtension->KeyboardPdo->Flags |= DO_POWER_PAGABLE | DO_BUS_ENUMERATED_DEVICE; 248 DeviceExtension->KeyboardPdo->Flags &= ~DO_DEVICE_INITIALIZING; 249 } 250 251 if (DeviceExtension->ScreenPdo == NULL) 252 { 253 Status = IoCreateDevice( 254 DeviceObject->DriverObject, 255 sizeof(COMMON_DEVICE_EXTENSION), 256 NULL, 257 FILE_DEVICE_SCREEN, 258 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, 259 FALSE, 260 &DeviceExtension->ScreenPdo); 261 if (!NT_SUCCESS(Status)) 262 { 263 DPRINT("IoCreateDevice() failed with status 0x%lx\n", Status); 264 goto cleanup; 265 } 266 ((PCOMMON_DEVICE_EXTENSION)DeviceExtension->ScreenPdo->DeviceExtension)->Type = ScreenPDO; 267 DeviceExtension->ScreenPdo->Flags |= DO_POWER_PAGABLE | DO_BUS_ENUMERATED_DEVICE; 268 DeviceExtension->ScreenPdo->Flags &= ~DO_DEVICE_INITIALIZING; 269 } 270 271 /* Allocate return structure */ 272 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool( 273 PagedPool, 274 FIELD_OFFSET(DEVICE_RELATIONS, Objects) + 2 * sizeof(PDEVICE_OBJECT)); 275 if (!DeviceRelations) 276 return STATUS_INSUFFICIENT_RESOURCES; 277 278 /* Fill return structure */ 279 DeviceRelations->Count = 2; 280 ObReferenceObject(DeviceExtension->KeyboardPdo); 281 ObReferenceObject(DeviceExtension->ScreenPdo); 282 DeviceRelations->Objects[0] = DeviceExtension->KeyboardPdo; 283 DeviceRelations->Objects[1] = DeviceExtension->ScreenPdo; 284 285 *pDeviceRelations = DeviceRelations; 286 Status = STATUS_SUCCESS; 287 288 cleanup: 289 if (!NT_SUCCESS(Status)) 290 { 291 if (DeviceRelations) 292 { 293 ULONG i; 294 for (i = 0; i < DeviceRelations->Count; i++) 295 ObDereferenceObject(DeviceRelations->Objects[i]); 296 ExFreePool(DeviceRelations); 297 } 298 if (DeviceExtension->KeyboardPdo) 299 { 300 IoDeleteDevice(DeviceExtension->KeyboardPdo); 301 DeviceExtension->KeyboardPdo = NULL; 302 } 303 if (DeviceExtension->ScreenPdo) 304 { 305 IoDeleteDevice(DeviceExtension->ScreenPdo); 306 DeviceExtension->ScreenPdo = NULL; 307 } 308 } 309 return Status; 310 } 311 312 static NTSTATUS 313 GreenQueryId( 314 IN PDEVICE_OBJECT DeviceObject, 315 IN PIRP Irp, 316 OUT ULONG_PTR* Information) 317 { 318 GREEN_DEVICE_TYPE Type; 319 ULONG IdType; 320 NTSTATUS Status = Irp->IoStatus.Status; 321 322 Type = ((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Type; 323 IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType; 324 325 switch (IdType) 326 { 327 case BusQueryDeviceID: 328 { 329 LPCWSTR Source = NULL; 330 331 if (Type == ScreenPDO) 332 Source = L"GREEN\\SCREEN"; 333 else if (Type == KeyboardPDO) 334 Source = L"GREEN\\KEYBOARD"; 335 else 336 { 337 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceId / Unknown type 0x%lx\n", 338 Type); 339 ASSERT(FALSE); 340 } 341 342 if (Source) 343 { 344 UNICODE_STRING SourceU, String; 345 RtlInitUnicodeString(&SourceU, Source); 346 Status = GreenDuplicateUnicodeString( 347 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 348 &SourceU, 349 &String); 350 *Information = (ULONG_PTR)String.Buffer; 351 } 352 break; 353 } 354 case BusQueryHardwareIDs: 355 { 356 UNICODE_STRING SourceU = { 0, }; 357 358 if (Type == ScreenPDO) 359 { 360 RtlInitUnicodeString(&SourceU, L"GREEN\\SCREEN\0"); 361 /* We can add the two \0 that are at the end of the string */ 362 SourceU.Length = SourceU.MaximumLength = SourceU.Length + 2 * sizeof(WCHAR); 363 } 364 else if (Type == KeyboardPDO) 365 { 366 RtlInitUnicodeString(&SourceU, L"GREEN\\KEYBOARD\0"); 367 /* We can add the two \0 that are at the end of the string */ 368 SourceU.Length = SourceU.MaximumLength = SourceU.Length + 2 * sizeof(WCHAR); 369 } 370 else 371 { 372 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs / Unknown type 0x%lx\n", 373 Type); 374 ASSERT(FALSE); 375 } 376 377 if (SourceU.Length) 378 { 379 UNICODE_STRING String; 380 Status = GreenDuplicateUnicodeString( 381 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 382 &SourceU, 383 &String); 384 *Information = (ULONG_PTR)String.Buffer; 385 } 386 break; 387 } 388 case BusQueryCompatibleIDs: 389 { 390 /* We don't have any compatible ID */ 391 break; 392 } 393 case BusQueryInstanceID: 394 { 395 /* We don't have any instance ID */ 396 break; 397 } 398 default: 399 { 400 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType); 401 } 402 } 403 404 return Status; 405 } 406 407 NTSTATUS 408 GreenPnp( 409 IN PDEVICE_OBJECT DeviceObject, 410 IN PIRP Irp) 411 { 412 GREEN_DEVICE_TYPE Type; 413 PIO_STACK_LOCATION Stack; 414 ULONG_PTR Information = Irp->IoStatus.Information; 415 NTSTATUS Status = Irp->IoStatus.Status; 416 417 Type = ((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Type; 418 Stack = IoGetCurrentIrpStackLocation(Irp); 419 420 switch (Stack->MinorFunction) 421 { 422 case IRP_MN_START_DEVICE: /* 0x00 */ 423 { 424 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); 425 if (Type == GreenFDO || Type == KeyboardPDO || Type == ScreenPDO) 426 Status = STATUS_SUCCESS; 427 else 428 { 429 DPRINT1("IRP_MJ_PNP / IRP_MN_START_DEVICE / Unknown type 0x%lx\n", 430 Type); 431 ASSERT(FALSE); 432 } 433 break; 434 } 435 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */ 436 { 437 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n"); 438 switch (Stack->Parameters.QueryDeviceRelations.Type) 439 { 440 case BusRelations: 441 { 442 if (Type == GreenFDO) 443 { 444 PDEVICE_RELATIONS DeviceRelations = NULL; 445 Status = GreenQueryBusRelations(DeviceObject, &DeviceRelations); 446 Information = (ULONG_PTR)DeviceRelations; 447 } 448 else if (Type == KeyboardPDO || Type == ScreenPDO) 449 { 450 PDEVICE_RELATIONS DeviceRelations = NULL; 451 DeviceRelations = ExAllocatePool(PagedPool, FIELD_OFFSET(DEVICE_RELATIONS, Objects)); 452 if (!DeviceRelations) 453 Status = STATUS_INSUFFICIENT_RESOURCES; 454 else 455 { 456 DeviceRelations->Count = 0; 457 Status = STATUS_SUCCESS; 458 Information = (ULONG_PTR)DeviceRelations; 459 } 460 } 461 else 462 { 463 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations / Unknown type 0x%lx\n", 464 Type); 465 ASSERT(FALSE); 466 } 467 break; 468 } 469 default: 470 { 471 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n", 472 Stack->Parameters.QueryDeviceRelations.Type); 473 break; 474 } 475 } 476 break; 477 } 478 case IRP_MN_QUERY_RESOURCES: /* 0x0a */ 479 { 480 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n"); 481 /* We don't need resources */ 482 break; 483 } 484 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */ 485 { 486 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); 487 /* We don't need resources */ 488 break; 489 } 490 case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */ 491 { 492 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT\n"); 493 switch (Stack->Parameters.QueryDeviceText.DeviceTextType) 494 { 495 case DeviceTextDescription: 496 { 497 LPCWSTR Description = NULL; 498 if (Type == GreenFDO) 499 Description = L"Green device"; 500 else if (Type == ScreenPDO) 501 Description = L"Green screen"; 502 else if (Type == KeyboardPDO) 503 Description = L"Green keyboard"; 504 505 if (Description != NULL) 506 { 507 LPWSTR Destination = ExAllocatePool(PagedPool, wcslen(Description) * sizeof(WCHAR) + sizeof(UNICODE_NULL)); 508 if (!Destination) 509 Status = STATUS_INSUFFICIENT_RESOURCES; 510 else 511 { 512 wcscpy(Destination, Description); 513 Information = (ULONG_PTR)Description; 514 Status = STATUS_SUCCESS; 515 } 516 } 517 else 518 { 519 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription / Unknown type 0x%lx\n", 520 Type); 521 ASSERT(FALSE); 522 } 523 break; 524 } 525 case DeviceTextLocationInformation: 526 { 527 /* We don't have any text location to report, 528 * and this query is optional, so ignore it. 529 */ 530 break; 531 } 532 default: 533 { 534 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown type 0x%lx\n", 535 Stack->Parameters.QueryDeviceText.DeviceTextType); 536 ASSERT(FALSE); 537 break; 538 } 539 } 540 break; 541 } 542 case IRP_MN_QUERY_ID: /* 0x13 */ 543 { 544 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID\n"); 545 Status = GreenQueryId(DeviceObject, Irp, &Information); 546 break; 547 } 548 default: 549 { 550 DPRINT1("IRP_MJ_PNP / unknown minor function 0x%lx\n", Stack->MinorFunction); 551 break; 552 } 553 } 554 555 Irp->IoStatus.Status = Status; 556 Irp->IoStatus.Information = Information; 557 if (Status != STATUS_PENDING) 558 IoCompleteRequest(Irp, IO_NO_INCREMENT); 559 560 return Status; 561 } 562 563 564