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 MOUSE_LEFT_BUTTON_DOWN, 16 MOUSE_RIGHT_BUTTON_DOWN, 17 MOUSE_MIDDLE_BUTTON_DOWN, 18 MOUSE_BUTTON_4_DOWN, 19 MOUSE_BUTTON_5_DOWN 20 }; 21 22 static USHORT MouHid_ButtonDownFlags[] = 23 { 24 MOUSE_LEFT_BUTTON_UP, 25 MOUSE_RIGHT_BUTTON_UP, 26 MOUSE_MIDDLE_BUTTON_UP, 27 MOUSE_BUTTON_4_UP, 28 MOUSE_BUTTON_5_UP 29 }; 30 31 VOID 32 MouHid_GetButtonMove( 33 IN PMOUHID_DEVICE_EXTENSION DeviceExtension, 34 OUT PLONG LastX, 35 OUT PLONG LastY) 36 { 37 NTSTATUS Status; 38 39 /* init result */ 40 *LastX = 0; 41 *LastY = 0; 42 43 /* get scaled usage value x */ 44 Status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_X, (PLONG)LastX, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength); 45 /* FIXME handle error */ 46 ASSERT(Status == HIDP_STATUS_SUCCESS); 47 48 /* get scaled usage value y */ 49 Status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Y, (PLONG)LastY, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength); 50 /* FIXME handle error */ 51 ASSERT(Status == HIDP_STATUS_SUCCESS); 52 53 } 54 55 56 VOID 57 MouHid_GetButtonFlags( 58 IN PMOUHID_DEVICE_EXTENSION DeviceExtension, 59 OUT PUSHORT ButtonFlags) 60 { 61 NTSTATUS Status; 62 USAGE Usage; 63 ULONG Index; 64 PUSAGE TempList; 65 ULONG CurrentUsageListLength; 66 67 /* init flags */ 68 *ButtonFlags = 0; 69 70 /* get usages */ 71 CurrentUsageListLength = DeviceExtension->UsageListLength; 72 Status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, HIDP_LINK_COLLECTION_UNSPECIFIED, DeviceExtension->CurrentUsageList, &CurrentUsageListLength, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength); 73 if (Status != HIDP_STATUS_SUCCESS) 74 { 75 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status); 76 return; 77 } 78 79 /* extract usage list difference */ 80 Status = HidP_UsageListDifference(DeviceExtension->PreviousUsageList, DeviceExtension->CurrentUsageList, DeviceExtension->BreakUsageList, DeviceExtension->MakeUsageList, DeviceExtension->UsageListLength); 81 if (Status != HIDP_STATUS_SUCCESS) 82 { 83 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status); 84 return; 85 } 86 87 if (DeviceExtension->UsageListLength) 88 { 89 Index = 0; 90 do 91 { 92 /* get usage */ 93 Usage = DeviceExtension->BreakUsageList[Index]; 94 if (!Usage) 95 break; 96 97 if (Usage <= 5) 98 { 99 /* max 5 buttons supported */ 100 *ButtonFlags |= MouHid_ButtonDownFlags[Usage]; 101 } 102 103 /* move to next index*/ 104 Index++; 105 }while(Index < DeviceExtension->UsageListLength); 106 } 107 108 if (DeviceExtension->UsageListLength) 109 { 110 Index = 0; 111 do 112 { 113 /* get usage */ 114 Usage = DeviceExtension->MakeUsageList[Index]; 115 if (!Usage) 116 break; 117 118 if (Usage <= 5) 119 { 120 /* max 5 buttons supported */ 121 *ButtonFlags |= MouHid_ButtonUpFlags[Usage]; 122 } 123 124 /* move to next index*/ 125 Index++; 126 }while(Index < DeviceExtension->UsageListLength); 127 } 128 129 /* now switch the previous list with current list */ 130 TempList = DeviceExtension->CurrentUsageList; 131 DeviceExtension->CurrentUsageList = DeviceExtension->PreviousUsageList; 132 DeviceExtension->PreviousUsageList = TempList; 133 } 134 135 VOID 136 MouHid_DispatchInputData( 137 IN PMOUHID_DEVICE_EXTENSION DeviceExtension, 138 IN PMOUSE_INPUT_DATA InputData) 139 { 140 KIRQL OldIrql; 141 ULONG InputDataConsumed; 142 143 if (!DeviceExtension->ClassService) 144 return; 145 146 /* sanity check */ 147 ASSERT(DeviceExtension->ClassService); 148 ASSERT(DeviceExtension->ClassDeviceObject); 149 150 /* raise irql */ 151 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 152 153 /* dispatch input data */ 154 (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)(DeviceExtension->ClassDeviceObject, InputData, InputData + 1, &InputDataConsumed); 155 156 /* lower irql to previous level */ 157 KeLowerIrql(OldIrql); 158 } 159 160 NTSTATUS 161 NTAPI 162 MouHid_ReadCompletion( 163 IN PDEVICE_OBJECT DeviceObject, 164 IN PIRP Irp, 165 IN PVOID Context) 166 { 167 PMOUHID_DEVICE_EXTENSION DeviceExtension; 168 USHORT ButtonFlags; 169 LONG UsageValue; 170 NTSTATUS Status; 171 LONG LastX, LastY; 172 MOUSE_INPUT_DATA MouseInputData; 173 174 /* get device extension */ 175 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)Context; 176 177 if (Irp->IoStatus.Status == STATUS_PRIVILEGE_NOT_HELD || 178 Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED || 179 Irp->IoStatus.Status == STATUS_CANCELLED || 180 DeviceExtension->StopReadReport) 181 { 182 /* failed to read or should be stopped*/ 183 DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp->IoStatus.Status); 184 185 /* report no longer active */ 186 DeviceExtension->ReadReportActive = FALSE; 187 188 /* request stopping of the report cycle */ 189 DeviceExtension->StopReadReport = FALSE; 190 191 /* signal completion event */ 192 KeSetEvent(&DeviceExtension->ReadCompletionEvent, 0, 0); 193 return STATUS_MORE_PROCESSING_REQUIRED; 194 } 195 196 /* get mouse change flags */ 197 MouHid_GetButtonFlags(DeviceExtension, &ButtonFlags); 198 199 /* get mouse change */ 200 MouHid_GetButtonMove(DeviceExtension, &LastX, &LastY); 201 202 /* init input data */ 203 RtlZeroMemory(&MouseInputData, sizeof(MOUSE_INPUT_DATA)); 204 205 /* init input data */ 206 MouseInputData.ButtonFlags = ButtonFlags; 207 MouseInputData.LastX = LastX; 208 MouseInputData.LastY = LastY; 209 210 /* detect mouse wheel change */ 211 if (DeviceExtension->MouseIdentifier == WHEELMOUSE_HID_HARDWARE) 212 { 213 /* get usage */ 214 UsageValue = 0; 215 Status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_WHEEL, &UsageValue, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength); 216 if (Status == HIDP_STATUS_SUCCESS) 217 { 218 /* store wheel status */ 219 MouseInputData.ButtonFlags |= MOUSE_WHEEL; 220 MouseInputData.ButtonData = (USHORT)UsageValue; /* FIXME */ 221 } 222 else 223 { 224 DPRINT1("[MOUHID] failed to get wheel status with %x\n", Status); 225 } 226 } 227 228 DPRINT1("[MOUHID] LastX %ld LastY %ld Flags %x ButtonData %x\n", MouseInputData.LastX, MouseInputData.LastY, MouseInputData.ButtonFlags, MouseInputData.ButtonData); 229 230 /* dispatch mouse action */ 231 MouHid_DispatchInputData(DeviceExtension, &MouseInputData); 232 233 /* re-init read */ 234 MouHid_InitiateRead(DeviceExtension); 235 236 /* stop completion */ 237 return STATUS_MORE_PROCESSING_REQUIRED; 238 } 239 240 NTSTATUS 241 MouHid_InitiateRead( 242 IN PMOUHID_DEVICE_EXTENSION DeviceExtension) 243 { 244 PIO_STACK_LOCATION IoStack; 245 NTSTATUS Status; 246 247 /* re-use irp */ 248 IoReuseIrp(DeviceExtension->Irp, STATUS_SUCCESS); 249 250 /* init irp */ 251 DeviceExtension->Irp->MdlAddress = DeviceExtension->ReportMDL; 252 253 /* get next stack location */ 254 IoStack = IoGetNextIrpStackLocation(DeviceExtension->Irp); 255 256 /* init stack location */ 257 IoStack->Parameters.Read.Length = DeviceExtension->ReportLength; 258 IoStack->Parameters.Read.Key = 0; 259 IoStack->Parameters.Read.ByteOffset.QuadPart = 0LL; 260 IoStack->MajorFunction = IRP_MJ_READ; 261 IoStack->FileObject = DeviceExtension->FileObject; 262 263 /* set completion routine */ 264 IoSetCompletionRoutine(DeviceExtension->Irp, MouHid_ReadCompletion, DeviceExtension, TRUE, TRUE, TRUE); 265 266 /* read is active */ 267 DeviceExtension->ReadReportActive = TRUE; 268 269 /* start the read */ 270 Status = IoCallDriver(DeviceExtension->NextDeviceObject, DeviceExtension->Irp); 271 272 /* done */ 273 return Status; 274 } 275 276 NTSTATUS 277 NTAPI 278 MouHid_CreateCompletion( 279 IN PDEVICE_OBJECT DeviceObject, 280 IN PIRP Irp, 281 IN PVOID Context) 282 { 283 KeSetEvent((PKEVENT)Context, 0, FALSE); 284 return STATUS_MORE_PROCESSING_REQUIRED; 285 } 286 287 288 NTSTATUS 289 NTAPI 290 MouHid_Create( 291 IN PDEVICE_OBJECT DeviceObject, 292 IN PIRP Irp) 293 { 294 PIO_STACK_LOCATION IoStack; 295 NTSTATUS Status; 296 KEVENT Event; 297 PMOUHID_DEVICE_EXTENSION DeviceExtension; 298 299 DPRINT1("MOUHID: IRP_MJ_CREATE\n"); 300 301 /* get device extension */ 302 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 303 304 /* get stack location */ 305 IoStack = IoGetCurrentIrpStackLocation(Irp); 306 307 /* copy stack location to next */ 308 IoCopyCurrentIrpStackLocationToNext(Irp); 309 310 /* init event */ 311 KeInitializeEvent(&Event, NotificationEvent, FALSE); 312 313 /* prepare irp */ 314 IoSetCompletionRoutine(Irp, MouHid_CreateCompletion, &Event, TRUE, TRUE, TRUE); 315 316 /* call lower driver */ 317 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 318 if (Status == STATUS_PENDING) 319 { 320 /* request pending */ 321 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 322 } 323 324 /* check for success */ 325 if (!NT_SUCCESS(Status)) 326 { 327 /* failed */ 328 Irp->IoStatus.Status = Status; 329 IoCompleteRequest(Irp, IO_NO_INCREMENT); 330 return Status; 331 } 332 333 /* is the driver already in use */ 334 if (DeviceExtension->FileObject == NULL) 335 { 336 /* did the caller specify correct attributes */ 337 ASSERT(IoStack->Parameters.Create.SecurityContext); 338 if (IoStack->Parameters.Create.SecurityContext->DesiredAccess) 339 { 340 /* store file object */ 341 DeviceExtension->FileObject = IoStack->FileObject; 342 343 /* reset event */ 344 KeResetEvent(&DeviceExtension->ReadCompletionEvent); 345 346 /* initiating read */ 347 Status = MouHid_InitiateRead(DeviceExtension); 348 DPRINT1("[MOUHID] MouHid_InitiateRead: status %x\n", Status); 349 if (Status == STATUS_PENDING) 350 { 351 /* report irp is pending */ 352 Status = STATUS_SUCCESS; 353 } 354 } 355 } 356 357 /* complete request */ 358 Irp->IoStatus.Status = Status; 359 IoCompleteRequest(Irp, IO_NO_INCREMENT); 360 return Status; 361 } 362 363 364 NTSTATUS 365 NTAPI 366 MouHid_Close( 367 IN PDEVICE_OBJECT DeviceObject, 368 IN PIRP Irp) 369 { 370 PMOUHID_DEVICE_EXTENSION DeviceExtension; 371 372 /* get device extension */ 373 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 374 375 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive); 376 377 if (DeviceExtension->ReadReportActive) 378 { 379 /* request stopping of the report cycle */ 380 DeviceExtension->StopReadReport = TRUE; 381 382 /* wait until the reports have been read */ 383 KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL); 384 385 /* cancel irp */ 386 IoCancelIrp(DeviceExtension->Irp); 387 } 388 389 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive); 390 391 /* remove file object */ 392 DeviceExtension->FileObject = NULL; 393 394 /* skip location */ 395 IoSkipCurrentIrpStackLocation(Irp); 396 397 /* pass irp to down the stack */ 398 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 399 } 400 401 NTSTATUS 402 NTAPI 403 MouHid_DeviceControl( 404 IN PDEVICE_OBJECT DeviceObject, 405 IN PIRP Irp) 406 { 407 PIO_STACK_LOCATION IoStack; 408 PMOUSE_ATTRIBUTES Attributes; 409 PMOUHID_DEVICE_EXTENSION DeviceExtension; 410 PCONNECT_DATA Data; 411 412 /* get current stack location */ 413 IoStack = IoGetCurrentIrpStackLocation(Irp); 414 415 DPRINT1("[MOUHID] DeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode); 416 417 /* get device extension */ 418 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 419 420 /* handle requests */ 421 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_MOUSE_QUERY_ATTRIBUTES) 422 { 423 /* verify output buffer length */ 424 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES)) 425 { 426 /* invalid request */ 427 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 428 IoCompleteRequest(Irp, IO_NO_INCREMENT); 429 return STATUS_BUFFER_TOO_SMALL; 430 } 431 432 /* get output buffer */ 433 Attributes = (PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer; 434 435 /* type of mouse */ 436 Attributes->MouseIdentifier = DeviceExtension->MouseIdentifier; 437 438 /* number of buttons */ 439 Attributes->NumberOfButtons = DeviceExtension->UsageListLength; 440 441 /* sample rate not used for usb */ 442 Attributes->SampleRate = 0; 443 444 /* queue length */ 445 Attributes->InputDataQueueLength = 2; 446 447 /* complete request */ 448 Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES); 449 Irp->IoStatus.Status = STATUS_SUCCESS; 450 IoCompleteRequest(Irp, IO_NO_INCREMENT); 451 return STATUS_SUCCESS; 452 } 453 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_CONNECT) 454 { 455 /* verify input buffer length */ 456 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA)) 457 { 458 /* invalid request */ 459 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 460 IoCompleteRequest(Irp, IO_NO_INCREMENT); 461 return STATUS_INVALID_PARAMETER; 462 } 463 464 /* is it already connected */ 465 if (DeviceExtension->ClassService) 466 { 467 /* already connected */ 468 Irp->IoStatus.Status = STATUS_SHARING_VIOLATION; 469 IoCompleteRequest(Irp, IO_NO_INCREMENT); 470 return STATUS_SHARING_VIOLATION; 471 } 472 473 /* get connect data */ 474 Data = (PCONNECT_DATA)IoStack->Parameters.DeviceIoControl.Type3InputBuffer; 475 476 /* store connect details */ 477 DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject; 478 DeviceExtension->ClassService = Data->ClassService; 479 480 /* completed successfully */ 481 Irp->IoStatus.Status = STATUS_SUCCESS; 482 IoCompleteRequest(Irp, IO_NO_INCREMENT); 483 return STATUS_SUCCESS; 484 } 485 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISCONNECT) 486 { 487 /* not supported */ 488 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; 489 IoCompleteRequest(Irp, IO_NO_INCREMENT); 490 return STATUS_NOT_IMPLEMENTED; 491 } 492 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_ENABLE) 493 { 494 /* not supported */ 495 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 496 IoCompleteRequest(Irp, IO_NO_INCREMENT); 497 return STATUS_NOT_SUPPORTED; 498 } 499 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISABLE) 500 { 501 /* not supported */ 502 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 503 IoCompleteRequest(Irp, IO_NO_INCREMENT); 504 return STATUS_INVALID_DEVICE_REQUEST; 505 } 506 507 /* unknown request not supported */ 508 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 509 IoCompleteRequest(Irp, IO_NO_INCREMENT); 510 return STATUS_NOT_SUPPORTED; 511 } 512 513 NTSTATUS 514 NTAPI 515 MouHid_InternalDeviceControl( 516 IN PDEVICE_OBJECT DeviceObject, 517 IN PIRP Irp) 518 { 519 PMOUHID_DEVICE_EXTENSION DeviceExtension; 520 521 /* get device extension */ 522 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 523 524 /* skip stack location */ 525 IoSkipCurrentIrpStackLocation(Irp); 526 527 /* pass and forget */ 528 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 529 } 530 531 NTSTATUS 532 NTAPI 533 MouHid_Power( 534 IN PDEVICE_OBJECT DeviceObject, 535 IN PIRP Irp) 536 { 537 UNIMPLEMENTED 538 ASSERT(FALSE); 539 return STATUS_NOT_IMPLEMENTED; 540 } 541 542 NTSTATUS 543 MouHid_SubmitRequest( 544 PDEVICE_OBJECT DeviceObject, 545 ULONG IoControlCode, 546 ULONG InputBufferSize, 547 PVOID InputBuffer, 548 ULONG OutputBufferSize, 549 PVOID OutputBuffer) 550 { 551 KEVENT Event; 552 PMOUHID_DEVICE_EXTENSION DeviceExtension; 553 PIRP Irp; 554 NTSTATUS Status; 555 IO_STATUS_BLOCK IoStatus; 556 557 /* get device extension */ 558 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 559 560 /* init event */ 561 KeInitializeEvent(&Event, NotificationEvent, FALSE); 562 563 /* build request */ 564 Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceExtension->NextDeviceObject, InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize, FALSE, &Event, &IoStatus); 565 if (!Irp) 566 { 567 /* no memory */ 568 return STATUS_INSUFFICIENT_RESOURCES; 569 } 570 571 /* send request */ 572 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 573 if (Status == STATUS_PENDING) 574 { 575 /* wait for request to complete */ 576 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 577 Status = IoStatus.Status; 578 } 579 580 /* done */ 581 return Status; 582 } 583 584 NTSTATUS 585 NTAPI 586 MouHid_StartDevice( 587 IN PDEVICE_OBJECT DeviceObject) 588 { 589 NTSTATUS Status; 590 ULONG Buttons; 591 HID_COLLECTION_INFORMATION Information; 592 PVOID PreparsedData; 593 HIDP_CAPS Capabilities; 594 ULONG ValueCapsLength; 595 HIDP_VALUE_CAPS ValueCaps; 596 PMOUHID_DEVICE_EXTENSION DeviceExtension; 597 PUSHORT Buffer; 598 599 /* get device extension */ 600 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 601 602 /* query collection information */ 603 Status = MouHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_INFORMATION, 0, NULL, sizeof(HID_COLLECTION_INFORMATION), &Information); 604 if (!NT_SUCCESS(Status)) 605 { 606 /* failed to query collection information */ 607 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status); 608 return Status; 609 } 610 611 /* lets allocate space for preparsed data */ 612 PreparsedData = ExAllocatePool(NonPagedPool, Information.DescriptorSize); 613 if (!PreparsedData) 614 { 615 /* no memory */ 616 DPRINT1("[MOUHID] no memory size %u\n", Information.DescriptorSize); 617 return STATUS_INSUFFICIENT_RESOURCES; 618 } 619 620 /* now obtain the preparsed data */ 621 Status = MouHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_DESCRIPTOR, 0, NULL, Information.DescriptorSize, PreparsedData); 622 if (!NT_SUCCESS(Status)) 623 { 624 /* failed to get preparsed data */ 625 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status); 626 ExFreePool(PreparsedData); 627 return Status; 628 } 629 630 /* lets get the caps */ 631 Status = HidP_GetCaps(PreparsedData, &Capabilities); 632 if (!NT_SUCCESS(Status)) 633 { 634 /* failed to get capabilities */ 635 DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status); 636 ExFreePool(PreparsedData); 637 return Status; 638 } 639 640 DPRINT1("[MOUHID] Usage %x UsagePage %x\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength); 641 642 /* verify capabilities */ 643 if (Capabilities.Usage != HID_USAGE_GENERIC_POINTER && Capabilities.Usage != HID_USAGE_GENERIC_MOUSE || Capabilities.UsagePage != HID_USAGE_PAGE_GENERIC) 644 { 645 /* not supported */ 646 ExFreePool(PreparsedData); 647 return STATUS_UNSUCCESSFUL; 648 } 649 650 /* init input report*/ 651 DeviceExtension->ReportLength = Capabilities.InputReportByteLength; 652 ASSERT(DeviceExtension->ReportLength); 653 DeviceExtension->Report = (PUCHAR)ExAllocatePool(NonPagedPool, DeviceExtension->ReportLength); 654 ASSERT(DeviceExtension->Report); 655 RtlZeroMemory(DeviceExtension->Report, DeviceExtension->ReportLength); 656 657 /* build mdl */ 658 DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report, DeviceExtension->ReportLength, FALSE, FALSE, NULL); 659 ASSERT(DeviceExtension->ReportMDL); 660 661 /* init mdl */ 662 MmBuildMdlForNonPagedPool(DeviceExtension->ReportMDL); 663 664 /* get max number of buttons */ 665 Buttons = HidP_MaxUsageListLength(HidP_Input, HID_USAGE_PAGE_BUTTON, PreparsedData); 666 DPRINT1("[MOUHID] Buttons %lu\n", Buttons); 667 ASSERT(Buttons > 0); 668 669 /* now allocate an array for those buttons */ 670 Buffer = ExAllocatePool(NonPagedPool, sizeof(USAGE) * 4 * Buttons); 671 if (!Buffer) 672 { 673 /* no memory */ 674 ExFreePool(PreparsedData); 675 return STATUS_INSUFFICIENT_RESOURCES; 676 } 677 678 /* init usage lists */ 679 RtlZeroMemory(Buffer, sizeof(USAGE) * 4 * Buttons); 680 DeviceExtension->CurrentUsageList = Buffer; 681 Buffer += Buttons; 682 DeviceExtension->PreviousUsageList = Buffer; 683 Buffer += Buttons; 684 DeviceExtension->MakeUsageList = Buffer; 685 Buffer += Buttons; 686 DeviceExtension->BreakUsageList = Buffer; 687 688 /* store number of buttons */ 689 DeviceExtension->UsageListLength = (USHORT)Buttons; 690 691 /* store preparsed data */ 692 DeviceExtension->PreparsedData = PreparsedData; 693 694 ValueCapsLength = 1; 695 HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_X, &ValueCaps, &ValueCapsLength, PreparsedData); 696 697 ValueCapsLength = 1; 698 HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Y, &ValueCaps, &ValueCapsLength, PreparsedData); 699 700 /* now check for wheel mouse support */ 701 ValueCapsLength = 1; 702 Status = HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_WHEEL, &ValueCaps, &ValueCapsLength, PreparsedData); 703 if (Status == HIDP_STATUS_SUCCESS ) 704 { 705 /* mouse has wheel support */ 706 DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE; 707 DeviceExtension->WheelUsagePage = ValueCaps.UsagePage; 708 DPRINT1("[MOUHID] mouse wheel support detected\n", Status); 709 } 710 else 711 { 712 /* check if the mouse has z-axis */ 713 ValueCapsLength = 1; 714 Status = HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Z, &ValueCaps, &ValueCapsLength, PreparsedData); 715 if (Status == HIDP_STATUS_SUCCESS && ValueCapsLength == 1) 716 { 717 /* wheel support */ 718 DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE; 719 DeviceExtension->WheelUsagePage = ValueCaps.UsagePage; 720 DPRINT1("[MOUHID] mouse wheel support detected with z-axis\n", Status); 721 } 722 } 723 724 /* completed successfully */ 725 return STATUS_SUCCESS; 726 } 727 728 NTSTATUS 729 NTAPI 730 MouHid_StartDeviceCompletion( 731 IN PDEVICE_OBJECT DeviceObject, 732 IN PIRP Irp, 733 IN PVOID Context) 734 { 735 KeSetEvent((PKEVENT)Context, 0, FALSE); 736 return STATUS_MORE_PROCESSING_REQUIRED; 737 } 738 739 NTSTATUS 740 NTAPI 741 MouHid_Pnp( 742 IN PDEVICE_OBJECT DeviceObject, 743 IN PIRP Irp) 744 { 745 PIO_STACK_LOCATION IoStack; 746 KEVENT Event; 747 NTSTATUS Status; 748 PMOUHID_DEVICE_EXTENSION DeviceExtension; 749 750 /* get device extension */ 751 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 752 753 /* get current irp stack */ 754 IoStack = IoGetCurrentIrpStackLocation(Irp); 755 DPRINT1("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction); 756 757 if (IoStack->MinorFunction == IRP_MN_STOP_DEVICE || IoStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE || IoStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE || IoStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) 758 { 759 /* indicate success */ 760 Irp->IoStatus.Status = STATUS_SUCCESS; 761 762 /* skip irp stack location */ 763 IoSkipCurrentIrpStackLocation(Irp); 764 765 /* dispatch to lower device */ 766 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 767 } 768 else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE) 769 { 770 /* FIXME synchronization */ 771 772 /* cancel irp */ 773 IoCancelIrp(DeviceExtension->Irp); 774 775 /* indicate success */ 776 Irp->IoStatus.Status = STATUS_SUCCESS; 777 778 /* skip irp stack location */ 779 IoSkipCurrentIrpStackLocation(Irp); 780 781 /* dispatch to lower device */ 782 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 783 784 IoFreeIrp(DeviceExtension->Irp); 785 IoDetachDevice(DeviceExtension->NextDeviceObject); 786 IoDeleteDevice(DeviceObject); 787 return Status; 788 } 789 else if (IoStack->MinorFunction == IRP_MN_START_DEVICE) 790 { 791 /* init event */ 792 KeInitializeEvent(&Event, NotificationEvent, FALSE); 793 794 /* copy stack location */ 795 IoCopyCurrentIrpStackLocationToNext (Irp); 796 797 /* set completion routine */ 798 IoSetCompletionRoutine(Irp, MouHid_StartDeviceCompletion, &Event, TRUE, TRUE, TRUE); 799 Irp->IoStatus.Status = 0; 800 801 /* pass request */ 802 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 803 if (Status == STATUS_PENDING) 804 { 805 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 806 Status = Irp->IoStatus.Status; 807 } 808 809 if (!NT_SUCCESS(Status)) 810 { 811 /* failed */ 812 Irp->IoStatus.Status = Status; 813 IoCompleteRequest(Irp, IO_NO_INCREMENT); 814 return Status; 815 } 816 817 /* lets start the device */ 818 Status = MouHid_StartDevice(DeviceObject); 819 DPRINT1("MouHid_StartDevice %x\n", Status); 820 821 /* complete request */ 822 Irp->IoStatus.Status = Status; 823 IoCompleteRequest(Irp, IO_NO_INCREMENT); 824 825 /* done */ 826 return Status; 827 } 828 else 829 { 830 /* skip irp stack location */ 831 IoSkipCurrentIrpStackLocation(Irp); 832 833 /* dispatch to lower device */ 834 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 835 } 836 } 837 838 NTSTATUS 839 NTAPI 840 MouHid_AddDevice( 841 IN PDRIVER_OBJECT DriverObject, 842 IN PDEVICE_OBJECT PhysicalDeviceObject) 843 { 844 NTSTATUS Status; 845 PDEVICE_OBJECT DeviceObject, NextDeviceObject; 846 PMOUHID_DEVICE_EXTENSION DeviceExtension; 847 POWER_STATE State; 848 849 /* create device object */ 850 Status = IoCreateDevice(DriverObject, sizeof(MOUHID_DEVICE_EXTENSION), NULL, FILE_DEVICE_MOUSE, 0, FALSE, &DeviceObject); 851 if (!NT_SUCCESS(Status)) 852 { 853 /* failed to create device object */ 854 return Status; 855 } 856 857 /* now attach it */ 858 NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); 859 if (!NextDeviceObject) 860 { 861 /* failed to attach */ 862 IoDeleteDevice(DeviceObject); 863 return STATUS_DEVICE_NOT_CONNECTED; 864 } 865 866 /* get device extension */ 867 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 868 869 /* zero extension */ 870 RtlZeroMemory(DeviceExtension, sizeof(MOUHID_DEVICE_EXTENSION)); 871 872 /* init device extension */ 873 DeviceExtension->MouseIdentifier = MOUSE_HID_HARDWARE; 874 DeviceExtension->WheelUsagePage = 0; 875 DeviceExtension->NextDeviceObject = NextDeviceObject; 876 KeInitializeEvent(&DeviceExtension->ReadCompletionEvent, NotificationEvent, FALSE); 877 DeviceExtension->Irp = IoAllocateIrp(NextDeviceObject->StackSize, FALSE); 878 879 /* FIXME handle allocation error */ 880 ASSERT(DeviceExtension->Irp); 881 882 /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */ 883 884 /* set power state to D0 */ 885 State.DeviceState = PowerDeviceD0; 886 PoSetPowerState(DeviceObject, DevicePowerState, State); 887 888 /* init device object */ 889 DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; 890 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 891 892 /* completed successfully */ 893 return STATUS_SUCCESS; 894 } 895 896 VOID 897 NTAPI 898 MouHid_Unload( 899 IN PDRIVER_OBJECT DriverObject) 900 { 901 UNIMPLEMENTED 902 } 903 904 905 NTSTATUS 906 NTAPI 907 DriverEntry( 908 IN PDRIVER_OBJECT DriverObject, 909 IN PUNICODE_STRING RegPath) 910 { 911 /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */ 912 913 /* initialize driver object */ 914 DriverObject->DriverUnload = MouHid_Unload; 915 DriverObject->DriverExtension->AddDevice = MouHid_AddDevice; 916 DriverObject->MajorFunction[IRP_MJ_CREATE] = MouHid_Create; 917 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouHid_Close; 918 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MouHid_DeviceControl; 919 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MouHid_InternalDeviceControl; 920 DriverObject->MajorFunction[IRP_MJ_POWER] = MouHid_Power; 921 DriverObject->MajorFunction[IRP_MJ_PNP] = MouHid_Pnp; 922 DriverObject->DriverUnload = MouHid_Unload; 923 DriverObject->DriverExtension->AddDevice = MouHid_AddDevice; 924 925 /* done */ 926 return STATUS_SUCCESS; 927 } 928