1 // Copyright (c) 2004, Antony C. Roberts 2 3 // Use of this file is subject to the terms 4 // described in the LICENSE.TXT file that 5 // accompanies this file. 6 // 7 // Your use of this file indicates your 8 // acceptance of the terms described in 9 // LICENSE.TXT. 10 // 11 // http://www.freebt.net 12 13 #include "fbtusb.h" 14 #include "fbtpnp.h" 15 #include "fbtpwr.h" 16 #include "fbtdev.h" 17 #include "fbtwmi.h" 18 #include "fbtrwr.h" 19 20 #include "fbtusr.h" 21 22 // Dispatch routine for CreateHandle 23 NTSTATUS NTAPI FreeBT_DispatchCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 24 { 25 //ULONG i; 26 NTSTATUS ntStatus; 27 PFILE_OBJECT fileObject; 28 PDEVICE_EXTENSION deviceExtension; 29 PIO_STACK_LOCATION irpStack; 30 //PFREEBT_PIPE_CONTEXT pipeContext; 31 PUSBD_INTERFACE_INFORMATION interface; 32 33 PAGED_CODE(); 34 35 FreeBT_DbgPrint(3, ("FreeBT_DispatchCreate: Entered\n")); 36 37 irpStack = IoGetCurrentIrpStackLocation(Irp); 38 fileObject = irpStack->FileObject; 39 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 40 41 if (deviceExtension->DeviceState != Working) 42 { 43 ntStatus = STATUS_INVALID_DEVICE_STATE; 44 goto FreeBT_DispatchCreate_Exit; 45 46 } 47 48 if (deviceExtension->UsbInterface) 49 { 50 interface = deviceExtension->UsbInterface; 51 52 } 53 54 else 55 { 56 FreeBT_DbgPrint(1, ("UsbInterface not found\n")); 57 ntStatus = STATUS_INVALID_DEVICE_STATE; 58 goto FreeBT_DispatchCreate_Exit; 59 60 } 61 62 if (fileObject) 63 { 64 fileObject->FsContext = NULL; 65 } 66 67 else 68 { 69 ntStatus = STATUS_INVALID_PARAMETER; 70 goto FreeBT_DispatchCreate_Exit; 71 72 } 73 74 if (deviceExtension->OpenHandleCount>0) 75 { 76 ntStatus = STATUS_ACCESS_VIOLATION; 77 goto FreeBT_DispatchCreate_Exit; 78 79 } 80 81 // opening a device as opposed to pipe. 82 ntStatus = STATUS_SUCCESS; 83 84 InterlockedIncrement(&deviceExtension->OpenHandleCount); 85 86 // the device is idle if it has no open handles or pending PnP Irps 87 // since we just received an open handle request, cancel idle req. 88 if (deviceExtension->SSEnable) 89 CancelSelectSuspend(deviceExtension); 90 91 FreeBT_DispatchCreate_Exit: 92 Irp->IoStatus.Status = ntStatus; 93 Irp->IoStatus.Information = 0; 94 IoCompleteRequest(Irp, IO_NO_INCREMENT); 95 96 FreeBT_DbgPrint(3, ("FreeBT_DispatchCreate: Leaving\n")); 97 return ntStatus; 98 99 } 100 101 // Dispatch routine for CloseHandle 102 NTSTATUS NTAPI FreeBT_DispatchClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 103 { 104 NTSTATUS ntStatus; 105 PFILE_OBJECT fileObject; 106 PDEVICE_EXTENSION deviceExtension; 107 PIO_STACK_LOCATION irpStack; 108 //PFREEBT_PIPE_CONTEXT pipeContext; 109 //PUSBD_PIPE_INFORMATION pipeInformation; 110 111 PAGED_CODE(); 112 113 irpStack = IoGetCurrentIrpStackLocation(Irp); 114 fileObject = irpStack->FileObject; 115 //pipeContext = NULL; 116 //pipeInformation = NULL; 117 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 118 119 FreeBT_DbgPrint(3, ("FreeBT_DispatchClose: Entered\n")); 120 121 ntStatus = STATUS_SUCCESS; 122 Irp->IoStatus.Status = ntStatus; 123 Irp->IoStatus.Information = 0; 124 IoCompleteRequest(Irp, IO_NO_INCREMENT); 125 126 InterlockedDecrement(&deviceExtension->OpenHandleCount); 127 128 FreeBT_DbgPrint(3, ("FreeBT_DispatchClose: Leaving\n")); 129 130 return ntStatus; 131 132 } 133 134 // Called when a HCI Send on the control pipe completes 135 NTSTATUS NTAPI FreeBT_HCISendCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) 136 { 137 //ULONG stageLength; 138 NTSTATUS ntStatus; 139 140 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_HCISendCompletion, status=0x%08X\n", Irp->IoStatus.Status)); 141 142 if (Irp->PendingReturned) 143 IoMarkIrpPending(Irp); 144 145 ExFreePool(Context); 146 FreeBT_IoDecrement(DeviceObject->DeviceExtension); 147 ntStatus = Irp->IoStatus.Status; 148 Irp->IoStatus.Information = 0; 149 150 return ntStatus; 151 152 } 153 154 // Called the DeviceIOControl handler to send an HCI command received from the user 155 // HCI Commands are sent on the (default) control pipe 156 NTSTATUS NTAPI FreeBT_SendHCICommand(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID IoBuffer, IN ULONG InputBufferLength) 157 { 158 PDEVICE_EXTENSION deviceExtension; 159 //ULONG urbFlags; 160 //ULONG stageLength; 161 //PVOID pBuffer; 162 PURB urb; 163 NTSTATUS ntStatus; 164 PIO_STACK_LOCATION nextStack; 165 //PFBT_HCI_CMD_HEADER pHCICommand; 166 //LARGE_INTEGER delay; 167 168 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 169 if (!deviceExtension) 170 { 171 ntStatus=STATUS_INVALID_PARAMETER; 172 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Failed to get DeviceExtension\n")); 173 Irp->IoStatus.Status = ntStatus; 174 Irp->IoStatus.Information = 0; 175 IoCompleteRequest(Irp, IO_NO_INCREMENT); 176 return ntStatus; 177 178 } 179 180 // The user is doing a reset, reset all the pipes as well, so that any 181 // old events or data are removed 182 /*pHCICommand=(PFBT_HCI_CMD_HEADER)IoBuffer; 183 if (pHCICommand->OpCode==FBT_HCI_CMD_RESET) 184 { 185 FreeBT_ResetPipe(DeviceObject, deviceExtension->EventPipe.PipeHandle); 186 FreeBT_ResetPipe(DeviceObject, deviceExtension->DataInPipe.PipeHandle); 187 FreeBT_ResetPipe(DeviceObject, deviceExtension->DataOutPipe.PipeHandle); 188 FreeBT_ResetPipe(DeviceObject, deviceExtension->AudioInPipe.PipeHandle); 189 FreeBT_ResetPipe(DeviceObject, deviceExtension->AudioOutPipe.PipeHandle); 190 191 // Wait a second for the device to recover 192 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Sleeping\n")); 193 delay.QuadPart = -10000 * 5000; // 5s 194 KeWaitForSingleObject(&deviceExtension->DelayEvent, 195 Executive, 196 UserMode, 197 FALSE, 198 &delay); 199 200 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Finished sleeping\n")); 201 202 203 }*/ 204 205 // Create the URB 206 urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); 207 if(urb == NULL) 208 { 209 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Failed to alloc mem for urb\n")); 210 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 211 Irp->IoStatus.Status = ntStatus; 212 Irp->IoStatus.Information = 0; 213 IoCompleteRequest(Irp, IO_NO_INCREMENT); 214 return ntStatus; 215 216 } 217 218 UsbBuildVendorRequest( 219 urb, 220 URB_FUNCTION_CLASS_DEVICE, // This works, for CSR and Silicon Wave 221 sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), 222 0, 223 0, 224 0, 225 0, 226 0, 227 IoBuffer, 228 NULL, 229 InputBufferLength, 230 NULL); 231 232 // use the original irp as an internal device control irp 233 nextStack = IoGetNextIrpStackLocation(Irp); 234 nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 235 nextStack->Parameters.Others.Argument1 = (PVOID) urb; 236 nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; 237 238 IoSetCompletionRoutine( 239 Irp, 240 (PIO_COMPLETION_ROUTINE)FreeBT_HCISendCompletion, 241 urb, 242 TRUE, 243 TRUE, 244 TRUE); 245 246 // We return STATUS_PENDING; call IoMarkIrpPending. 247 IoMarkIrpPending(Irp); 248 249 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand::")); 250 FreeBT_IoIncrement(deviceExtension); 251 252 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: Sending IRP %X to underlying driver\n", Irp)); 253 ntStatus=IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); 254 if(!NT_SUCCESS(ntStatus)) 255 { 256 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: IoCallDriver fails with status %X\n", ntStatus)); 257 258 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand::")); 259 FreeBT_IoDecrement(deviceExtension); 260 261 // If the device was surprise removed out, the pipeInformation field is invalid. 262 // similarly if the request was cancelled, then we need not reset the device. 263 if((ntStatus != STATUS_CANCELLED) && (ntStatus != STATUS_DEVICE_NOT_CONNECTED)) 264 ntStatus = FreeBT_ResetDevice(DeviceObject); 265 266 else 267 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n")); 268 269 Irp->IoStatus.Status = ntStatus; 270 Irp->IoStatus.Information = 0; 271 IoCompleteRequest(Irp, IO_NO_INCREMENT); 272 273 return ntStatus; 274 275 } 276 277 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: Completed successfully\n")); 278 279 return STATUS_PENDING; 280 281 } 282 283 // Called when a HCI Get on the event pipe completes 284 NTSTATUS NTAPI FreeBT_HCIEventCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) 285 { 286 //ULONG stageLength; 287 NTSTATUS ntStatus; 288 PIO_STACK_LOCATION nextStack; 289 PURB urb; 290 291 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_HCIEventCompletion, status=0x%08X\n", Irp->IoStatus.Status)); 292 293 if (Irp->PendingReturned) 294 IoMarkIrpPending(Irp); 295 296 // initialize variables 297 urb=(PURB)Context; 298 ntStatus = Irp->IoStatus.Status; 299 Irp->IoStatus.Information = urb->UrbBulkOrInterruptTransfer.TransferBufferLength; 300 nextStack = IoGetNextIrpStackLocation(Irp); 301 302 ExFreePool(Context); 303 FreeBT_IoDecrement(DeviceObject->DeviceExtension); 304 305 return ntStatus; 306 307 } 308 309 // Called from the DeviceIOControl handler to wait for an event on the interrupt pipe 310 NTSTATUS NTAPI FreeBT_GetHCIEvent(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID IoBuffer, IN ULONG InputBufferLength) 311 { 312 PDEVICE_EXTENSION deviceExtension; 313 PURB urb; 314 NTSTATUS ntStatus; 315 PIO_STACK_LOCATION nextStack; 316 317 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: Entered\n")); 318 319 urb = NULL; 320 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 321 322 urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER)); 323 if (urb==NULL) 324 { 325 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_GetHCIEvent: Failed to alloc mem for urb\n")); 326 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 327 goto FreeBT_GetHCIEvent_Exit; 328 329 } 330 331 UsbBuildInterruptOrBulkTransferRequest( 332 urb, 333 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), 334 deviceExtension->EventPipe.PipeHandle, 335 IoBuffer, 336 NULL, 337 InputBufferLength, 338 USBD_SHORT_TRANSFER_OK|USBD_TRANSFER_DIRECTION_IN, 339 NULL); 340 341 // use the original irp as an internal device control irp, which we send down to the 342 // USB class driver in order to get our request out on the wire 343 nextStack = IoGetNextIrpStackLocation(Irp); 344 nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 345 nextStack->Parameters.Others.Argument1 = (PVOID) urb; 346 nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; 347 348 IoSetCompletionRoutine( 349 Irp, 350 (PIO_COMPLETION_ROUTINE)FreeBT_HCIEventCompletion, 351 urb, 352 TRUE, 353 TRUE, 354 TRUE); 355 356 // We return STATUS_PENDING; call IoMarkIrpPending. 357 IoMarkIrpPending(Irp); 358 359 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent::")); 360 FreeBT_IoIncrement(deviceExtension); 361 362 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); 363 if (!NT_SUCCESS(ntStatus)) 364 { 365 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: IoCallDriver fails with status %X\n", ntStatus)); 366 367 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent::")); 368 FreeBT_IoDecrement(deviceExtension); 369 370 // If the device was surprise removed out, the pipeInformation field is invalid. 371 // similarly if the request was cancelled, then we need not reset the pipe. 372 if((ntStatus != STATUS_CANCELLED) && (ntStatus != STATUS_DEVICE_NOT_CONNECTED)) 373 { 374 ntStatus = FreeBT_ResetPipe(DeviceObject, deviceExtension->EventPipe.PipeHandle); 375 if(!NT_SUCCESS(ntStatus)) 376 { 377 FreeBT_DbgPrint(1, ("FreeBT_ResetPipe failed\n")); 378 ntStatus = FreeBT_ResetDevice(DeviceObject); 379 380 } 381 382 } 383 384 else 385 { 386 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n")); 387 388 } 389 390 goto FreeBT_GetHCIEvent_Exit; 391 392 } 393 394 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: Leaving\n")); 395 396 // Return STATUS_PENDING, when the lower driver completes the request, 397 // the FreeBT_HCIEventCompletion completion routine. 398 return STATUS_PENDING; 399 400 FreeBT_GetHCIEvent_Exit: 401 Irp->IoStatus.Status=ntStatus; 402 Irp->IoStatus.Information=0; 403 404 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: Failure (0x%08x), completing IRP\n", ntStatus)); 405 IoCompleteRequest(Irp, IO_NO_INCREMENT); 406 407 return ntStatus; 408 409 } 410 411 // DeviceIOControl dispatch 412 NTSTATUS NTAPI FreeBT_DispatchDevCtrl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 413 { 414 ULONG code; 415 PVOID ioBuffer; 416 ULONG inputBufferLength; 417 ULONG outputBufferLength; 418 ULONG info; 419 NTSTATUS ntStatus; 420 PDEVICE_EXTENSION deviceExtension; 421 PIO_STACK_LOCATION irpStack; 422 423 info = 0; 424 irpStack = IoGetCurrentIrpStackLocation(Irp); 425 code = irpStack->Parameters.DeviceIoControl.IoControlCode; 426 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 427 428 ioBuffer = Irp->AssociatedIrp.SystemBuffer; 429 inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength; 430 outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; 431 432 if (deviceExtension->DeviceState != Working) 433 { 434 FreeBT_DbgPrint(1, ("FBTUSB: Invalid device state\n")); 435 ntStatus = STATUS_INVALID_DEVICE_STATE; 436 goto FreeBT_DispatchDevCtrlExit; 437 438 } 439 440 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchDevCtrl::")); 441 442 // Make sure that any selective suspend request has been completed. 443 if (deviceExtension->SSEnable) 444 { 445 FreeBT_DbgPrint(3, ("Waiting on the IdleReqPendEvent\n")); 446 KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, 447 Executive, 448 KernelMode, 449 FALSE, 450 NULL); 451 452 } 453 454 switch(code) 455 { 456 case IOCTL_FREEBT_HCI_SEND_CMD: 457 FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_SEND_CMD received\n")); 458 if (inputBufferLength<FBT_HCI_CMD_MIN_SIZE) 459 { 460 ntStatus = STATUS_BUFFER_TOO_SMALL; 461 FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_SEND_CMD: Buffer too small\n")); 462 goto FreeBT_DispatchDevCtrlExit; 463 464 } 465 466 if (inputBufferLength>FBT_HCI_CMD_MAX_SIZE) 467 { 468 ntStatus = STATUS_INVALID_BUFFER_SIZE; 469 FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_SEND_CMD: Buffer too long\n")); 470 goto FreeBT_DispatchDevCtrlExit; 471 472 } 473 474 return FreeBT_SendHCICommand(DeviceObject, Irp, ioBuffer, inputBufferLength); 475 break; 476 477 case IOCTL_FREEBT_HCI_GET_EVENT: 478 FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_GET_EVENT received\n")); 479 if (outputBufferLength<FBT_HCI_EVENT_MAX_SIZE) 480 { 481 ntStatus = STATUS_BUFFER_TOO_SMALL; 482 FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_GET_EVENT: Buffer too small\n")); 483 goto FreeBT_DispatchDevCtrlExit; 484 485 } 486 487 return FreeBT_GetHCIEvent(DeviceObject, Irp, ioBuffer, outputBufferLength); 488 break; 489 490 default: 491 FreeBT_DbgPrint(3, ("FBTUSB: Invalid IOCTL 0x%08x received\n", code)); 492 ntStatus = STATUS_INVALID_DEVICE_REQUEST; 493 break; 494 495 } 496 497 FreeBT_DispatchDevCtrlExit: 498 Irp->IoStatus.Information = 0; 499 Irp->IoStatus.Status = ntStatus; 500 IoCompleteRequest(Irp, IO_NO_INCREMENT); 501 502 return ntStatus; 503 } 504 505 // Submit URB_FUNCTION_RESET_PIPE 506 NTSTATUS NTAPI FreeBT_ResetPipe(IN PDEVICE_OBJECT DeviceObject, IN USBD_PIPE_HANDLE PipeHandle) 507 { 508 PURB urb; 509 NTSTATUS ntStatus; 510 PDEVICE_EXTENSION deviceExtension; 511 512 urb = NULL; 513 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 514 515 urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST)); 516 if (urb) 517 { 518 urb->UrbHeader.Length = (USHORT) sizeof(struct _URB_PIPE_REQUEST); 519 urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE; 520 urb->UrbPipeRequest.PipeHandle = PipeHandle; 521 522 ntStatus = CallUSBD(DeviceObject, urb); 523 524 ExFreePool(urb); 525 526 } 527 528 else 529 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 530 531 if(NT_SUCCESS(ntStatus)) 532 { 533 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ResetPipe - success\n")); 534 ntStatus = STATUS_SUCCESS; 535 536 } 537 538 else 539 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ResetPipe - failed\n")); 540 541 return ntStatus; 542 543 } 544 545 // Call FreeBT_ResetParentPort to reset the device 546 NTSTATUS NTAPI FreeBT_ResetDevice(IN PDEVICE_OBJECT DeviceObject) 547 { 548 NTSTATUS ntStatus; 549 ULONG portStatus; 550 551 FreeBT_DbgPrint(3, ("FreeBT_ResetDevice: Entered\n")); 552 553 ntStatus = FreeBT_GetPortStatus(DeviceObject, &portStatus); 554 555 if ( (NT_SUCCESS(ntStatus)) && (!(portStatus & USBD_PORT_ENABLED)) && (portStatus & USBD_PORT_CONNECTED)) 556 ntStatus=FreeBT_ResetParentPort(DeviceObject); 557 558 FreeBT_DbgPrint(3, ("FreeBT_ResetDevice: Leaving\n")); 559 560 return ntStatus; 561 562 } 563 564 // Read port status from the lower driver (USB class driver) 565 NTSTATUS NTAPI FreeBT_GetPortStatus(IN PDEVICE_OBJECT DeviceObject, IN OUT PULONG PortStatus) 566 { 567 NTSTATUS ntStatus; 568 KEVENT event; 569 PIRP irp; 570 IO_STATUS_BLOCK ioStatus; 571 PIO_STACK_LOCATION nextStack; 572 PDEVICE_EXTENSION deviceExtension; 573 574 FreeBT_DbgPrint(3, ("FreeBT_GetPortStatus: Entered\n")); 575 576 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 577 *PortStatus = 0; 578 579 KeInitializeEvent(&event, NotificationEvent, FALSE); 580 irp = IoBuildDeviceIoControlRequest( 581 IOCTL_INTERNAL_USB_GET_PORT_STATUS, 582 deviceExtension->TopOfStackDeviceObject, 583 NULL, 584 0, 585 NULL, 586 0, 587 TRUE, 588 &event, 589 &ioStatus); 590 591 if (NULL == irp) 592 { 593 FreeBT_DbgPrint(1, ("memory alloc for irp failed\n")); 594 return STATUS_INSUFFICIENT_RESOURCES; 595 596 } 597 598 nextStack = IoGetNextIrpStackLocation(irp); 599 ASSERT(nextStack != NULL); 600 nextStack->Parameters.Others.Argument1 = PortStatus; 601 602 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp); 603 if (STATUS_PENDING==ntStatus) 604 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 605 606 else 607 ioStatus.Status = ntStatus; 608 609 ntStatus = ioStatus.Status; 610 FreeBT_DbgPrint(3, ("FreeBT_GetPortStatus: Leaving\n")); 611 612 return ntStatus; 613 614 } 615 616 // Sends an IOCTL_INTERNAL_USB_RESET_PORT via the lower driver 617 NTSTATUS NTAPI FreeBT_ResetParentPort(IN PDEVICE_OBJECT DeviceObject) 618 { 619 NTSTATUS ntStatus; 620 KEVENT event; 621 PIRP irp; 622 IO_STATUS_BLOCK ioStatus; 623 PIO_STACK_LOCATION nextStack; 624 PDEVICE_EXTENSION deviceExtension; 625 626 FreeBT_DbgPrint(3, ("FreeBT_ResetParentPort: Entered\n")); 627 628 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 629 630 KeInitializeEvent(&event, NotificationEvent, FALSE); 631 irp = IoBuildDeviceIoControlRequest( 632 IOCTL_INTERNAL_USB_RESET_PORT, 633 deviceExtension->TopOfStackDeviceObject, 634 NULL, 635 0, 636 NULL, 637 0, 638 TRUE, 639 &event, 640 &ioStatus); 641 642 if (NULL == irp) 643 { 644 FreeBT_DbgPrint(1, ("memory alloc for irp failed\n")); 645 return STATUS_INSUFFICIENT_RESOURCES; 646 647 } 648 649 nextStack = IoGetNextIrpStackLocation(irp); 650 ASSERT(nextStack != NULL); 651 652 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp); 653 if(STATUS_PENDING == ntStatus) 654 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 655 656 else 657 ioStatus.Status = ntStatus; 658 659 660 ntStatus = ioStatus.Status; 661 662 FreeBT_DbgPrint(3, ("FreeBT_ResetParentPort: Leaving\n")); 663 664 return ntStatus; 665 666 } 667 668 // Send an idle request to the lower driver 669 NTSTATUS NTAPI SubmitIdleRequestIrp(IN PDEVICE_EXTENSION DeviceExtension) 670 { 671 PIRP irp; 672 NTSTATUS ntStatus; 673 KIRQL oldIrql; 674 PUSB_IDLE_CALLBACK_INFO idleCallbackInfo; 675 PIO_STACK_LOCATION nextStack; 676 677 FreeBT_DbgPrint(3, ("SubmitIdleRequest: Entered\n")); 678 679 irp = NULL; 680 idleCallbackInfo = NULL; 681 682 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 683 684 if(PowerDeviceD0 != DeviceExtension->DevPower) { 685 686 ntStatus = STATUS_POWER_STATE_INVALID; 687 688 goto SubmitIdleRequestIrp_Exit; 689 } 690 691 KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql); 692 693 if(InterlockedExchange(&DeviceExtension->IdleReqPend, 1)) { 694 695 FreeBT_DbgPrint(1, ("Idle request pending..\n")); 696 697 KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql); 698 699 ntStatus = STATUS_DEVICE_BUSY; 700 701 goto SubmitIdleRequestIrp_Exit; 702 } 703 704 // 705 // clear the NoIdleReqPendEvent because we are about 706 // to submit an idle request. Since we are so early 707 // to clear this event, make sure that if we fail this 708 // request we set back the event. 709 // 710 KeClearEvent(&DeviceExtension->NoIdleReqPendEvent); 711 712 idleCallbackInfo = (PUSB_IDLE_CALLBACK_INFO)ExAllocatePool(NonPagedPool, sizeof(struct _USB_IDLE_CALLBACK_INFO)); 713 714 if(idleCallbackInfo) { 715 716 idleCallbackInfo->IdleCallback = (USB_IDLE_CALLBACK)IdleNotificationCallback; 717 718 idleCallbackInfo->IdleContext = (PVOID)DeviceExtension; 719 720 ASSERT(DeviceExtension->IdleCallbackInfo == NULL); 721 722 DeviceExtension->IdleCallbackInfo = idleCallbackInfo; 723 724 // 725 // we use IoAllocateIrp to create an irp to selectively suspend the 726 // device. This irp lies pending with the hub driver. When appropriate 727 // the hub driver will invoked callback, where we power down. The completion 728 // routine is invoked when we power back. 729 // 730 irp = IoAllocateIrp(DeviceExtension->TopOfStackDeviceObject->StackSize, 731 FALSE); 732 733 if(irp == NULL) { 734 735 FreeBT_DbgPrint(1, ("cannot build idle request irp\n")); 736 737 KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, 738 IO_NO_INCREMENT, 739 FALSE); 740 741 InterlockedExchange(&DeviceExtension->IdleReqPend, 0); 742 743 KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql); 744 745 ExFreePool(idleCallbackInfo); 746 747 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 748 749 goto SubmitIdleRequestIrp_Exit; 750 } 751 752 nextStack = IoGetNextIrpStackLocation(irp); 753 754 nextStack->MajorFunction = 755 IRP_MJ_INTERNAL_DEVICE_CONTROL; 756 757 nextStack->Parameters.DeviceIoControl.IoControlCode = 758 IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION; 759 760 nextStack->Parameters.DeviceIoControl.Type3InputBuffer = 761 idleCallbackInfo; 762 763 nextStack->Parameters.DeviceIoControl.InputBufferLength = 764 sizeof(struct _USB_IDLE_CALLBACK_INFO); 765 766 767 IoSetCompletionRoutine(irp, 768 (PIO_COMPLETION_ROUTINE)IdleNotificationRequestComplete, 769 DeviceExtension, 770 TRUE, 771 TRUE, 772 TRUE); 773 774 DeviceExtension->PendingIdleIrp = irp; 775 776 // 777 // we initialize the count to 2. 778 // The reason is, if the CancelSelectSuspend routine manages 779 // to grab the irp from the device extension, then the last of the 780 // CancelSelectSuspend routine/IdleNotificationRequestComplete routine 781 // to execute will free this irp. We need to have this schema so that 782 // 1. completion routine does not attempt to touch the irp freed by 783 // CancelSelectSuspend routine. 784 // 2. CancelSelectSuspend routine doesnt wait for ever for the completion 785 // routine to complete! 786 // 787 DeviceExtension->FreeIdleIrpCount = 2; 788 789 KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql); 790 791 // 792 // check if the device is idle. 793 // A check here ensures that a race condition did not 794 // completely reverse the call sequence of SubmitIdleRequestIrp 795 // and CancelSelectiveSuspend 796 // 797 798 if(!CanDeviceSuspend(DeviceExtension) || 799 PowerDeviceD0 != DeviceExtension->DevPower) { 800 801 // 802 // IRPs created using IoBuildDeviceIoControlRequest should be 803 // completed by calling IoCompleteRequest and not merely 804 // deallocated. 805 // 806 807 FreeBT_DbgPrint(1, ("Device is not idle\n")); 808 809 KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql); 810 811 DeviceExtension->IdleCallbackInfo = NULL; 812 813 DeviceExtension->PendingIdleIrp = NULL; 814 815 KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, 816 IO_NO_INCREMENT, 817 FALSE); 818 819 InterlockedExchange(&DeviceExtension->IdleReqPend, 0); 820 821 KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql); 822 823 if(idleCallbackInfo) { 824 825 ExFreePool(idleCallbackInfo); 826 } 827 828 // 829 // it is still safe to touch the local variable "irp" here. 830 // the irp has not been passed down the stack, the irp has 831 // no cancellation routine. The worse position is that the 832 // CancelSelectSuspend has run after we released the spin 833 // lock above. It is still essential to free the irp. 834 // 835 if(irp) { 836 837 IoFreeIrp(irp); 838 } 839 840 ntStatus = STATUS_UNSUCCESSFUL; 841 842 goto SubmitIdleRequestIrp_Exit; 843 } 844 845 FreeBT_DbgPrint(3, ("Cancel the timers\n")); 846 // 847 // Cancel the timer so that the DPCs are no longer fired. 848 // Thus, we are making judicious usage of our resources. 849 // we do not need DPCs because we already have an idle irp pending. 850 // The timers are re-initialized in the completion routine. 851 // 852 KeCancelTimer(&DeviceExtension->Timer); 853 854 ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp); 855 856 if(!NT_SUCCESS(ntStatus)) { 857 858 FreeBT_DbgPrint(1, ("IoCallDriver failed\n")); 859 860 goto SubmitIdleRequestIrp_Exit; 861 } 862 } 863 else { 864 865 FreeBT_DbgPrint(1, ("Memory allocation for idleCallbackInfo failed\n")); 866 867 KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, 868 IO_NO_INCREMENT, 869 FALSE); 870 871 InterlockedExchange(&DeviceExtension->IdleReqPend, 0); 872 873 KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql); 874 875 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 876 } 877 878 SubmitIdleRequestIrp_Exit: 879 880 FreeBT_DbgPrint(3, ("SubmitIdleRequest: Leaving\n")); 881 882 return ntStatus; 883 } 884 885 886 VOID NTAPI IdleNotificationCallback(IN PDEVICE_EXTENSION DeviceExtension) 887 { 888 NTSTATUS ntStatus; 889 POWER_STATE powerState; 890 KEVENT irpCompletionEvent; 891 PIRP_COMPLETION_CONTEXT irpContext; 892 893 FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback: Entered\n")); 894 895 // 896 // Dont idle, if the device was just disconnected or being stopped 897 // i.e. return for the following DeviceState(s) 898 // NotStarted, Stopped, PendingStop, PendingRemove, SurpriseRemoved, Removed 899 // 900 901 if(DeviceExtension->DeviceState != Working) { 902 903 return; 904 } 905 906 // 907 // If there is not already a WW IRP pending, submit one now 908 // 909 if(DeviceExtension->WaitWakeEnable) { 910 911 IssueWaitWake(DeviceExtension); 912 } 913 914 915 // 916 // power down the device 917 // 918 919 irpContext = (PIRP_COMPLETION_CONTEXT) 920 ExAllocatePool(NonPagedPool, 921 sizeof(IRP_COMPLETION_CONTEXT)); 922 923 if(!irpContext) { 924 925 FreeBT_DbgPrint(1, ("FBTUSB: IdleNotificationCallback: Failed to alloc memory for irpContext\n")); 926 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 927 } 928 else { 929 930 // 931 // increment the count. In the HoldIoRequestWorkerRoutine, the 932 // count is decremented twice (one for the system Irp and the 933 // other for the device Irp. An increment here compensates for 934 // the sytem irp..The decrement corresponding to this increment 935 // is in the completion function 936 // 937 938 FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback::")); 939 FreeBT_IoIncrement(DeviceExtension); 940 941 powerState.DeviceState = (DEVICE_POWER_STATE) DeviceExtension->PowerDownLevel; 942 943 KeInitializeEvent(&irpCompletionEvent, NotificationEvent, FALSE); 944 945 irpContext->DeviceExtension = DeviceExtension; 946 irpContext->Event = &irpCompletionEvent; 947 948 ntStatus = PoRequestPowerIrp( 949 DeviceExtension->PhysicalDeviceObject, 950 IRP_MN_SET_POWER, 951 powerState, 952 (PREQUEST_POWER_COMPLETE) PoIrpCompletionFunc, 953 irpContext, 954 NULL); 955 956 if(STATUS_PENDING == ntStatus) { 957 958 FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback::" 959 "waiting for the power irp to complete\n")); 960 961 KeWaitForSingleObject(&irpCompletionEvent, 962 Executive, 963 KernelMode, 964 FALSE, 965 NULL); 966 } 967 } 968 969 if(!NT_SUCCESS(ntStatus)) { 970 971 if(irpContext) { 972 973 ExFreePool(irpContext); 974 } 975 } 976 977 FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback: Leaving\n")); 978 } 979 980 981 NTSTATUS NTAPI IdleNotificationRequestComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension) 982 { 983 NTSTATUS ntStatus; 984 POWER_STATE powerState; 985 KIRQL oldIrql; 986 LARGE_INTEGER dueTime; 987 PIRP idleIrp; 988 PUSB_IDLE_CALLBACK_INFO idleCallbackInfo; 989 990 FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationRequestCompete: Entered\n")); 991 992 idleIrp = NULL; 993 994 ntStatus = Irp->IoStatus.Status; 995 if(!NT_SUCCESS(ntStatus) && ntStatus != STATUS_NOT_SUPPORTED) 996 { 997 FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationRequestCompete: Idle irp completes with error::")); 998 switch(ntStatus) 999 { 1000 case STATUS_INVALID_DEVICE_REQUEST: 1001 FreeBT_DbgPrint(3, ("STATUS_INVALID_DEVICE_REQUEST\n")); 1002 break; 1003 1004 case STATUS_CANCELLED: 1005 FreeBT_DbgPrint(3, ("STATUS_CANCELLED\n")); 1006 break; 1007 1008 case STATUS_DEVICE_BUSY: 1009 FreeBT_DbgPrint(3, ("STATUS_DEVICE_BUSY\n")); 1010 break; 1011 1012 case STATUS_POWER_STATE_INVALID: 1013 FreeBT_DbgPrint(3, ("STATUS_POWER_STATE_INVALID\n")); 1014 goto IdleNotificationRequestComplete_Exit; 1015 1016 default: 1017 FreeBT_DbgPrint(3, ("default: status = %X\n", ntStatus)); 1018 break; 1019 1020 } 1021 1022 // if in error, issue a SetD0 1023 FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationRequestComplete::")); 1024 FreeBT_IoIncrement(DeviceExtension); 1025 1026 powerState.DeviceState = PowerDeviceD0; 1027 ntStatus = PoRequestPowerIrp( 1028 DeviceExtension->PhysicalDeviceObject, 1029 IRP_MN_SET_POWER, 1030 powerState, 1031 (PREQUEST_POWER_COMPLETE) PoIrpAsyncCompletionFunc, 1032 DeviceExtension, 1033 NULL); 1034 1035 if(!NT_SUCCESS(ntStatus)) 1036 FreeBT_DbgPrint(1, ("PoRequestPowerIrp failed\n")); 1037 1038 } 1039 1040 IdleNotificationRequestComplete_Exit: 1041 KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql); 1042 idleCallbackInfo = DeviceExtension->IdleCallbackInfo; 1043 DeviceExtension->IdleCallbackInfo = NULL; 1044 1045 idleIrp = (PIRP) InterlockedExchangePointer((PVOID*)&DeviceExtension->PendingIdleIrp, NULL); 1046 InterlockedExchange(&DeviceExtension->IdleReqPend, 0); 1047 1048 KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql); 1049 1050 if(idleCallbackInfo) 1051 ExFreePool(idleCallbackInfo); 1052 1053 // Since the irp was created using IoAllocateIrp, 1054 // the Irp needs to be freed using IoFreeIrp. 1055 // Also return STATUS_MORE_PROCESSING_REQUIRED so that 1056 // the kernel does not reference this in the near future. 1057 if(idleIrp) 1058 { 1059 FreeBT_DbgPrint(3, ("completion routine has a valid irp and frees it\n")); 1060 IoFreeIrp(Irp); 1061 KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE); 1062 1063 } 1064 1065 else 1066 { 1067 // The CancelSelectiveSuspend routine has grabbed the Irp from the device 1068 // extension. Now the last one to decrement the FreeIdleIrpCount should 1069 // free the irp. 1070 if (0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount)) 1071 { 1072 FreeBT_DbgPrint(3, ("completion routine frees the irp\n")); 1073 IoFreeIrp(Irp); 1074 KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE); 1075 1076 } 1077 1078 } 1079 1080 if(DeviceExtension->SSEnable) 1081 { 1082 FreeBT_DbgPrint(3, ("Set the timer to fire DPCs\n")); 1083 dueTime.QuadPart = -10000 * IDLE_INTERVAL; // 5000 ms 1084 KeSetTimerEx(&DeviceExtension->Timer, dueTime, IDLE_INTERVAL, &DeviceExtension->DeferredProcCall); 1085 FreeBT_DbgPrint(3, ("IdleNotificationRequestCompete: Leaving\n")); 1086 1087 } 1088 1089 return STATUS_MORE_PROCESSING_REQUIRED; 1090 1091 } 1092 1093 VOID NTAPI CancelSelectSuspend(IN PDEVICE_EXTENSION DeviceExtension) 1094 { 1095 PIRP irp; 1096 KIRQL oldIrql; 1097 1098 FreeBT_DbgPrint(3, ("CancelSelectSuspend: Entered\n")); 1099 1100 irp = NULL; 1101 1102 KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql); 1103 1104 if(!CanDeviceSuspend(DeviceExtension)) 1105 { 1106 FreeBT_DbgPrint(3, ("Device is not idle\n")); 1107 irp = (PIRP) InterlockedExchangePointer((PVOID*)&DeviceExtension->PendingIdleIrp, NULL); 1108 1109 } 1110 1111 KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql); 1112 1113 // since we have a valid Irp ptr, 1114 // we can call IoCancelIrp on it, 1115 // without the fear of the irp 1116 // being freed underneath us. 1117 if(irp) 1118 { 1119 // This routine has the irp pointer. 1120 // It is safe to call IoCancelIrp because we know that 1121 // the compleiton routine will not free this irp unless... 1122 // 1123 // 1124 if(IoCancelIrp(irp)) 1125 { 1126 FreeBT_DbgPrint(3, ("IoCancelIrp returns TRUE\n")); 1127 1128 } 1129 1130 else 1131 { 1132 FreeBT_DbgPrint(3, ("IoCancelIrp returns FALSE\n")); 1133 1134 } 1135 1136 // ....we decrement the FreeIdleIrpCount from 2 to 1. 1137 // if completion routine runs ahead of us, then this routine 1138 // decrements the FreeIdleIrpCount from 1 to 0 and hence shall 1139 // free the irp. 1140 if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount)) 1141 { 1142 FreeBT_DbgPrint(3, ("CancelSelectSuspend frees the irp\n")); 1143 IoFreeIrp(irp); 1144 KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE); 1145 1146 } 1147 1148 } 1149 1150 FreeBT_DbgPrint(3, ("CancelSelectSuspend: Leaving\n")); 1151 1152 return; 1153 1154 } 1155 1156 VOID NTAPI PoIrpCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus) 1157 { 1158 PIRP_COMPLETION_CONTEXT irpContext; 1159 irpContext = NULL; 1160 1161 FreeBT_DbgPrint(3, ("PoIrpCompletionFunc::")); 1162 1163 if(Context) 1164 irpContext = (PIRP_COMPLETION_CONTEXT) Context; 1165 1166 // all we do is set the event and decrement the count 1167 if(irpContext) 1168 { 1169 KeSetEvent(irpContext->Event, 0, FALSE); 1170 FreeBT_IoDecrement(irpContext->DeviceExtension); 1171 ExFreePool(irpContext); 1172 1173 } 1174 1175 return; 1176 1177 } 1178 1179 VOID NTAPI PoIrpAsyncCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus) 1180 { 1181 PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Context; 1182 FreeBT_DbgPrint(3, ("PoIrpAsyncCompletionFunc::")); 1183 FreeBT_IoDecrement(DeviceExtension); 1184 1185 return; 1186 1187 } 1188 1189 VOID NTAPI WWIrpCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus) 1190 { 1191 PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Context; 1192 1193 FreeBT_DbgPrint(3, ("WWIrpCompletionFunc::")); 1194 FreeBT_IoDecrement(DeviceExtension); 1195 1196 return; 1197 1198 } 1199