1 /* 2 * PROJECT: ReactOS HID Stack 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: drivers/hid/mouhid/mouhid.c 5 * PURPOSE: Mouse HID Driver 6 * PROGRAMMERS: 7 * Michael Martin (michael.martin@reactos.org) 8 * Johannes Anderwald (johannes.anderwald@reactos.org) 9 */ 10 11 #include "mouhid.h" 12 13 static USHORT MouHid_ButtonUpFlags[] = 14 { 15 0xFF, /* unused */ 16 MOUSE_LEFT_BUTTON_DOWN, 17 MOUSE_RIGHT_BUTTON_DOWN, 18 MOUSE_MIDDLE_BUTTON_DOWN, 19 MOUSE_BUTTON_4_DOWN, 20 MOUSE_BUTTON_5_DOWN 21 }; 22 23 static USHORT MouHid_ButtonDownFlags[] = 24 { 25 0xFF, /* unused */ 26 MOUSE_LEFT_BUTTON_UP, 27 MOUSE_RIGHT_BUTTON_UP, 28 MOUSE_MIDDLE_BUTTON_UP, 29 MOUSE_BUTTON_4_UP, 30 MOUSE_BUTTON_5_UP 31 }; 32 33 34 VOID 35 MouHid_GetButtonMove( 36 IN PMOUHID_DEVICE_EXTENSION DeviceExtension, 37 OUT PLONG LastX, 38 OUT PLONG LastY) 39 { 40 NTSTATUS Status; 41 ULONG ValueX, ValueY; 42 43 /* init result */ 44 *LastX = 0; 45 *LastY = 0; 46 47 if (!DeviceExtension->MouseAbsolute) 48 { 49 /* get scaled usage value x */ 50 Status = HidP_GetScaledUsageValue(HidP_Input, 51 HID_USAGE_PAGE_GENERIC, 52 HIDP_LINK_COLLECTION_UNSPECIFIED, 53 HID_USAGE_GENERIC_X, 54 LastX, 55 DeviceExtension->PreparsedData, 56 DeviceExtension->Report, 57 DeviceExtension->ReportLength); 58 59 if (Status != HIDP_STATUS_SUCCESS) 60 { 61 /* FIXME: handle more errors */ 62 if (Status == HIDP_STATUS_BAD_LOG_PHY_VALUES) 63 { 64 /* FIXME: assume it operates in absolute mode */ 65 DeviceExtension->MouseAbsolute = TRUE; 66 67 /* get unscaled value */ 68 Status = HidP_GetUsageValue(HidP_Input, 69 HID_USAGE_PAGE_GENERIC, 70 HIDP_LINK_COLLECTION_UNSPECIFIED, 71 HID_USAGE_GENERIC_X, 72 &ValueX, 73 DeviceExtension->PreparsedData, 74 DeviceExtension->Report, 75 DeviceExtension->ReportLength); 76 77 /* FIXME handle error */ 78 ASSERT(Status == HIDP_STATUS_SUCCESS); 79 80 /* absolute pointing devices values need be in range 0 - 0xffff */ 81 ASSERT(DeviceExtension->ValueCapsX.LogicalMax > 0); 82 ASSERT(DeviceExtension->ValueCapsX.LogicalMax > DeviceExtension->ValueCapsX.LogicalMin); 83 84 /* convert to logical range */ 85 *LastX = (ValueX * VIRTUAL_SCREEN_SIZE_X) / DeviceExtension->ValueCapsX.LogicalMax; 86 } 87 } 88 } 89 else 90 { 91 /* get unscaled value */ 92 Status = HidP_GetUsageValue(HidP_Input, 93 HID_USAGE_PAGE_GENERIC, 94 HIDP_LINK_COLLECTION_UNSPECIFIED, 95 HID_USAGE_GENERIC_X, 96 &ValueX, 97 DeviceExtension->PreparsedData, 98 DeviceExtension->Report, 99 DeviceExtension->ReportLength); 100 101 /* FIXME handle error */ 102 ASSERT(Status == HIDP_STATUS_SUCCESS); 103 104 /* absolute pointing devices values need be in range 0 - 0xffff */ 105 ASSERT(DeviceExtension->ValueCapsX.LogicalMax > 0); 106 ASSERT(DeviceExtension->ValueCapsX.LogicalMax > DeviceExtension->ValueCapsX.LogicalMin); 107 108 /* convert to logical range */ 109 *LastX = (ValueX * VIRTUAL_SCREEN_SIZE_X) / DeviceExtension->ValueCapsX.LogicalMax; 110 } 111 112 if (!DeviceExtension->MouseAbsolute) 113 { 114 /* get scaled usage value y */ 115 Status = HidP_GetScaledUsageValue(HidP_Input, 116 HID_USAGE_PAGE_GENERIC, 117 HIDP_LINK_COLLECTION_UNSPECIFIED, 118 HID_USAGE_GENERIC_Y, 119 LastY, 120 DeviceExtension->PreparsedData, 121 DeviceExtension->Report, 122 DeviceExtension->ReportLength); 123 124 if (Status != HIDP_STATUS_SUCCESS) 125 { 126 // FIXME: handle more errors 127 if (Status == HIDP_STATUS_BAD_LOG_PHY_VALUES) 128 { 129 // assume it operates in absolute mode 130 DeviceExtension->MouseAbsolute = TRUE; 131 132 // get unscaled value 133 Status = HidP_GetUsageValue(HidP_Input, 134 HID_USAGE_PAGE_GENERIC, 135 HIDP_LINK_COLLECTION_UNSPECIFIED, 136 HID_USAGE_GENERIC_Y, 137 &ValueY, 138 DeviceExtension->PreparsedData, 139 DeviceExtension->Report, 140 DeviceExtension->ReportLength); 141 142 /* FIXME handle error */ 143 ASSERT(Status == HIDP_STATUS_SUCCESS); 144 145 /* absolute pointing devices values need be in range 0 - 0xffff */ 146 ASSERT(DeviceExtension->ValueCapsY.LogicalMax > 0); 147 ASSERT(DeviceExtension->ValueCapsY.LogicalMax > DeviceExtension->ValueCapsY.LogicalMin); 148 149 /* convert to logical range */ 150 *LastY = (ValueY * VIRTUAL_SCREEN_SIZE_Y) / DeviceExtension->ValueCapsY.LogicalMax; 151 } 152 } 153 } 154 else 155 { 156 // get unscaled value 157 Status = HidP_GetUsageValue(HidP_Input, 158 HID_USAGE_PAGE_GENERIC, 159 HIDP_LINK_COLLECTION_UNSPECIFIED, 160 HID_USAGE_GENERIC_Y, 161 &ValueY, 162 DeviceExtension->PreparsedData, 163 DeviceExtension->Report, 164 DeviceExtension->ReportLength); 165 166 /* FIXME handle error */ 167 ASSERT(Status == HIDP_STATUS_SUCCESS); 168 169 /* absolute pointing devices values need be in range 0 - 0xffff */ 170 ASSERT(DeviceExtension->ValueCapsY.LogicalMax > 0); 171 ASSERT(DeviceExtension->ValueCapsY.LogicalMax > DeviceExtension->ValueCapsY.LogicalMin); 172 173 /* convert to logical range */ 174 *LastY = (ValueY * VIRTUAL_SCREEN_SIZE_Y) / DeviceExtension->ValueCapsY.LogicalMax; 175 } 176 } 177 178 VOID 179 MouHid_GetButtonFlags( 180 IN PMOUHID_DEVICE_EXTENSION DeviceExtension, 181 OUT PUSHORT ButtonFlags, 182 OUT PUSHORT Flags) 183 { 184 NTSTATUS Status; 185 USAGE Usage; 186 ULONG Index; 187 PUSAGE TempList; 188 ULONG CurrentUsageListLength; 189 190 /* init flags */ 191 *ButtonFlags = 0; 192 *Flags = 0; 193 194 /* get usages */ 195 CurrentUsageListLength = DeviceExtension->UsageListLength; 196 Status = HidP_GetUsages(HidP_Input, 197 HID_USAGE_PAGE_BUTTON, 198 HIDP_LINK_COLLECTION_UNSPECIFIED, 199 DeviceExtension->CurrentUsageList, 200 &CurrentUsageListLength, 201 DeviceExtension->PreparsedData, 202 DeviceExtension->Report, 203 DeviceExtension->ReportLength); 204 if (Status != HIDP_STATUS_SUCCESS) 205 { 206 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status); 207 return; 208 } 209 210 /* extract usage list difference */ 211 Status = HidP_UsageListDifference(DeviceExtension->PreviousUsageList, 212 DeviceExtension->CurrentUsageList, 213 DeviceExtension->BreakUsageList, 214 DeviceExtension->MakeUsageList, 215 DeviceExtension->UsageListLength); 216 if (Status != HIDP_STATUS_SUCCESS) 217 { 218 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status); 219 return; 220 } 221 222 if (DeviceExtension->UsageListLength) 223 { 224 Index = 0; 225 do 226 { 227 /* get usage */ 228 Usage = DeviceExtension->BreakUsageList[Index]; 229 if (!Usage) 230 break; 231 232 if (Usage <= 5) 233 { 234 /* max 5 buttons supported */ 235 *ButtonFlags |= MouHid_ButtonDownFlags[Usage]; 236 } 237 238 /* move to next index*/ 239 Index++; 240 }while(Index < DeviceExtension->UsageListLength); 241 } 242 243 if (DeviceExtension->UsageListLength) 244 { 245 Index = 0; 246 do 247 { 248 /* get usage */ 249 Usage = DeviceExtension->MakeUsageList[Index]; 250 if (!Usage) 251 break; 252 253 if (Usage <= 5) 254 { 255 /* max 5 buttons supported */ 256 *ButtonFlags |= MouHid_ButtonUpFlags[Usage]; 257 } 258 259 /* move to next index*/ 260 Index++; 261 }while(Index < DeviceExtension->UsageListLength); 262 } 263 264 /* now switch the previous list with current list */ 265 TempList = DeviceExtension->CurrentUsageList; 266 DeviceExtension->CurrentUsageList = DeviceExtension->PreviousUsageList; 267 DeviceExtension->PreviousUsageList = TempList; 268 269 if (DeviceExtension->MouseAbsolute) 270 { 271 // mouse operates absolute 272 *Flags |= MOUSE_MOVE_ABSOLUTE; 273 } 274 } 275 276 VOID 277 MouHid_DispatchInputData( 278 IN PMOUHID_DEVICE_EXTENSION DeviceExtension, 279 IN PMOUSE_INPUT_DATA InputData) 280 { 281 KIRQL OldIrql; 282 ULONG InputDataConsumed; 283 284 if (!DeviceExtension->ClassService) 285 return; 286 287 /* sanity check */ 288 ASSERT(DeviceExtension->ClassService); 289 ASSERT(DeviceExtension->ClassDeviceObject); 290 291 /* raise irql */ 292 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 293 294 /* dispatch input data */ 295 (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)(DeviceExtension->ClassDeviceObject, InputData, InputData + 1, &InputDataConsumed); 296 297 /* lower irql to previous level */ 298 KeLowerIrql(OldIrql); 299 } 300 301 NTSTATUS 302 NTAPI 303 MouHid_ReadCompletion( 304 IN PDEVICE_OBJECT DeviceObject, 305 IN PIRP Irp, 306 IN PVOID Context) 307 { 308 PMOUHID_DEVICE_EXTENSION DeviceExtension; 309 USHORT ButtonFlags; 310 LONG UsageValue; 311 NTSTATUS Status; 312 LONG LastX, LastY; 313 MOUSE_INPUT_DATA MouseInputData; 314 USHORT Flags; 315 316 /* get device extension */ 317 DeviceExtension = Context; 318 319 if (Irp->IoStatus.Status == STATUS_PRIVILEGE_NOT_HELD || 320 Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED || 321 Irp->IoStatus.Status == STATUS_CANCELLED || 322 DeviceExtension->StopReadReport) 323 { 324 /* failed to read or should be stopped*/ 325 DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp->IoStatus.Status); 326 327 /* report no longer active */ 328 DeviceExtension->ReadReportActive = FALSE; 329 330 /* request stopping of the report cycle */ 331 DeviceExtension->StopReadReport = FALSE; 332 333 /* signal completion event */ 334 KeSetEvent(&DeviceExtension->ReadCompletionEvent, 0, 0); 335 return STATUS_MORE_PROCESSING_REQUIRED; 336 } 337 338 /* get mouse change */ 339 MouHid_GetButtonMove(DeviceExtension, &LastX, &LastY); 340 341 /* get mouse change flags */ 342 MouHid_GetButtonFlags(DeviceExtension, &ButtonFlags, &Flags); 343 344 /* init input data */ 345 RtlZeroMemory(&MouseInputData, sizeof(MOUSE_INPUT_DATA)); 346 347 /* init input data */ 348 MouseInputData.ButtonFlags = ButtonFlags; 349 MouseInputData.Flags = Flags; 350 MouseInputData.LastX = LastX; 351 MouseInputData.LastY = LastY; 352 353 /* detect mouse wheel change */ 354 if (DeviceExtension->MouseIdentifier == WHEELMOUSE_HID_HARDWARE) 355 { 356 /* get usage */ 357 UsageValue = 0; 358 Status = HidP_GetScaledUsageValue(HidP_Input, 359 HID_USAGE_PAGE_GENERIC, 360 HIDP_LINK_COLLECTION_UNSPECIFIED, 361 HID_USAGE_GENERIC_WHEEL, 362 &UsageValue, 363 DeviceExtension->PreparsedData, 364 DeviceExtension->Report, 365 DeviceExtension->ReportLength); 366 if (Status == HIDP_STATUS_SUCCESS && UsageValue != 0) 367 { 368 /* store wheel status */ 369 MouseInputData.ButtonFlags |= MOUSE_WHEEL; 370 MouseInputData.ButtonData = (USHORT)(UsageValue * WHEEL_DELTA); 371 } 372 else 373 { 374 DPRINT("[MOUHID] failed to get wheel status with %x\n", Status); 375 } 376 } 377 378 DPRINT("[MOUHID] ReportData %02x %02x %02x %02x %02x %02x %02x\n", 379 DeviceExtension->Report[0] & 0xFF, 380 DeviceExtension->Report[1] & 0xFF, DeviceExtension->Report[2] & 0xFF, 381 DeviceExtension->Report[3] & 0xFF, DeviceExtension->Report[4] & 0xFF, 382 DeviceExtension->Report[5] & 0xFF, DeviceExtension->Report[6] & 0xFF); 383 384 DPRINT("[MOUHID] LastX %ld LastY %ld Flags %x ButtonFlags %x ButtonData %x\n", MouseInputData.LastX, MouseInputData.LastY, MouseInputData.Flags, MouseInputData.ButtonFlags, MouseInputData.ButtonData); 385 386 /* dispatch mouse action */ 387 MouHid_DispatchInputData(DeviceExtension, &MouseInputData); 388 389 /* re-init read */ 390 MouHid_InitiateRead(DeviceExtension); 391 392 /* stop completion */ 393 return STATUS_MORE_PROCESSING_REQUIRED; 394 } 395 396 NTSTATUS 397 MouHid_InitiateRead( 398 IN PMOUHID_DEVICE_EXTENSION DeviceExtension) 399 { 400 PIO_STACK_LOCATION IoStack; 401 NTSTATUS Status; 402 403 /* re-use irp */ 404 IoReuseIrp(DeviceExtension->Irp, STATUS_SUCCESS); 405 406 /* init irp */ 407 DeviceExtension->Irp->MdlAddress = DeviceExtension->ReportMDL; 408 409 /* get next stack location */ 410 IoStack = IoGetNextIrpStackLocation(DeviceExtension->Irp); 411 412 /* init stack location */ 413 IoStack->Parameters.Read.Length = DeviceExtension->ReportLength; 414 IoStack->Parameters.Read.Key = 0; 415 IoStack->Parameters.Read.ByteOffset.QuadPart = 0LL; 416 IoStack->MajorFunction = IRP_MJ_READ; 417 IoStack->FileObject = DeviceExtension->FileObject; 418 419 /* set completion routine */ 420 IoSetCompletionRoutine(DeviceExtension->Irp, MouHid_ReadCompletion, DeviceExtension, TRUE, TRUE, TRUE); 421 422 /* read is active */ 423 DeviceExtension->ReadReportActive = TRUE; 424 425 /* start the read */ 426 Status = IoCallDriver(DeviceExtension->NextDeviceObject, DeviceExtension->Irp); 427 428 /* done */ 429 return Status; 430 } 431 432 NTSTATUS 433 NTAPI 434 MouHid_CreateCompletion( 435 IN PDEVICE_OBJECT DeviceObject, 436 IN PIRP Irp, 437 IN PVOID Context) 438 { 439 KeSetEvent(Context, 0, FALSE); 440 return STATUS_MORE_PROCESSING_REQUIRED; 441 } 442 443 444 NTSTATUS 445 NTAPI 446 MouHid_Create( 447 IN PDEVICE_OBJECT DeviceObject, 448 IN PIRP Irp) 449 { 450 PIO_STACK_LOCATION IoStack; 451 NTSTATUS Status; 452 KEVENT Event; 453 PMOUHID_DEVICE_EXTENSION DeviceExtension; 454 455 DPRINT("MOUHID: IRP_MJ_CREATE\n"); 456 457 /* get device extension */ 458 DeviceExtension = DeviceObject->DeviceExtension; 459 460 /* get stack location */ 461 IoStack = IoGetCurrentIrpStackLocation(Irp); 462 463 /* copy stack location to next */ 464 IoCopyCurrentIrpStackLocationToNext(Irp); 465 466 /* init event */ 467 KeInitializeEvent(&Event, NotificationEvent, FALSE); 468 469 /* prepare irp */ 470 IoSetCompletionRoutine(Irp, MouHid_CreateCompletion, &Event, TRUE, TRUE, TRUE); 471 472 /* call lower driver */ 473 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 474 if (Status == STATUS_PENDING) 475 { 476 /* request pending */ 477 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 478 } 479 480 /* check for success */ 481 if (!NT_SUCCESS(Status)) 482 { 483 /* failed */ 484 Irp->IoStatus.Status = Status; 485 IoCompleteRequest(Irp, IO_NO_INCREMENT); 486 return Status; 487 } 488 489 /* is the driver already in use */ 490 if (DeviceExtension->FileObject == NULL) 491 { 492 /* did the caller specify correct attributes */ 493 ASSERT(IoStack->Parameters.Create.SecurityContext); 494 if (IoStack->Parameters.Create.SecurityContext->DesiredAccess) 495 { 496 /* store file object */ 497 DeviceExtension->FileObject = IoStack->FileObject; 498 499 /* reset event */ 500 KeClearEvent(&DeviceExtension->ReadCompletionEvent); 501 502 /* initiating read */ 503 Status = MouHid_InitiateRead(DeviceExtension); 504 DPRINT("[MOUHID] MouHid_InitiateRead: status %x\n", Status); 505 if (Status == STATUS_PENDING) 506 { 507 /* report irp is pending */ 508 Status = STATUS_SUCCESS; 509 } 510 } 511 } 512 513 /* complete request */ 514 Irp->IoStatus.Status = Status; 515 IoCompleteRequest(Irp, IO_NO_INCREMENT); 516 return Status; 517 } 518 519 520 NTSTATUS 521 NTAPI 522 MouHid_Close( 523 IN PDEVICE_OBJECT DeviceObject, 524 IN PIRP Irp) 525 { 526 PMOUHID_DEVICE_EXTENSION DeviceExtension; 527 528 /* get device extension */ 529 DeviceExtension = DeviceObject->DeviceExtension; 530 531 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive); 532 533 if (DeviceExtension->ReadReportActive) 534 { 535 /* request stopping of the report cycle */ 536 DeviceExtension->StopReadReport = TRUE; 537 538 /* wait until the reports have been read */ 539 KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL); 540 541 /* cancel irp */ 542 IoCancelIrp(DeviceExtension->Irp); 543 } 544 545 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive); 546 547 /* remove file object */ 548 DeviceExtension->FileObject = NULL; 549 550 /* skip location */ 551 IoSkipCurrentIrpStackLocation(Irp); 552 553 /* pass irp to down the stack */ 554 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 555 } 556 557 NTSTATUS 558 NTAPI 559 MouHid_InternalDeviceControl( 560 IN PDEVICE_OBJECT DeviceObject, 561 IN PIRP Irp) 562 { 563 PIO_STACK_LOCATION IoStack; 564 PMOUSE_ATTRIBUTES Attributes; 565 PMOUHID_DEVICE_EXTENSION DeviceExtension; 566 PCONNECT_DATA Data; 567 568 /* get current stack location */ 569 IoStack = IoGetCurrentIrpStackLocation(Irp); 570 571 DPRINT("[MOUHID] InternalDeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode); 572 573 /* get device extension */ 574 DeviceExtension = DeviceObject->DeviceExtension; 575 576 /* handle requests */ 577 switch (IoStack->Parameters.DeviceIoControl.IoControlCode) 578 { 579 case IOCTL_MOUSE_QUERY_ATTRIBUTES: 580 /* verify output buffer length */ 581 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES)) 582 { 583 /* invalid request */ 584 DPRINT1("[MOUHID] IOCTL_MOUSE_QUERY_ATTRIBUTES Buffer too small\n"); 585 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 586 IoCompleteRequest(Irp, IO_NO_INCREMENT); 587 return STATUS_BUFFER_TOO_SMALL; 588 } 589 590 /* get output buffer */ 591 Attributes = Irp->AssociatedIrp.SystemBuffer; 592 593 /* type of mouse */ 594 Attributes->MouseIdentifier = DeviceExtension->MouseIdentifier; 595 596 /* number of buttons */ 597 Attributes->NumberOfButtons = DeviceExtension->UsageListLength; 598 599 /* sample rate not used for usb */ 600 Attributes->SampleRate = 0; 601 602 /* queue length */ 603 Attributes->InputDataQueueLength = 2; 604 605 DPRINT("[MOUHID] MouseIdentifier %x\n", Attributes->MouseIdentifier); 606 DPRINT("[MOUHID] NumberOfButtons %x\n", Attributes->NumberOfButtons); 607 DPRINT("[MOUHID] SampleRate %x\n", Attributes->SampleRate); 608 DPRINT("[MOUHID] InputDataQueueLength %x\n", Attributes->InputDataQueueLength); 609 610 /* complete request */ 611 Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES); 612 Irp->IoStatus.Status = STATUS_SUCCESS; 613 IoCompleteRequest(Irp, IO_NO_INCREMENT); 614 return STATUS_SUCCESS; 615 616 case IOCTL_INTERNAL_MOUSE_CONNECT: 617 /* verify input buffer length */ 618 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA)) 619 { 620 /* invalid request */ 621 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 622 IoCompleteRequest(Irp, IO_NO_INCREMENT); 623 return STATUS_INVALID_PARAMETER; 624 } 625 626 /* is it already connected */ 627 if (DeviceExtension->ClassService) 628 { 629 /* already connected */ 630 Irp->IoStatus.Status = STATUS_SHARING_VIOLATION; 631 IoCompleteRequest(Irp, IO_NO_INCREMENT); 632 return STATUS_SHARING_VIOLATION; 633 } 634 635 /* get connect data */ 636 Data = IoStack->Parameters.DeviceIoControl.Type3InputBuffer; 637 638 /* store connect details */ 639 DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject; 640 DeviceExtension->ClassService = Data->ClassService; 641 642 /* completed successfully */ 643 Irp->IoStatus.Status = STATUS_SUCCESS; 644 IoCompleteRequest(Irp, IO_NO_INCREMENT); 645 return STATUS_SUCCESS; 646 647 case IOCTL_INTERNAL_MOUSE_DISCONNECT: 648 /* not supported */ 649 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; 650 IoCompleteRequest(Irp, IO_NO_INCREMENT); 651 return STATUS_NOT_IMPLEMENTED; 652 653 case IOCTL_INTERNAL_MOUSE_ENABLE: 654 /* not supported */ 655 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 656 IoCompleteRequest(Irp, IO_NO_INCREMENT); 657 return STATUS_NOT_SUPPORTED; 658 659 case IOCTL_INTERNAL_MOUSE_DISABLE: 660 /* not supported */ 661 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 662 IoCompleteRequest(Irp, IO_NO_INCREMENT); 663 return STATUS_INVALID_DEVICE_REQUEST; 664 } 665 666 DPRINT1("[MOUHID] Unknown DeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode); 667 /* unknown request not supported */ 668 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 669 IoCompleteRequest(Irp, IO_NO_INCREMENT); 670 return STATUS_NOT_SUPPORTED; 671 } 672 673 NTSTATUS 674 NTAPI 675 MouHid_DeviceControl( 676 IN PDEVICE_OBJECT DeviceObject, 677 IN PIRP Irp) 678 { 679 PMOUHID_DEVICE_EXTENSION DeviceExtension; 680 681 /* get device extension */ 682 DeviceExtension = DeviceObject->DeviceExtension; 683 684 /* skip stack location */ 685 IoSkipCurrentIrpStackLocation(Irp); 686 687 /* pass and forget */ 688 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 689 } 690 691 NTSTATUS 692 NTAPI 693 MouHid_Power( 694 IN PDEVICE_OBJECT DeviceObject, 695 IN PIRP Irp) 696 { 697 PMOUHID_DEVICE_EXTENSION DeviceExtension; 698 699 DeviceExtension = DeviceObject->DeviceExtension; 700 PoStartNextPowerIrp(Irp); 701 IoSkipCurrentIrpStackLocation(Irp); 702 return PoCallDriver(DeviceExtension->NextDeviceObject, Irp); 703 } 704 705 NTSTATUS 706 NTAPI 707 MouHid_SystemControl( 708 IN PDEVICE_OBJECT DeviceObject, 709 IN PIRP Irp) 710 { 711 PMOUHID_DEVICE_EXTENSION DeviceExtension; 712 713 DeviceExtension = DeviceObject->DeviceExtension; 714 IoSkipCurrentIrpStackLocation(Irp); 715 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 716 } 717 718 NTSTATUS 719 MouHid_SubmitRequest( 720 PDEVICE_OBJECT DeviceObject, 721 ULONG IoControlCode, 722 ULONG InputBufferSize, 723 PVOID InputBuffer, 724 ULONG OutputBufferSize, 725 PVOID OutputBuffer) 726 { 727 KEVENT Event; 728 PMOUHID_DEVICE_EXTENSION DeviceExtension; 729 PIRP Irp; 730 NTSTATUS Status; 731 IO_STATUS_BLOCK IoStatus; 732 733 /* get device extension */ 734 DeviceExtension = DeviceObject->DeviceExtension; 735 736 /* init event */ 737 KeInitializeEvent(&Event, NotificationEvent, FALSE); 738 739 /* build request */ 740 Irp = IoBuildDeviceIoControlRequest(IoControlCode, 741 DeviceExtension->NextDeviceObject, 742 InputBuffer, 743 InputBufferSize, 744 OutputBuffer, 745 OutputBufferSize, 746 FALSE, 747 &Event, 748 &IoStatus); 749 if (!Irp) 750 { 751 /* no memory */ 752 return STATUS_INSUFFICIENT_RESOURCES; 753 } 754 755 /* send request */ 756 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 757 if (Status == STATUS_PENDING) 758 { 759 /* wait for request to complete */ 760 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 761 Status = IoStatus.Status; 762 } 763 764 /* done */ 765 return Status; 766 } 767 768 NTSTATUS 769 NTAPI 770 MouHid_StartDevice( 771 IN PDEVICE_OBJECT DeviceObject) 772 { 773 NTSTATUS Status; 774 ULONG Buttons; 775 HID_COLLECTION_INFORMATION Information; 776 PVOID PreparsedData; 777 HIDP_CAPS Capabilities; 778 USHORT ValueCapsLength; 779 HIDP_VALUE_CAPS ValueCaps; 780 PMOUHID_DEVICE_EXTENSION DeviceExtension; 781 PUSAGE Buffer; 782 783 /* get device extension */ 784 DeviceExtension = DeviceObject->DeviceExtension; 785 786 /* query collection information */ 787 Status = MouHid_SubmitRequest(DeviceObject, 788 IOCTL_HID_GET_COLLECTION_INFORMATION, 789 0, 790 NULL, 791 sizeof(HID_COLLECTION_INFORMATION), 792 &Information); 793 if (!NT_SUCCESS(Status)) 794 { 795 /* failed to query collection information */ 796 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status); 797 return Status; 798 } 799 800 /* lets allocate space for preparsed data */ 801 PreparsedData = ExAllocatePoolWithTag(NonPagedPool, Information.DescriptorSize, MOUHID_TAG); 802 if (!PreparsedData) 803 { 804 /* no memory */ 805 DPRINT1("[MOUHID] no memory size %u\n", Information.DescriptorSize); 806 return STATUS_INSUFFICIENT_RESOURCES; 807 } 808 809 /* now obtain the preparsed data */ 810 Status = MouHid_SubmitRequest(DeviceObject, 811 IOCTL_HID_GET_COLLECTION_DESCRIPTOR, 812 0, 813 NULL, 814 Information.DescriptorSize, 815 PreparsedData); 816 if (!NT_SUCCESS(Status)) 817 { 818 /* failed to get preparsed data */ 819 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status); 820 ExFreePoolWithTag(PreparsedData, MOUHID_TAG); 821 return Status; 822 } 823 824 /* lets get the caps */ 825 Status = HidP_GetCaps(PreparsedData, &Capabilities); 826 if (Status != HIDP_STATUS_SUCCESS) 827 { 828 /* failed to get capabilities */ 829 DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status); 830 ExFreePoolWithTag(PreparsedData, MOUHID_TAG); 831 return Status; 832 } 833 834 DPRINT("[MOUHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength); 835 836 /* verify capabilities */ 837 if ((Capabilities.Usage != HID_USAGE_GENERIC_POINTER && Capabilities.Usage != HID_USAGE_GENERIC_MOUSE) || Capabilities.UsagePage != HID_USAGE_PAGE_GENERIC) 838 { 839 /* not supported */ 840 ExFreePoolWithTag(PreparsedData, MOUHID_TAG); 841 return STATUS_UNSUCCESSFUL; 842 } 843 844 /* init input report */ 845 DeviceExtension->ReportLength = Capabilities.InputReportByteLength; 846 ASSERT(DeviceExtension->ReportLength); 847 DeviceExtension->Report = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->ReportLength, MOUHID_TAG); 848 ASSERT(DeviceExtension->Report); 849 RtlZeroMemory(DeviceExtension->Report, DeviceExtension->ReportLength); 850 851 /* build mdl */ 852 DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report, 853 DeviceExtension->ReportLength, 854 FALSE, 855 FALSE, 856 NULL); 857 ASSERT(DeviceExtension->ReportMDL); 858 859 /* init mdl */ 860 MmBuildMdlForNonPagedPool(DeviceExtension->ReportMDL); 861 862 /* get max number of buttons */ 863 Buttons = HidP_MaxUsageListLength(HidP_Input, 864 HID_USAGE_PAGE_BUTTON, 865 PreparsedData); 866 DPRINT("[MOUHID] Buttons %lu\n", Buttons); 867 ASSERT(Buttons > 0); 868 869 /* now allocate an array for those buttons */ 870 Buffer = ExAllocatePoolWithTag(NonPagedPool, sizeof(USAGE) * 4 * Buttons, MOUHID_TAG); 871 if (!Buffer) 872 { 873 /* no memory */ 874 ExFreePoolWithTag(PreparsedData, MOUHID_TAG); 875 return STATUS_INSUFFICIENT_RESOURCES; 876 } 877 DeviceExtension->UsageListBuffer = Buffer; 878 879 /* init usage lists */ 880 RtlZeroMemory(Buffer, sizeof(USAGE) * 4 * Buttons); 881 DeviceExtension->CurrentUsageList = Buffer; 882 Buffer += Buttons; 883 DeviceExtension->PreviousUsageList = Buffer; 884 Buffer += Buttons; 885 DeviceExtension->MakeUsageList = Buffer; 886 Buffer += Buttons; 887 DeviceExtension->BreakUsageList = Buffer; 888 889 /* store number of buttons */ 890 DeviceExtension->UsageListLength = (USHORT)Buttons; 891 892 /* store preparsed data */ 893 DeviceExtension->PreparsedData = PreparsedData; 894 895 ValueCapsLength = 1; 896 HidP_GetSpecificValueCaps(HidP_Input, 897 HID_USAGE_PAGE_GENERIC, 898 HIDP_LINK_COLLECTION_UNSPECIFIED, 899 HID_USAGE_GENERIC_X, 900 &DeviceExtension->ValueCapsX, 901 &ValueCapsLength, 902 PreparsedData); 903 904 ValueCapsLength = 1; 905 HidP_GetSpecificValueCaps(HidP_Input, 906 HID_USAGE_PAGE_GENERIC, 907 HIDP_LINK_COLLECTION_UNSPECIFIED, 908 HID_USAGE_GENERIC_Y, 909 &DeviceExtension->ValueCapsY, 910 &ValueCapsLength, 911 PreparsedData); 912 913 /* now check for wheel mouse support */ 914 ValueCapsLength = 1; 915 Status = HidP_GetSpecificValueCaps(HidP_Input, 916 HID_USAGE_PAGE_GENERIC, 917 HIDP_LINK_COLLECTION_UNSPECIFIED, 918 HID_USAGE_GENERIC_WHEEL, 919 &ValueCaps, 920 &ValueCapsLength, 921 PreparsedData); 922 if (Status == HIDP_STATUS_SUCCESS ) 923 { 924 /* mouse has wheel support */ 925 DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE; 926 DeviceExtension->WheelUsagePage = ValueCaps.UsagePage; 927 DPRINT("[MOUHID] mouse wheel support detected\n", Status); 928 } 929 else 930 { 931 /* check if the mouse has z-axis */ 932 ValueCapsLength = 1; 933 Status = HidP_GetSpecificValueCaps(HidP_Input, 934 HID_USAGE_PAGE_GENERIC, 935 HIDP_LINK_COLLECTION_UNSPECIFIED, 936 HID_USAGE_GENERIC_Z, 937 &ValueCaps, 938 &ValueCapsLength, 939 PreparsedData); 940 if (Status == HIDP_STATUS_SUCCESS && ValueCapsLength == 1) 941 { 942 /* wheel support */ 943 DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE; 944 DeviceExtension->WheelUsagePage = ValueCaps.UsagePage; 945 DPRINT("[MOUHID] mouse wheel support detected with z-axis\n", Status); 946 } 947 } 948 949 /* check if mice is absolute */ 950 if (DeviceExtension->ValueCapsY.IsAbsolute && 951 DeviceExtension->ValueCapsX.IsAbsolute) 952 { 953 /* mice is absolute */ 954 DeviceExtension->MouseAbsolute = TRUE; 955 } 956 957 /* completed successfully */ 958 return STATUS_SUCCESS; 959 } 960 961 NTSTATUS 962 NTAPI 963 MouHid_StartDeviceCompletion( 964 IN PDEVICE_OBJECT DeviceObject, 965 IN PIRP Irp, 966 IN PVOID Context) 967 { 968 KeSetEvent(Context, 0, FALSE); 969 return STATUS_MORE_PROCESSING_REQUIRED; 970 } 971 972 NTSTATUS 973 NTAPI 974 MouHid_FreeResources( 975 IN PDEVICE_OBJECT DeviceObject) 976 { 977 PMOUHID_DEVICE_EXTENSION DeviceExtension; 978 979 /* get device extension */ 980 DeviceExtension = DeviceObject->DeviceExtension; 981 982 /* free resources */ 983 if (DeviceExtension->PreparsedData) 984 { 985 ExFreePoolWithTag(DeviceExtension->PreparsedData, MOUHID_TAG); 986 DeviceExtension->PreparsedData = NULL; 987 } 988 989 if (DeviceExtension->UsageListBuffer) 990 { 991 ExFreePoolWithTag(DeviceExtension->UsageListBuffer, MOUHID_TAG); 992 DeviceExtension->UsageListBuffer = NULL; 993 DeviceExtension->CurrentUsageList = NULL; 994 DeviceExtension->PreviousUsageList = NULL; 995 DeviceExtension->MakeUsageList = NULL; 996 DeviceExtension->BreakUsageList = NULL; 997 } 998 999 if (DeviceExtension->ReportMDL) 1000 { 1001 IoFreeMdl(DeviceExtension->ReportMDL); 1002 DeviceExtension->ReportMDL = NULL; 1003 } 1004 1005 if (DeviceExtension->Report) 1006 { 1007 ExFreePoolWithTag(DeviceExtension->Report, MOUHID_TAG); 1008 DeviceExtension->Report = NULL; 1009 } 1010 1011 return STATUS_SUCCESS; 1012 } 1013 1014 NTSTATUS 1015 NTAPI 1016 MouHid_Flush( 1017 IN PDEVICE_OBJECT DeviceObject, 1018 IN PIRP Irp) 1019 { 1020 PIO_STACK_LOCATION IoStack; 1021 PMOUHID_DEVICE_EXTENSION DeviceExtension; 1022 1023 /* get device extension */ 1024 DeviceExtension = DeviceObject->DeviceExtension; 1025 1026 /* skip current stack location */ 1027 IoSkipCurrentIrpStackLocation(Irp); 1028 1029 /* get next stack location */ 1030 IoStack = IoGetNextIrpStackLocation(Irp); 1031 1032 /* change request to hid flush queue request */ 1033 IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL; 1034 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE; 1035 1036 /* call device */ 1037 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 1038 } 1039 1040 NTSTATUS 1041 NTAPI 1042 MouHid_Pnp( 1043 IN PDEVICE_OBJECT DeviceObject, 1044 IN PIRP Irp) 1045 { 1046 PIO_STACK_LOCATION IoStack; 1047 KEVENT Event; 1048 NTSTATUS Status; 1049 PMOUHID_DEVICE_EXTENSION DeviceExtension; 1050 1051 /* get device extension */ 1052 DeviceExtension = DeviceObject->DeviceExtension; 1053 1054 /* get current irp stack */ 1055 IoStack = IoGetCurrentIrpStackLocation(Irp); 1056 DPRINT("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction); 1057 1058 switch (IoStack->MinorFunction) 1059 { 1060 case IRP_MN_STOP_DEVICE: 1061 case IRP_MN_SURPRISE_REMOVAL: 1062 /* free resources */ 1063 MouHid_FreeResources(DeviceObject); 1064 case IRP_MN_CANCEL_REMOVE_DEVICE: 1065 case IRP_MN_QUERY_STOP_DEVICE: 1066 case IRP_MN_CANCEL_STOP_DEVICE: 1067 case IRP_MN_QUERY_REMOVE_DEVICE: 1068 /* indicate success */ 1069 Irp->IoStatus.Status = STATUS_SUCCESS; 1070 1071 /* skip irp stack location */ 1072 IoSkipCurrentIrpStackLocation(Irp); 1073 1074 /* dispatch to lower device */ 1075 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 1076 1077 case IRP_MN_REMOVE_DEVICE: 1078 /* FIXME synchronization */ 1079 1080 /* request stop */ 1081 DeviceExtension->StopReadReport = TRUE; 1082 1083 /* cancel irp */ 1084 IoCancelIrp(DeviceExtension->Irp); 1085 1086 /* free resources */ 1087 MouHid_FreeResources(DeviceObject); 1088 1089 /* indicate success */ 1090 Irp->IoStatus.Status = STATUS_SUCCESS; 1091 1092 /* skip irp stack location */ 1093 IoSkipCurrentIrpStackLocation(Irp); 1094 1095 /* dispatch to lower device */ 1096 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 1097 1098 /* wait for completion of stop event */ 1099 KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL); 1100 1101 /* free irp */ 1102 IoFreeIrp(DeviceExtension->Irp); 1103 1104 /* detach device */ 1105 IoDetachDevice(DeviceExtension->NextDeviceObject); 1106 1107 /* delete device */ 1108 IoDeleteDevice(DeviceObject); 1109 1110 /* done */ 1111 return Status; 1112 1113 case IRP_MN_START_DEVICE: 1114 /* init event */ 1115 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1116 1117 /* copy stack location */ 1118 IoCopyCurrentIrpStackLocationToNext (Irp); 1119 1120 /* set completion routine */ 1121 IoSetCompletionRoutine(Irp, MouHid_StartDeviceCompletion, &Event, TRUE, TRUE, TRUE); 1122 Irp->IoStatus.Status = 0; 1123 1124 /* pass request */ 1125 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 1126 if (Status == STATUS_PENDING) 1127 { 1128 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1129 Status = Irp->IoStatus.Status; 1130 } 1131 1132 if (!NT_SUCCESS(Status)) 1133 { 1134 /* failed */ 1135 Irp->IoStatus.Status = Status; 1136 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1137 return Status; 1138 } 1139 1140 /* lets start the device */ 1141 Status = MouHid_StartDevice(DeviceObject); 1142 DPRINT("MouHid_StartDevice %x\n", Status); 1143 1144 /* complete request */ 1145 Irp->IoStatus.Status = Status; 1146 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1147 1148 /* done */ 1149 return Status; 1150 1151 default: 1152 /* skip irp stack location */ 1153 IoSkipCurrentIrpStackLocation(Irp); 1154 1155 /* dispatch to lower device */ 1156 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 1157 } 1158 } 1159 1160 NTSTATUS 1161 NTAPI 1162 MouHid_AddDevice( 1163 IN PDRIVER_OBJECT DriverObject, 1164 IN PDEVICE_OBJECT PhysicalDeviceObject) 1165 { 1166 NTSTATUS Status; 1167 PDEVICE_OBJECT DeviceObject, NextDeviceObject; 1168 PMOUHID_DEVICE_EXTENSION DeviceExtension; 1169 POWER_STATE State; 1170 1171 /* create device object */ 1172 Status = IoCreateDevice(DriverObject, 1173 sizeof(MOUHID_DEVICE_EXTENSION), 1174 NULL, 1175 FILE_DEVICE_MOUSE, 1176 0, 1177 FALSE, 1178 &DeviceObject); 1179 if (!NT_SUCCESS(Status)) 1180 { 1181 /* failed to create device object */ 1182 return Status; 1183 } 1184 1185 /* now attach it */ 1186 NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); 1187 if (!NextDeviceObject) 1188 { 1189 /* failed to attach */ 1190 IoDeleteDevice(DeviceObject); 1191 return STATUS_DEVICE_NOT_CONNECTED; 1192 } 1193 1194 /* get device extension */ 1195 DeviceExtension = DeviceObject->DeviceExtension; 1196 1197 /* zero extension */ 1198 RtlZeroMemory(DeviceExtension, sizeof(MOUHID_DEVICE_EXTENSION)); 1199 1200 /* init device extension */ 1201 DeviceExtension->MouseIdentifier = MOUSE_HID_HARDWARE; 1202 DeviceExtension->WheelUsagePage = 0; 1203 DeviceExtension->NextDeviceObject = NextDeviceObject; 1204 KeInitializeEvent(&DeviceExtension->ReadCompletionEvent, NotificationEvent, FALSE); 1205 DeviceExtension->Irp = IoAllocateIrp(NextDeviceObject->StackSize, FALSE); 1206 1207 /* FIXME handle allocation error */ 1208 ASSERT(DeviceExtension->Irp); 1209 1210 /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */ 1211 1212 /* set power state to D0 */ 1213 State.DeviceState = PowerDeviceD0; 1214 PoSetPowerState(DeviceObject, DevicePowerState, State); 1215 1216 /* init device object */ 1217 DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; 1218 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1219 1220 /* completed successfully */ 1221 return STATUS_SUCCESS; 1222 } 1223 1224 VOID 1225 NTAPI 1226 MouHid_Unload( 1227 IN PDRIVER_OBJECT DriverObject) 1228 { 1229 UNIMPLEMENTED; 1230 } 1231 1232 1233 NTSTATUS 1234 NTAPI 1235 DriverEntry( 1236 IN PDRIVER_OBJECT DriverObject, 1237 IN PUNICODE_STRING RegPath) 1238 { 1239 /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */ 1240 1241 /* initialize driver object */ 1242 DriverObject->MajorFunction[IRP_MJ_CREATE] = MouHid_Create; 1243 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouHid_Close; 1244 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = MouHid_Flush; 1245 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MouHid_DeviceControl; 1246 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MouHid_InternalDeviceControl; 1247 DriverObject->MajorFunction[IRP_MJ_POWER] = MouHid_Power; 1248 DriverObject->MajorFunction[IRP_MJ_PNP] = MouHid_Pnp; 1249 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = MouHid_SystemControl; 1250 DriverObject->DriverUnload = MouHid_Unload; 1251 DriverObject->DriverExtension->AddDevice = MouHid_AddDevice; 1252 1253 /* done */ 1254 return STATUS_SUCCESS; 1255 } 1256