1 /* 2 * PROJECT: ReactOS Universal Serial Bus Human Interface Device Driver 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: drivers/hid/hidclass/hidclass.c 5 * PURPOSE: HID Class Driver 6 * PROGRAMMERS: 7 * Michael Martin (michael.martin@reactos.org) 8 * Johannes Anderwald (johannes.anderwald@reactos.org) 9 */ 10 11 #include "precomp.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 static LPWSTR ClientIdentificationAddress = L"HIDCLASS"; 17 static ULONG HidClassDeviceNumber = 0; 18 19 NTSTATUS 20 NTAPI 21 DllInitialize( 22 IN PUNICODE_STRING RegistryPath) 23 { 24 return STATUS_SUCCESS; 25 } 26 27 NTSTATUS 28 NTAPI 29 DllUnload(VOID) 30 { 31 return STATUS_SUCCESS; 32 } 33 34 NTSTATUS 35 NTAPI 36 HidClassAddDevice( 37 IN PDRIVER_OBJECT DriverObject, 38 IN PDEVICE_OBJECT PhysicalDeviceObject) 39 { 40 WCHAR CharDeviceName[64]; 41 NTSTATUS Status; 42 UNICODE_STRING DeviceName; 43 PDEVICE_OBJECT NewDeviceObject; 44 PHIDCLASS_FDO_EXTENSION FDODeviceExtension; 45 ULONG DeviceExtensionSize; 46 PHIDCLASS_DRIVER_EXTENSION DriverExtension; 47 48 /* increment device number */ 49 InterlockedIncrement((PLONG)&HidClassDeviceNumber); 50 51 /* construct device name */ 52 swprintf(CharDeviceName, L"\\Device\\_HID%08x", HidClassDeviceNumber); 53 54 /* initialize device name */ 55 RtlInitUnicodeString(&DeviceName, CharDeviceName); 56 57 /* get driver object extension */ 58 DriverExtension = IoGetDriverObjectExtension(DriverObject, ClientIdentificationAddress); 59 if (!DriverExtension) 60 { 61 /* device removed */ 62 ASSERT(FALSE); 63 return STATUS_DEVICE_CONFIGURATION_ERROR; 64 } 65 66 /* calculate device extension size */ 67 DeviceExtensionSize = sizeof(HIDCLASS_FDO_EXTENSION) + DriverExtension->DeviceExtensionSize; 68 69 /* now create the device */ 70 Status = IoCreateDevice(DriverObject, DeviceExtensionSize, &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &NewDeviceObject); 71 if (!NT_SUCCESS(Status)) 72 { 73 /* failed to create device object */ 74 ASSERT(FALSE); 75 return Status; 76 } 77 78 /* get device extension */ 79 FDODeviceExtension = NewDeviceObject->DeviceExtension; 80 81 /* zero device extension */ 82 RtlZeroMemory(FDODeviceExtension, sizeof(HIDCLASS_FDO_EXTENSION)); 83 84 /* initialize device extension */ 85 FDODeviceExtension->Common.IsFDO = TRUE; 86 FDODeviceExtension->Common.DriverExtension = DriverExtension; 87 FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = PhysicalDeviceObject; 88 FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = (PVOID)((ULONG_PTR)FDODeviceExtension + sizeof(HIDCLASS_FDO_EXTENSION)); 89 FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = IoAttachDeviceToDeviceStack(NewDeviceObject, PhysicalDeviceObject); 90 if (FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject == NULL) 91 { 92 /* no PDO */ 93 IoDeleteDevice(NewDeviceObject); 94 DPRINT1("[HIDCLASS] failed to attach to device stack\n"); 95 return STATUS_DEVICE_REMOVED; 96 } 97 98 /* sanity check */ 99 ASSERT(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject); 100 101 /* increment stack size */ 102 NewDeviceObject->StackSize++; 103 104 /* init device object */ 105 NewDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; 106 NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 107 108 /* now call driver provided add device routine */ 109 ASSERT(DriverExtension->AddDevice != 0); 110 Status = DriverExtension->AddDevice(DriverObject, NewDeviceObject); 111 if (!NT_SUCCESS(Status)) 112 { 113 /* failed */ 114 DPRINT1("HIDCLASS: AddDevice failed with %x\n", Status); 115 IoDetachDevice(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject); 116 IoDeleteDevice(NewDeviceObject); 117 return Status; 118 } 119 120 /* succeeded */ 121 return Status; 122 } 123 124 VOID 125 NTAPI 126 HidClassDriverUnload( 127 IN PDRIVER_OBJECT DriverObject) 128 { 129 UNIMPLEMENTED; 130 } 131 132 NTSTATUS 133 NTAPI 134 HidClass_Create( 135 IN PDEVICE_OBJECT DeviceObject, 136 IN PIRP Irp) 137 { 138 PIO_STACK_LOCATION IoStack; 139 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; 140 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; 141 PHIDCLASS_FILEOP_CONTEXT Context; 142 143 // 144 // get device extension 145 // 146 CommonDeviceExtension = DeviceObject->DeviceExtension; 147 if (CommonDeviceExtension->IsFDO) 148 { 149 // 150 // only supported for PDO 151 // 152 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 153 IoCompleteRequest(Irp, IO_NO_INCREMENT); 154 return STATUS_UNSUCCESSFUL; 155 } 156 157 // 158 // must be a PDO 159 // 160 ASSERT(CommonDeviceExtension->IsFDO == FALSE); 161 162 // 163 // get device extension 164 // 165 PDODeviceExtension = DeviceObject->DeviceExtension; 166 167 // 168 // get stack location 169 // 170 IoStack = IoGetCurrentIrpStackLocation(Irp); 171 172 DPRINT("ShareAccess %x\n", IoStack->Parameters.Create.ShareAccess); 173 DPRINT("Options %x\n", IoStack->Parameters.Create.Options); 174 DPRINT("DesiredAccess %x\n", IoStack->Parameters.Create.SecurityContext->DesiredAccess); 175 176 // 177 // allocate context 178 // 179 Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_FILEOP_CONTEXT), HIDCLASS_TAG); 180 if (!Context) 181 { 182 // 183 // no memory 184 // 185 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 186 IoCompleteRequest(Irp, IO_NO_INCREMENT); 187 return STATUS_INSUFFICIENT_RESOURCES; 188 } 189 190 // 191 // init context 192 // 193 RtlZeroMemory(Context, sizeof(HIDCLASS_FILEOP_CONTEXT)); 194 Context->DeviceExtension = PDODeviceExtension; 195 KeInitializeSpinLock(&Context->Lock); 196 InitializeListHead(&Context->ReadPendingIrpListHead); 197 InitializeListHead(&Context->IrpCompletedListHead); 198 KeInitializeEvent(&Context->IrpReadComplete, NotificationEvent, FALSE); 199 200 // 201 // store context 202 // 203 ASSERT(IoStack->FileObject); 204 IoStack->FileObject->FsContext = Context; 205 206 // 207 // done 208 // 209 Irp->IoStatus.Status = STATUS_SUCCESS; 210 IoCompleteRequest(Irp, IO_NO_INCREMENT); 211 return STATUS_SUCCESS; 212 } 213 214 NTSTATUS 215 NTAPI 216 HidClass_Close( 217 IN PDEVICE_OBJECT DeviceObject, 218 IN PIRP Irp) 219 { 220 PIO_STACK_LOCATION IoStack; 221 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; 222 PHIDCLASS_FILEOP_CONTEXT IrpContext; 223 BOOLEAN IsRequestPending = FALSE; 224 KIRQL OldLevel; 225 PLIST_ENTRY Entry; 226 PIRP ListIrp; 227 228 // 229 // get device extension 230 // 231 CommonDeviceExtension = DeviceObject->DeviceExtension; 232 233 // 234 // is it a FDO request 235 // 236 if (CommonDeviceExtension->IsFDO) 237 { 238 // 239 // how did the request get there 240 // 241 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1; 242 IoCompleteRequest(Irp, IO_NO_INCREMENT); 243 return STATUS_INVALID_PARAMETER_1; 244 } 245 246 // 247 // get stack location 248 // 249 IoStack = IoGetCurrentIrpStackLocation(Irp); 250 251 // 252 // sanity checks 253 // 254 ASSERT(IoStack->FileObject); 255 ASSERT(IoStack->FileObject->FsContext); 256 257 // 258 // get irp context 259 // 260 IrpContext = IoStack->FileObject->FsContext; 261 ASSERT(IrpContext); 262 263 // 264 // acquire lock 265 // 266 KeAcquireSpinLock(&IrpContext->Lock, &OldLevel); 267 268 if (!IsListEmpty(&IrpContext->ReadPendingIrpListHead)) 269 { 270 // 271 // FIXME cancel irp 272 // 273 IsRequestPending = TRUE; 274 } 275 276 // 277 // signal stop 278 // 279 IrpContext->StopInProgress = TRUE; 280 281 // 282 // release lock 283 // 284 KeReleaseSpinLock(&IrpContext->Lock, OldLevel); 285 286 if (IsRequestPending) 287 { 288 // 289 // wait for request to complete 290 // 291 DPRINT1("[HIDCLASS] Waiting for read irp completion...\n"); 292 KeWaitForSingleObject(&IrpContext->IrpReadComplete, Executive, KernelMode, FALSE, NULL); 293 } 294 295 // 296 // acquire lock 297 // 298 KeAcquireSpinLock(&IrpContext->Lock, &OldLevel); 299 300 // 301 // sanity check 302 // 303 ASSERT(IsListEmpty(&IrpContext->ReadPendingIrpListHead)); 304 305 // 306 // now free all irps 307 // 308 while (!IsListEmpty(&IrpContext->IrpCompletedListHead)) 309 { 310 // 311 // remove head irp 312 // 313 Entry = RemoveHeadList(&IrpContext->IrpCompletedListHead); 314 315 // 316 // get irp 317 // 318 ListIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); 319 320 // 321 // free the irp 322 // 323 IoFreeIrp(ListIrp); 324 } 325 326 // 327 // release lock 328 // 329 KeReleaseSpinLock(&IrpContext->Lock, OldLevel); 330 331 // 332 // remove context 333 // 334 IoStack->FileObject->FsContext = NULL; 335 336 // 337 // free context 338 // 339 ExFreePoolWithTag(IrpContext, HIDCLASS_TAG); 340 341 // 342 // complete request 343 // 344 Irp->IoStatus.Status = STATUS_SUCCESS; 345 IoCompleteRequest(Irp, IO_NO_INCREMENT); 346 return STATUS_SUCCESS; 347 } 348 349 NTSTATUS 350 NTAPI 351 HidClass_ReadCompleteIrp( 352 IN PDEVICE_OBJECT DeviceObject, 353 IN PIRP Irp, 354 IN PVOID Ctx) 355 { 356 PHIDCLASS_IRP_CONTEXT IrpContext; 357 KIRQL OldLevel; 358 PUCHAR Address; 359 ULONG Offset; 360 PHIDP_COLLECTION_DESC CollectionDescription; 361 PHIDP_REPORT_IDS ReportDescription; 362 BOOLEAN IsEmpty; 363 364 // 365 // get irp context 366 // 367 IrpContext = Ctx; 368 369 DPRINT("HidClass_ReadCompleteIrp Irql %lu\n", KeGetCurrentIrql()); 370 DPRINT("HidClass_ReadCompleteIrp Status %lx\n", Irp->IoStatus.Status); 371 DPRINT("HidClass_ReadCompleteIrp Length %lu\n", Irp->IoStatus.Information); 372 DPRINT("HidClass_ReadCompleteIrp Irp %p\n", Irp); 373 DPRINT("HidClass_ReadCompleteIrp InputReportBuffer %p\n", IrpContext->InputReportBuffer); 374 DPRINT("HidClass_ReadCompleteIrp InputReportBufferLength %li\n", IrpContext->InputReportBufferLength); 375 DPRINT("HidClass_ReadCompleteIrp OriginalIrp %p\n", IrpContext->OriginalIrp); 376 377 // 378 // copy result 379 // 380 if (Irp->IoStatus.Information) 381 { 382 // 383 // get address 384 // 385 Address = MmGetSystemAddressForMdlSafe(IrpContext->OriginalIrp->MdlAddress, NormalPagePriority); 386 if (Address) 387 { 388 // 389 // reports may have a report id prepended 390 // 391 Offset = 0; 392 393 // 394 // get collection description 395 // 396 CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, 397 IrpContext->FileOp->DeviceExtension->CollectionNumber); 398 ASSERT(CollectionDescription); 399 400 // 401 // get report description 402 // 403 ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, 404 IrpContext->FileOp->DeviceExtension->CollectionNumber); 405 ASSERT(ReportDescription); 406 407 if (CollectionDescription && ReportDescription) 408 { 409 // 410 // calculate offset 411 // 412 ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength); 413 Offset = CollectionDescription->InputLength - ReportDescription->InputLength; 414 } 415 416 // 417 // copy result 418 // 419 RtlCopyMemory(&Address[Offset], IrpContext->InputReportBuffer, IrpContext->InputReportBufferLength); 420 } 421 } 422 423 // 424 // copy result status 425 // 426 IrpContext->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status; 427 IrpContext->OriginalIrp->IoStatus.Information = Irp->IoStatus.Information; 428 429 // 430 // free input report buffer 431 // 432 ExFreePoolWithTag(IrpContext->InputReportBuffer, HIDCLASS_TAG); 433 434 // 435 // remove us from pending list 436 // 437 KeAcquireSpinLock(&IrpContext->FileOp->Lock, &OldLevel); 438 439 // 440 // remove from pending list 441 // 442 RemoveEntryList(&Irp->Tail.Overlay.ListEntry); 443 444 // 445 // is list empty 446 // 447 IsEmpty = IsListEmpty(&IrpContext->FileOp->ReadPendingIrpListHead); 448 449 // 450 // insert into completed list 451 // 452 InsertTailList(&IrpContext->FileOp->IrpCompletedListHead, &Irp->Tail.Overlay.ListEntry); 453 454 // 455 // release lock 456 // 457 KeReleaseSpinLock(&IrpContext->FileOp->Lock, OldLevel); 458 459 // 460 // complete original request 461 // 462 IoCompleteRequest(IrpContext->OriginalIrp, IO_NO_INCREMENT); 463 464 465 DPRINT("StopInProgress %x IsEmpty %x\n", IrpContext->FileOp->StopInProgress, IsEmpty); 466 if (IrpContext->FileOp->StopInProgress && IsEmpty) 467 { 468 // 469 // last pending irp 470 // 471 DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n"); 472 KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE); 473 } 474 475 if (IrpContext->FileOp->StopInProgress && IsEmpty) 476 { 477 // 478 // last pending irp 479 // 480 DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n"); 481 KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE); 482 } 483 484 // 485 // free irp context 486 // 487 ExFreePoolWithTag(IrpContext, HIDCLASS_TAG); 488 489 // 490 // done 491 // 492 return STATUS_MORE_PROCESSING_REQUIRED; 493 } 494 495 PIRP 496 HidClass_GetIrp( 497 IN PHIDCLASS_FILEOP_CONTEXT Context) 498 { 499 KIRQL OldLevel; 500 PIRP Irp = NULL; 501 PLIST_ENTRY ListEntry; 502 503 // 504 // acquire lock 505 // 506 KeAcquireSpinLock(&Context->Lock, &OldLevel); 507 508 // 509 // is list empty? 510 // 511 if (!IsListEmpty(&Context->IrpCompletedListHead)) 512 { 513 // 514 // grab first entry 515 // 516 ListEntry = RemoveHeadList(&Context->IrpCompletedListHead); 517 518 // 519 // get irp 520 // 521 Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry); 522 } 523 524 // 525 // release lock 526 // 527 KeReleaseSpinLock(&Context->Lock, OldLevel); 528 529 // 530 // done 531 // 532 return Irp; 533 } 534 535 NTSTATUS 536 HidClass_BuildIrp( 537 IN PDEVICE_OBJECT DeviceObject, 538 IN PIRP RequestIrp, 539 IN PHIDCLASS_FILEOP_CONTEXT Context, 540 IN ULONG DeviceIoControlCode, 541 IN ULONG BufferLength, 542 OUT PIRP *OutIrp, 543 OUT PHIDCLASS_IRP_CONTEXT *OutIrpContext) 544 { 545 PIRP Irp; 546 PIO_STACK_LOCATION IoStack; 547 PHIDCLASS_IRP_CONTEXT IrpContext; 548 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; 549 PHIDP_COLLECTION_DESC CollectionDescription; 550 PHIDP_REPORT_IDS ReportDescription; 551 552 // 553 // get an irp from fresh list 554 // 555 Irp = HidClass_GetIrp(Context); 556 if (!Irp) 557 { 558 // 559 // build new irp 560 // 561 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 562 if (!Irp) 563 { 564 // 565 // no memory 566 // 567 return STATUS_INSUFFICIENT_RESOURCES; 568 } 569 } 570 else 571 { 572 // 573 // re-use irp 574 // 575 IoReuseIrp(Irp, STATUS_SUCCESS); 576 } 577 578 // 579 // allocate completion context 580 // 581 IrpContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_IRP_CONTEXT), HIDCLASS_TAG); 582 if (!IrpContext) 583 { 584 // 585 // no memory 586 // 587 IoFreeIrp(Irp); 588 return STATUS_INSUFFICIENT_RESOURCES; 589 } 590 591 // 592 // get device extension 593 // 594 PDODeviceExtension = DeviceObject->DeviceExtension; 595 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); 596 597 // 598 // init irp context 599 // 600 RtlZeroMemory(IrpContext, sizeof(HIDCLASS_IRP_CONTEXT)); 601 IrpContext->OriginalIrp = RequestIrp; 602 IrpContext->FileOp = Context; 603 604 // 605 // get collection description 606 // 607 CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, 608 IrpContext->FileOp->DeviceExtension->CollectionNumber); 609 ASSERT(CollectionDescription); 610 611 // 612 // get report description 613 // 614 ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, 615 IrpContext->FileOp->DeviceExtension->CollectionNumber); 616 ASSERT(ReportDescription); 617 618 // 619 // sanity check 620 // 621 ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength); 622 623 if (Context->StopInProgress) 624 { 625 // 626 // stop in progress 627 // 628 DPRINT1("[HIDCLASS] Stop In Progress\n"); 629 Irp->IoStatus.Status = STATUS_CANCELLED; 630 IoCompleteRequest(Irp, IO_NO_INCREMENT); 631 return STATUS_CANCELLED; 632 633 } 634 635 // 636 // store report length 637 // 638 IrpContext->InputReportBufferLength = ReportDescription->InputLength; 639 640 // 641 // allocate buffer 642 // 643 IrpContext->InputReportBuffer = ExAllocatePoolWithTag(NonPagedPool, IrpContext->InputReportBufferLength, HIDCLASS_TAG); 644 if (!IrpContext->InputReportBuffer) 645 { 646 // 647 // no memory 648 // 649 IoFreeIrp(Irp); 650 ExFreePoolWithTag(IrpContext, HIDCLASS_TAG); 651 return STATUS_INSUFFICIENT_RESOURCES; 652 } 653 654 // 655 // get stack location 656 // 657 IoStack = IoGetNextIrpStackLocation(Irp); 658 659 // 660 // init stack location 661 // 662 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 663 IoStack->Parameters.DeviceIoControl.IoControlCode = DeviceIoControlCode; 664 IoStack->Parameters.DeviceIoControl.OutputBufferLength = IrpContext->InputReportBufferLength; 665 IoStack->Parameters.DeviceIoControl.InputBufferLength = 0; 666 IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; 667 Irp->UserBuffer = IrpContext->InputReportBuffer; 668 IoStack->DeviceObject = DeviceObject; 669 670 // 671 // store result 672 // 673 *OutIrp = Irp; 674 *OutIrpContext = IrpContext; 675 676 // 677 // done 678 // 679 return STATUS_SUCCESS; 680 } 681 682 NTSTATUS 683 NTAPI 684 HidClass_Read( 685 IN PDEVICE_OBJECT DeviceObject, 686 IN PIRP Irp) 687 { 688 PIO_STACK_LOCATION IoStack; 689 PHIDCLASS_FILEOP_CONTEXT Context; 690 KIRQL OldLevel; 691 NTSTATUS Status; 692 PIRP NewIrp; 693 PHIDCLASS_IRP_CONTEXT NewIrpContext; 694 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; 695 696 // 697 // get current stack location 698 // 699 IoStack = IoGetCurrentIrpStackLocation(Irp); 700 701 // 702 // get device extension 703 // 704 CommonDeviceExtension = DeviceObject->DeviceExtension; 705 ASSERT(CommonDeviceExtension->IsFDO == FALSE); 706 707 // 708 // sanity check 709 // 710 ASSERT(IoStack->FileObject); 711 ASSERT(IoStack->FileObject->FsContext); 712 713 // 714 // get context 715 // 716 Context = IoStack->FileObject->FsContext; 717 ASSERT(Context); 718 719 // 720 // FIXME support polled devices 721 // 722 ASSERT(Context->DeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE); 723 724 if (Context->StopInProgress) 725 { 726 // 727 // stop in progress 728 // 729 DPRINT1("[HIDCLASS] Stop In Progress\n"); 730 Irp->IoStatus.Status = STATUS_CANCELLED; 731 IoCompleteRequest(Irp, IO_NO_INCREMENT); 732 return STATUS_CANCELLED; 733 } 734 735 // 736 // build irp request 737 // 738 Status = HidClass_BuildIrp(DeviceObject, 739 Irp, 740 Context, 741 IOCTL_HID_READ_REPORT, 742 IoStack->Parameters.Read.Length, 743 &NewIrp, 744 &NewIrpContext); 745 if (!NT_SUCCESS(Status)) 746 { 747 // 748 // failed 749 // 750 DPRINT1("HidClass_BuildIrp failed with %x\n", Status); 751 Irp->IoStatus.Status = Status; 752 IoCompleteRequest(Irp, IO_NO_INCREMENT); 753 return Status; 754 } 755 756 // 757 // acquire lock 758 // 759 KeAcquireSpinLock(&Context->Lock, &OldLevel); 760 761 // 762 // insert irp into pending list 763 // 764 InsertTailList(&Context->ReadPendingIrpListHead, &NewIrp->Tail.Overlay.ListEntry); 765 766 // 767 // set completion routine 768 // 769 IoSetCompletionRoutine(NewIrp, HidClass_ReadCompleteIrp, NewIrpContext, TRUE, TRUE, TRUE); 770 771 // 772 // make next location current 773 // 774 IoSetNextIrpStackLocation(NewIrp); 775 776 // 777 // release spin lock 778 // 779 KeReleaseSpinLock(&Context->Lock, OldLevel); 780 781 // 782 // mark irp pending 783 // 784 IoMarkIrpPending(Irp); 785 786 // 787 // let's dispatch the request 788 // 789 ASSERT(Context->DeviceExtension); 790 Status = Context->DeviceExtension->Common.DriverExtension->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL](Context->DeviceExtension->FDODeviceObject, NewIrp); 791 792 // 793 // complete 794 // 795 return STATUS_PENDING; 796 } 797 798 NTSTATUS 799 NTAPI 800 HidClass_Write( 801 IN PDEVICE_OBJECT DeviceObject, 802 IN PIRP Irp) 803 { 804 UNIMPLEMENTED; 805 ASSERT(FALSE); 806 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; 807 IoCompleteRequest(Irp, IO_NO_INCREMENT); 808 return STATUS_NOT_IMPLEMENTED; 809 } 810 811 NTSTATUS 812 NTAPI 813 HidClass_DeviceControl( 814 IN PDEVICE_OBJECT DeviceObject, 815 IN PIRP Irp) 816 { 817 PIO_STACK_LOCATION IoStack; 818 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; 819 PHID_COLLECTION_INFORMATION CollectionInformation; 820 PHIDP_COLLECTION_DESC CollectionDescription; 821 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; 822 823 // 824 // get device extension 825 // 826 CommonDeviceExtension = DeviceObject->DeviceExtension; 827 828 // 829 // only PDO are supported 830 // 831 if (CommonDeviceExtension->IsFDO) 832 { 833 // 834 // invalid request 835 // 836 DPRINT1("[HIDCLASS] DeviceControl Irp for FDO arrived\n"); 837 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1; 838 IoCompleteRequest(Irp, IO_NO_INCREMENT); 839 return STATUS_INVALID_PARAMETER_1; 840 } 841 842 ASSERT(CommonDeviceExtension->IsFDO == FALSE); 843 844 // 845 // get pdo device extension 846 // 847 PDODeviceExtension = DeviceObject->DeviceExtension; 848 849 // 850 // get stack location 851 // 852 IoStack = IoGetCurrentIrpStackLocation(Irp); 853 854 switch (IoStack->Parameters.DeviceIoControl.IoControlCode) 855 { 856 case IOCTL_HID_GET_COLLECTION_INFORMATION: 857 { 858 // 859 // check if output buffer is big enough 860 // 861 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION)) 862 { 863 // 864 // invalid buffer size 865 // 866 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE; 867 IoCompleteRequest(Irp, IO_NO_INCREMENT); 868 return STATUS_INVALID_BUFFER_SIZE; 869 } 870 871 // 872 // get output buffer 873 // 874 CollectionInformation = Irp->AssociatedIrp.SystemBuffer; 875 ASSERT(CollectionInformation); 876 877 // 878 // get collection description 879 // 880 CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription, 881 PDODeviceExtension->CollectionNumber); 882 ASSERT(CollectionDescription); 883 884 // 885 // init result buffer 886 // 887 CollectionInformation->DescriptorSize = CollectionDescription->PreparsedDataLength; 888 CollectionInformation->Polled = CommonDeviceExtension->DriverExtension->DevicesArePolled; 889 CollectionInformation->VendorID = CommonDeviceExtension->Attributes.VendorID; 890 CollectionInformation->ProductID = CommonDeviceExtension->Attributes.ProductID; 891 CollectionInformation->VersionNumber = CommonDeviceExtension->Attributes.VersionNumber; 892 893 // 894 // complete request 895 // 896 Irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION); 897 Irp->IoStatus.Status = STATUS_SUCCESS; 898 IoCompleteRequest(Irp, IO_NO_INCREMENT); 899 return STATUS_SUCCESS; 900 } 901 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR: 902 { 903 // 904 // get collection description 905 // 906 CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription, 907 PDODeviceExtension->CollectionNumber); 908 ASSERT(CollectionDescription); 909 910 // 911 // check if output buffer is big enough 912 // 913 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < CollectionDescription->PreparsedDataLength) 914 { 915 // 916 // invalid buffer size 917 // 918 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE; 919 IoCompleteRequest(Irp, IO_NO_INCREMENT); 920 return STATUS_INVALID_BUFFER_SIZE; 921 } 922 923 // 924 // copy result 925 // 926 ASSERT(Irp->UserBuffer); 927 RtlCopyMemory(Irp->UserBuffer, CollectionDescription->PreparsedData, CollectionDescription->PreparsedDataLength); 928 929 // 930 // complete request 931 // 932 Irp->IoStatus.Information = CollectionDescription->PreparsedDataLength; 933 Irp->IoStatus.Status = STATUS_SUCCESS; 934 IoCompleteRequest(Irp, IO_NO_INCREMENT); 935 return STATUS_SUCCESS; 936 } 937 default: 938 { 939 DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack->Parameters.DeviceIoControl.IoControlCode); 940 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; 941 IoCompleteRequest(Irp, IO_NO_INCREMENT); 942 return STATUS_NOT_IMPLEMENTED; 943 } 944 } 945 } 946 947 NTSTATUS 948 NTAPI 949 HidClass_InternalDeviceControl( 950 IN PDEVICE_OBJECT DeviceObject, 951 IN PIRP Irp) 952 { 953 UNIMPLEMENTED; 954 ASSERT(FALSE); 955 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; 956 IoCompleteRequest(Irp, IO_NO_INCREMENT); 957 return STATUS_NOT_IMPLEMENTED; 958 } 959 960 NTSTATUS 961 NTAPI 962 HidClass_Power( 963 IN PDEVICE_OBJECT DeviceObject, 964 IN PIRP Irp) 965 { 966 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; 967 CommonDeviceExtension = DeviceObject->DeviceExtension; 968 969 if (CommonDeviceExtension->IsFDO) 970 { 971 IoCopyCurrentIrpStackLocationToNext(Irp); 972 return HidClassFDO_DispatchRequest(DeviceObject, Irp); 973 } 974 else 975 { 976 Irp->IoStatus.Status = STATUS_SUCCESS; 977 PoStartNextPowerIrp(Irp); 978 IoCompleteRequest(Irp, IO_NO_INCREMENT); 979 return STATUS_SUCCESS; 980 } 981 } 982 983 NTSTATUS 984 NTAPI 985 HidClass_PnP( 986 IN PDEVICE_OBJECT DeviceObject, 987 IN PIRP Irp) 988 { 989 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; 990 991 // 992 // get common device extension 993 // 994 CommonDeviceExtension = DeviceObject->DeviceExtension; 995 996 // 997 // check type of device object 998 // 999 if (CommonDeviceExtension->IsFDO) 1000 { 1001 // 1002 // handle request 1003 // 1004 return HidClassFDO_PnP(DeviceObject, Irp); 1005 } 1006 else 1007 { 1008 // 1009 // handle request 1010 // 1011 return HidClassPDO_PnP(DeviceObject, Irp); 1012 } 1013 } 1014 1015 NTSTATUS 1016 NTAPI 1017 HidClass_DispatchDefault( 1018 IN PDEVICE_OBJECT DeviceObject, 1019 IN PIRP Irp) 1020 { 1021 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; 1022 1023 // 1024 // get common device extension 1025 // 1026 CommonDeviceExtension = DeviceObject->DeviceExtension; 1027 1028 // 1029 // FIXME: support PDO 1030 // 1031 ASSERT(CommonDeviceExtension->IsFDO == TRUE); 1032 1033 // 1034 // skip current irp stack location 1035 // 1036 IoSkipCurrentIrpStackLocation(Irp); 1037 1038 // 1039 // dispatch to lower device object 1040 // 1041 return IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, Irp); 1042 } 1043 1044 NTSTATUS 1045 NTAPI 1046 HidClassDispatch( 1047 IN PDEVICE_OBJECT DeviceObject, 1048 IN PIRP Irp) 1049 { 1050 PIO_STACK_LOCATION IoStack; 1051 1052 // 1053 // get current stack location 1054 // 1055 IoStack = IoGetCurrentIrpStackLocation(Irp); 1056 DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", IoStack->MajorFunction, IoStack->MinorFunction); 1057 1058 // 1059 // dispatch request based on major function 1060 // 1061 switch (IoStack->MajorFunction) 1062 { 1063 case IRP_MJ_CREATE: 1064 return HidClass_Create(DeviceObject, Irp); 1065 case IRP_MJ_CLOSE: 1066 return HidClass_Close(DeviceObject, Irp); 1067 case IRP_MJ_READ: 1068 return HidClass_Read(DeviceObject, Irp); 1069 case IRP_MJ_WRITE: 1070 return HidClass_Write(DeviceObject, Irp); 1071 case IRP_MJ_DEVICE_CONTROL: 1072 return HidClass_DeviceControl(DeviceObject, Irp); 1073 case IRP_MJ_INTERNAL_DEVICE_CONTROL: 1074 return HidClass_InternalDeviceControl(DeviceObject, Irp); 1075 case IRP_MJ_POWER: 1076 return HidClass_Power(DeviceObject, Irp); 1077 case IRP_MJ_PNP: 1078 return HidClass_PnP(DeviceObject, Irp); 1079 default: 1080 return HidClass_DispatchDefault(DeviceObject, Irp); 1081 } 1082 } 1083 1084 NTSTATUS 1085 NTAPI 1086 HidRegisterMinidriver( 1087 IN PHID_MINIDRIVER_REGISTRATION MinidriverRegistration) 1088 { 1089 NTSTATUS Status; 1090 PHIDCLASS_DRIVER_EXTENSION DriverExtension; 1091 1092 /* check if the version matches */ 1093 if (MinidriverRegistration->Revision > HID_REVISION) 1094 { 1095 /* revision mismatch */ 1096 ASSERT(FALSE); 1097 return STATUS_REVISION_MISMATCH; 1098 } 1099 1100 /* now allocate the driver object extension */ 1101 Status = IoAllocateDriverObjectExtension(MinidriverRegistration->DriverObject, 1102 ClientIdentificationAddress, 1103 sizeof(HIDCLASS_DRIVER_EXTENSION), 1104 (PVOID *)&DriverExtension); 1105 if (!NT_SUCCESS(Status)) 1106 { 1107 /* failed to allocate driver extension */ 1108 ASSERT(FALSE); 1109 return Status; 1110 } 1111 1112 /* zero driver extension */ 1113 RtlZeroMemory(DriverExtension, sizeof(HIDCLASS_DRIVER_EXTENSION)); 1114 1115 /* init driver extension */ 1116 DriverExtension->DriverObject = MinidriverRegistration->DriverObject; 1117 DriverExtension->DeviceExtensionSize = MinidriverRegistration->DeviceExtensionSize; 1118 DriverExtension->DevicesArePolled = MinidriverRegistration->DevicesArePolled; 1119 DriverExtension->AddDevice = MinidriverRegistration->DriverObject->DriverExtension->AddDevice; 1120 DriverExtension->DriverUnload = MinidriverRegistration->DriverObject->DriverUnload; 1121 1122 /* copy driver dispatch routines */ 1123 RtlCopyMemory(DriverExtension->MajorFunction, 1124 MinidriverRegistration->DriverObject->MajorFunction, 1125 sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1)); 1126 1127 /* initialize lock */ 1128 KeInitializeSpinLock(&DriverExtension->Lock); 1129 1130 /* now replace dispatch routines */ 1131 DriverExtension->DriverObject->DriverExtension->AddDevice = HidClassAddDevice; 1132 DriverExtension->DriverObject->DriverUnload = HidClassDriverUnload; 1133 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CREATE] = HidClassDispatch; 1134 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidClassDispatch; 1135 DriverExtension->DriverObject->MajorFunction[IRP_MJ_READ] = HidClassDispatch; 1136 DriverExtension->DriverObject->MajorFunction[IRP_MJ_WRITE] = HidClassDispatch; 1137 DriverExtension->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidClassDispatch; 1138 DriverExtension->DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HidClassDispatch; 1139 DriverExtension->DriverObject->MajorFunction[IRP_MJ_POWER] = HidClassDispatch; 1140 DriverExtension->DriverObject->MajorFunction[IRP_MJ_PNP] = HidClassDispatch; 1141 1142 /* done */ 1143 return STATUS_SUCCESS; 1144 } 1145