Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1455 lines
36 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. bulkdev.c
  5. Abstract:
  6. This file contains dispatch routines for create,
  7. close and selective suspend.
  8. The selective suspend feature is enabled if
  9. the SSRegistryEnable key in the registry is set to 1.
  10. Environment:
  11. Kernel mode
  12. Notes:
  13. Copyright (c) 2000 Microsoft Corporation.
  14. All Rights Reserved.
  15. --*/
  16. #include "bulkusb.h"
  17. #include "bulkpnp.h"
  18. #include "bulkpwr.h"
  19. #include "bulkdev.h"
  20. #include "bulkusr.h"
  21. #include "bulkwmi.h"
  22. #include "bulkrwr.h"
  23. NTSTATUS
  24. BulkUsb_DispatchCreate(
  25. IN PDEVICE_OBJECT DeviceObject,
  26. IN PIRP Irp
  27. )
  28. /*++
  29. Routine Description:
  30. Dispatch routine for create.
  31. Arguments:
  32. DeviceObject - pointer to device object
  33. Irp - I/O request packet.
  34. Return Value:
  35. NT status value
  36. --*/
  37. {
  38. ULONG i;
  39. NTSTATUS ntStatus;
  40. PFILE_OBJECT fileObject;
  41. PDEVICE_EXTENSION deviceExtension;
  42. PIO_STACK_LOCATION irpStack;
  43. PBULKUSB_PIPE_CONTEXT pipeContext;
  44. PUSBD_INTERFACE_INFORMATION interface;
  45. PAGED_CODE();
  46. BulkUsb_DbgPrint(3, ("BulkUsb_DispatchCreate - begins\n"));
  47. //
  48. // initialize variables
  49. //
  50. irpStack = IoGetCurrentIrpStackLocation(Irp);
  51. fileObject = irpStack->FileObject;
  52. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  53. if(deviceExtension->DeviceState != Working) {
  54. ntStatus = STATUS_INVALID_DEVICE_STATE;
  55. goto BulkUsb_DispatchCreate_Exit;
  56. }
  57. if(deviceExtension->UsbInterface) {
  58. interface = deviceExtension->UsbInterface;
  59. }
  60. else {
  61. BulkUsb_DbgPrint(1, ("UsbInterface not found\n"));
  62. ntStatus = STATUS_INVALID_DEVICE_STATE;
  63. goto BulkUsb_DispatchCreate_Exit;
  64. }
  65. //
  66. // FsContext is Null for the device
  67. //
  68. if(fileObject) {
  69. fileObject->FsContext = NULL;
  70. }
  71. else {
  72. ntStatus = STATUS_INVALID_PARAMETER;
  73. goto BulkUsb_DispatchCreate_Exit;
  74. }
  75. if(0 == fileObject->FileName.Length) {
  76. //
  77. // opening a device as opposed to pipe.
  78. //
  79. ntStatus = STATUS_SUCCESS;
  80. InterlockedIncrement(&deviceExtension->OpenHandleCount);
  81. //
  82. // the device is idle if it has no open handles or pending PnP Irps
  83. // since we just received an open handle request, cancel idle req.
  84. //
  85. if(deviceExtension->SSEnable) {
  86. CancelSelectSuspend(deviceExtension);
  87. }
  88. goto BulkUsb_DispatchCreate_Exit;
  89. }
  90. pipeContext = BulkUsb_PipeWithName(DeviceObject, &fileObject->FileName);
  91. if(pipeContext == NULL) {
  92. ntStatus = STATUS_INVALID_PARAMETER;
  93. goto BulkUsb_DispatchCreate_Exit;
  94. }
  95. ntStatus = STATUS_INVALID_PARAMETER;
  96. for(i=0; i<interface->NumberOfPipes; i++) {
  97. if(pipeContext == &deviceExtension->PipeContext[i]) {
  98. //
  99. // found a match
  100. //
  101. BulkUsb_DbgPrint(3, ("open pipe %d\n", i));
  102. fileObject->FsContext = &interface->Pipes[i];
  103. ASSERT(fileObject->FsContext);
  104. pipeContext->PipeOpen = TRUE;
  105. ntStatus = STATUS_SUCCESS;
  106. //
  107. // increment OpenHandleCounts
  108. //
  109. InterlockedIncrement(&deviceExtension->OpenHandleCount);
  110. //
  111. // the device is idle if it has no open handles or pending PnP Irps
  112. // since we just received an open handle request, cancel idle req.
  113. //
  114. if(deviceExtension->SSEnable) {
  115. CancelSelectSuspend(deviceExtension);
  116. }
  117. }
  118. }
  119. BulkUsb_DispatchCreate_Exit:
  120. Irp->IoStatus.Status = ntStatus;
  121. Irp->IoStatus.Information = 0;
  122. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  123. BulkUsb_DbgPrint(3, ("BulkUsb_DispatchCreate - ends\n"));
  124. return ntStatus;
  125. }
  126. NTSTATUS
  127. BulkUsb_DispatchClose(
  128. IN PDEVICE_OBJECT DeviceObject,
  129. IN PIRP Irp
  130. )
  131. /*++
  132. Routine Description:
  133. Dispatch routine for close.
  134. Arguments:
  135. DeviceObject - pointer to device object
  136. Irp - I/O request packet
  137. Return Value:
  138. NT status value
  139. --*/
  140. {
  141. NTSTATUS ntStatus;
  142. PFILE_OBJECT fileObject;
  143. PDEVICE_EXTENSION deviceExtension;
  144. PIO_STACK_LOCATION irpStack;
  145. PBULKUSB_PIPE_CONTEXT pipeContext;
  146. PUSBD_PIPE_INFORMATION pipeInformation;
  147. PAGED_CODE();
  148. //
  149. // initialize variables
  150. //
  151. irpStack = IoGetCurrentIrpStackLocation(Irp);
  152. fileObject = irpStack->FileObject;
  153. pipeContext = NULL;
  154. pipeInformation = NULL;
  155. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  156. BulkUsb_DbgPrint(3, ("BulkUsb_DispatchClose - begins\n"));
  157. if(fileObject && fileObject->FsContext) {
  158. pipeInformation = fileObject->FsContext;
  159. if(0 != fileObject->FileName.Length) {
  160. pipeContext = BulkUsb_PipeWithName(DeviceObject,
  161. &fileObject->FileName);
  162. }
  163. if(pipeContext && pipeContext->PipeOpen) {
  164. pipeContext->PipeOpen = FALSE;
  165. }
  166. }
  167. //
  168. // set ntStatus to STATUS_SUCCESS
  169. //
  170. ntStatus = STATUS_SUCCESS;
  171. Irp->IoStatus.Status = ntStatus;
  172. Irp->IoStatus.Information = 0;
  173. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  174. InterlockedDecrement(&deviceExtension->OpenHandleCount);
  175. BulkUsb_DbgPrint(3, ("BulkUsb_DispatchClose - ends\n"));
  176. return ntStatus;
  177. }
  178. NTSTATUS
  179. BulkUsb_DispatchDevCtrl(
  180. IN PDEVICE_OBJECT DeviceObject,
  181. IN PIRP Irp
  182. )
  183. /*++
  184. Routine Description:
  185. Dispatch routine for IRP_MJ_DEVICE_CONTROL
  186. Arguments:
  187. DeviceObject - pointer to device object
  188. Irp - I/O request packet
  189. Return Value:
  190. NT status value
  191. --*/
  192. {
  193. ULONG code;
  194. PVOID ioBuffer;
  195. ULONG inputBufferLength;
  196. ULONG outputBufferLength;
  197. ULONG info;
  198. NTSTATUS ntStatus;
  199. PDEVICE_EXTENSION deviceExtension;
  200. PIO_STACK_LOCATION irpStack;
  201. //
  202. // initialize variables
  203. //
  204. info = 0;
  205. irpStack = IoGetCurrentIrpStackLocation(Irp);
  206. code = irpStack->Parameters.DeviceIoControl.IoControlCode;
  207. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  208. ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  209. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  210. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  211. if(deviceExtension->DeviceState != Working) {
  212. BulkUsb_DbgPrint(1, ("Invalid device state\n"));
  213. Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE;
  214. Irp->IoStatus.Information = info;
  215. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  216. return ntStatus;
  217. }
  218. BulkUsb_DbgPrint(3, ("BulkUsb_DispatchDevCtrl::"));
  219. BulkUsb_IoIncrement(deviceExtension);
  220. //
  221. // It is true that the client driver cancelled the selective suspend
  222. // request in the dispatch routine for create.
  223. // But there is no guarantee that it has indeed been completed.
  224. // so wait on the NoIdleReqPendEvent and proceed only if this event
  225. // is signalled.
  226. //
  227. BulkUsb_DbgPrint(3, ("Waiting on the IdleReqPendEvent\n"));
  228. //
  229. // make sure that the selective suspend request has been completed.
  230. //
  231. if(deviceExtension->SSEnable) {
  232. KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
  233. Executive,
  234. KernelMode,
  235. FALSE,
  236. NULL);
  237. }
  238. switch(code) {
  239. case IOCTL_BULKUSB_RESET_PIPE:
  240. {
  241. PFILE_OBJECT fileObject;
  242. PUSBD_PIPE_INFORMATION pipe;
  243. pipe = NULL;
  244. fileObject = NULL;
  245. //
  246. // FileObject is the address of the kernel file object to
  247. // which the IRP is directed. Drivers use the FileObject
  248. // to correlate IRPs in a queue.
  249. //
  250. fileObject = irpStack->FileObject;
  251. if(fileObject == NULL) {
  252. ntStatus = STATUS_INVALID_PARAMETER;
  253. break;
  254. }
  255. pipe = (PUSBD_PIPE_INFORMATION) fileObject->FsContext;
  256. if(pipe == NULL) {
  257. ntStatus = STATUS_INVALID_PARAMETER;
  258. }
  259. else {
  260. ntStatus = BulkUsb_ResetPipe(DeviceObject, pipe);
  261. }
  262. break;
  263. }
  264. case IOCTL_BULKUSB_GET_CONFIG_DESCRIPTOR:
  265. {
  266. ULONG length;
  267. if(deviceExtension->UsbConfigurationDescriptor) {
  268. length = deviceExtension->UsbConfigurationDescriptor->wTotalLength;
  269. if(outputBufferLength >= length) {
  270. RtlCopyMemory(ioBuffer,
  271. deviceExtension->UsbConfigurationDescriptor,
  272. length);
  273. info = length;
  274. ntStatus = STATUS_SUCCESS;
  275. }
  276. else {
  277. ntStatus = STATUS_BUFFER_TOO_SMALL;
  278. }
  279. }
  280. else {
  281. ntStatus = STATUS_UNSUCCESSFUL;
  282. }
  283. break;
  284. }
  285. case IOCTL_BULKUSB_RESET_DEVICE:
  286. ntStatus = BulkUsb_ResetDevice(DeviceObject);
  287. break;
  288. default :
  289. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  290. break;
  291. }
  292. Irp->IoStatus.Status = ntStatus;
  293. Irp->IoStatus.Information = info;
  294. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  295. BulkUsb_DbgPrint(3, ("BulkUsb_DispatchDevCtrl::"));
  296. BulkUsb_IoDecrement(deviceExtension);
  297. return ntStatus;
  298. }
  299. NTSTATUS
  300. BulkUsb_ResetPipe(
  301. IN PDEVICE_OBJECT DeviceObject,
  302. IN PUSBD_PIPE_INFORMATION PipeInfo
  303. )
  304. /*++
  305. Routine Description:
  306. This routine synchronously submits a URB_FUNCTION_RESET_PIPE
  307. request down the stack.
  308. Arguments:
  309. DeviceObject - pointer to device object
  310. PipeInfo - pointer to PipeInformation structure
  311. to retrieve the pipe handle
  312. Return Value:
  313. NT status value
  314. --*/
  315. {
  316. PURB urb;
  317. NTSTATUS ntStatus;
  318. PDEVICE_EXTENSION deviceExtension;
  319. //
  320. // initialize variables
  321. //
  322. urb = NULL;
  323. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  324. urb = ExAllocatePool(NonPagedPool,
  325. sizeof(struct _URB_PIPE_REQUEST));
  326. if(urb) {
  327. urb->UrbHeader.Length = (USHORT) sizeof(struct _URB_PIPE_REQUEST);
  328. urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
  329. urb->UrbPipeRequest.PipeHandle = PipeInfo->PipeHandle;
  330. ntStatus = CallUSBD(DeviceObject, urb);
  331. ExFreePool(urb);
  332. }
  333. else {
  334. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  335. }
  336. if(NT_SUCCESS(ntStatus)) {
  337. BulkUsb_DbgPrint(3, ("BulkUsb_ResetPipe - success\n"));
  338. ntStatus = STATUS_SUCCESS;
  339. }
  340. else {
  341. BulkUsb_DbgPrint(1, ("BulkUsb_ResetPipe - failed\n"));
  342. }
  343. return ntStatus;
  344. }
  345. NTSTATUS
  346. BulkUsb_ResetDevice(
  347. IN PDEVICE_OBJECT DeviceObject
  348. )
  349. /*++
  350. Routine Description:
  351. This routine invokes BulkUsb_ResetParentPort to reset the device
  352. Arguments:
  353. DeviceObject - pointer to device object
  354. Return Value:
  355. NT status value
  356. --*/
  357. {
  358. NTSTATUS ntStatus;
  359. ULONG portStatus;
  360. BulkUsb_DbgPrint(3, ("BulkUsb_ResetDevice - begins\n"));
  361. ntStatus = BulkUsb_GetPortStatus(DeviceObject, &portStatus);
  362. if((NT_SUCCESS(ntStatus)) &&
  363. (!(portStatus & USBD_PORT_ENABLED)) &&
  364. (portStatus & USBD_PORT_CONNECTED)) {
  365. ntStatus = BulkUsb_ResetParentPort(DeviceObject);
  366. }
  367. BulkUsb_DbgPrint(3, ("BulkUsb_ResetDevice - ends\n"));
  368. return ntStatus;
  369. }
  370. NTSTATUS
  371. BulkUsb_GetPortStatus(
  372. IN PDEVICE_OBJECT DeviceObject,
  373. IN OUT PULONG PortStatus
  374. )
  375. /*++
  376. Routine Description:
  377. This routine retrieves the status value
  378. Arguments:
  379. DeviceObject - pointer to device object
  380. PortStatus - port status
  381. Return Value:
  382. NT status value
  383. --*/
  384. {
  385. NTSTATUS ntStatus;
  386. KEVENT event;
  387. PIRP irp;
  388. IO_STATUS_BLOCK ioStatus;
  389. PIO_STACK_LOCATION nextStack;
  390. PDEVICE_EXTENSION deviceExtension;
  391. //
  392. // initialize variables
  393. //
  394. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  395. *PortStatus = 0;
  396. BulkUsb_DbgPrint(3, ("BulkUsb_GetPortStatus - begins\n"));
  397. KeInitializeEvent(&event, NotificationEvent, FALSE);
  398. irp = IoBuildDeviceIoControlRequest(
  399. IOCTL_INTERNAL_USB_GET_PORT_STATUS,
  400. deviceExtension->TopOfStackDeviceObject,
  401. NULL,
  402. 0,
  403. NULL,
  404. 0,
  405. TRUE,
  406. &event,
  407. &ioStatus);
  408. if(NULL == irp) {
  409. BulkUsb_DbgPrint(1, ("memory alloc for irp failed\n"));
  410. return STATUS_INSUFFICIENT_RESOURCES;
  411. }
  412. nextStack = IoGetNextIrpStackLocation(irp);
  413. ASSERT(nextStack != NULL);
  414. nextStack->Parameters.Others.Argument1 = PortStatus;
  415. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
  416. if(STATUS_PENDING == ntStatus) {
  417. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  418. }
  419. else {
  420. ioStatus.Status = ntStatus;
  421. }
  422. ntStatus = ioStatus.Status;
  423. BulkUsb_DbgPrint(3, ("BulkUsb_GetPortStatus - ends\n"));
  424. return ntStatus;
  425. }
  426. NTSTATUS
  427. BulkUsb_ResetParentPort(
  428. IN PDEVICE_OBJECT DeviceObject
  429. )
  430. /*++
  431. Routine Description:
  432. This routine sends an IOCTL_INTERNAL_USB_RESET_PORT
  433. synchronously down the stack.
  434. Arguments:
  435. Return Value:
  436. --*/
  437. {
  438. NTSTATUS ntStatus;
  439. KEVENT event;
  440. PIRP irp;
  441. IO_STATUS_BLOCK ioStatus;
  442. PIO_STACK_LOCATION nextStack;
  443. PDEVICE_EXTENSION deviceExtension;
  444. //
  445. // initialize variables
  446. //
  447. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  448. BulkUsb_DbgPrint(3, ("BulkUsb_ResetParentPort - begins\n"));
  449. KeInitializeEvent(&event, NotificationEvent, FALSE);
  450. irp = IoBuildDeviceIoControlRequest(
  451. IOCTL_INTERNAL_USB_RESET_PORT,
  452. deviceExtension->TopOfStackDeviceObject,
  453. NULL,
  454. 0,
  455. NULL,
  456. 0,
  457. TRUE,
  458. &event,
  459. &ioStatus);
  460. if(NULL == irp) {
  461. BulkUsb_DbgPrint(1, ("memory alloc for irp failed\n"));
  462. return STATUS_INSUFFICIENT_RESOURCES;
  463. }
  464. nextStack = IoGetNextIrpStackLocation(irp);
  465. ASSERT(nextStack != NULL);
  466. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
  467. if(STATUS_PENDING == ntStatus) {
  468. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  469. }
  470. else {
  471. ioStatus.Status = ntStatus;
  472. }
  473. ntStatus = ioStatus.Status;
  474. BulkUsb_DbgPrint(3, ("BulkUsb_ResetParentPort - ends\n"));
  475. return ntStatus;
  476. }
  477. NTSTATUS
  478. SubmitIdleRequestIrp(
  479. IN PDEVICE_EXTENSION DeviceExtension
  480. )
  481. /*++
  482. Routine Description:
  483. This routine builds an idle request irp with an associated callback routine
  484. and a completion routine in the driver and passes the irp down the stack.
  485. Arguments:
  486. DeviceExtension - pointer to device extension
  487. Return Value:
  488. NT status value
  489. --*/
  490. {
  491. PIRP irp;
  492. NTSTATUS ntStatus;
  493. KIRQL oldIrql;
  494. PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
  495. PIO_STACK_LOCATION nextStack;
  496. //
  497. // initialize variables
  498. //
  499. irp = NULL;
  500. idleCallbackInfo = NULL;
  501. BulkUsb_DbgPrint(3, ("SubmitIdleRequest - begins\n"));
  502. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  503. if(PowerDeviceD0 != DeviceExtension->DevPower) {
  504. ntStatus = STATUS_POWER_STATE_INVALID;
  505. goto SubmitIdleRequestIrp_Exit;
  506. }
  507. KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
  508. if(InterlockedExchange(&DeviceExtension->IdleReqPend, 1)) {
  509. BulkUsb_DbgPrint(1, ("Idle request pending..\n"));
  510. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  511. ntStatus = STATUS_DEVICE_BUSY;
  512. goto SubmitIdleRequestIrp_Exit;
  513. }
  514. //
  515. // clear the NoIdleReqPendEvent because we are about
  516. // to submit an idle request. Since we are so early
  517. // to clear this event, make sure that if we fail this
  518. // request we set back the event.
  519. //
  520. KeClearEvent(&DeviceExtension->NoIdleReqPendEvent);
  521. idleCallbackInfo = ExAllocatePool(NonPagedPool,
  522. sizeof(struct _USB_IDLE_CALLBACK_INFO));
  523. if(idleCallbackInfo) {
  524. idleCallbackInfo->IdleCallback = IdleNotificationCallback;
  525. idleCallbackInfo->IdleContext = (PVOID)DeviceExtension;
  526. ASSERT(DeviceExtension->IdleCallbackInfo == NULL);
  527. DeviceExtension->IdleCallbackInfo = idleCallbackInfo;
  528. //
  529. // we use IoAllocateIrp to create an irp to selectively suspend the
  530. // device. This irp lies pending with the hub driver. When appropriate
  531. // the hub driver will invoked callback, where we power down. The completion
  532. // routine is invoked when we power back.
  533. //
  534. irp = IoAllocateIrp(DeviceExtension->TopOfStackDeviceObject->StackSize,
  535. FALSE);
  536. if(irp == NULL) {
  537. BulkUsb_DbgPrint(1, ("cannot build idle request irp\n"));
  538. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  539. IO_NO_INCREMENT,
  540. FALSE);
  541. InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
  542. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  543. ExFreePool(idleCallbackInfo);
  544. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  545. goto SubmitIdleRequestIrp_Exit;
  546. }
  547. nextStack = IoGetNextIrpStackLocation(irp);
  548. nextStack->MajorFunction =
  549. IRP_MJ_INTERNAL_DEVICE_CONTROL;
  550. nextStack->Parameters.DeviceIoControl.IoControlCode =
  551. IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
  552. nextStack->Parameters.DeviceIoControl.Type3InputBuffer =
  553. idleCallbackInfo;
  554. nextStack->Parameters.DeviceIoControl.InputBufferLength =
  555. sizeof(struct _USB_IDLE_CALLBACK_INFO);
  556. IoSetCompletionRoutine(irp,
  557. IdleNotificationRequestComplete,
  558. DeviceExtension,
  559. TRUE,
  560. TRUE,
  561. TRUE);
  562. DeviceExtension->PendingIdleIrp = irp;
  563. //
  564. // we initialize the count to 2.
  565. // The reason is, if the CancelSelectSuspend routine manages
  566. // to grab the irp from the device extension, then the last of the
  567. // CancelSelectSuspend routine/IdleNotificationRequestComplete routine
  568. // to execute will free this irp. We need to have this schema so that
  569. // 1. completion routine does not attempt to touch the irp freed by
  570. // CancelSelectSuspend routine.
  571. // 2. CancelSelectSuspend routine doesnt wait for ever for the completion
  572. // routine to complete!
  573. //
  574. DeviceExtension->FreeIdleIrpCount = 2;
  575. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  576. //
  577. // check if the device is idle.
  578. // A check here ensures that a race condition did not
  579. // completely reverse the call sequence of SubmitIdleRequestIrp
  580. // and CancelSelectiveSuspend
  581. //
  582. if(!CanDeviceSuspend(DeviceExtension) ||
  583. PowerDeviceD0 != DeviceExtension->DevPower) {
  584. //
  585. // IRPs created using IoBuildDeviceIoControlRequest should be
  586. // completed by calling IoCompleteRequest and not merely
  587. // deallocated.
  588. //
  589. BulkUsb_DbgPrint(1, ("Device is not idle\n"));
  590. KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
  591. DeviceExtension->IdleCallbackInfo = NULL;
  592. DeviceExtension->PendingIdleIrp = NULL;
  593. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  594. IO_NO_INCREMENT,
  595. FALSE);
  596. InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
  597. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  598. if(idleCallbackInfo) {
  599. ExFreePool(idleCallbackInfo);
  600. }
  601. //
  602. // it is still safe to touch the local variable "irp" here.
  603. // the irp has not been passed down the stack, the irp has
  604. // no cancellation routine. The worse position is that the
  605. // CancelSelectSuspend has run after we released the spin
  606. // lock above. It is still essential to free the irp.
  607. //
  608. if(irp) {
  609. IoFreeIrp(irp);
  610. }
  611. ntStatus = STATUS_UNSUCCESSFUL;
  612. goto SubmitIdleRequestIrp_Exit;
  613. }
  614. BulkUsb_DbgPrint(3, ("Cancel the timers\n"));
  615. //
  616. // Cancel the timer so that the DPCs are no longer fired.
  617. // Thus, we are making judicious usage of our resources.
  618. // we do not need DPCs because we already have an idle irp pending.
  619. // The timers are re-initialized in the completion routine.
  620. //
  621. KeCancelTimer(&DeviceExtension->Timer);
  622. ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);
  623. if(!NT_SUCCESS(ntStatus)) {
  624. BulkUsb_DbgPrint(1, ("IoCallDriver failed\n"));
  625. goto SubmitIdleRequestIrp_Exit;
  626. }
  627. }
  628. else {
  629. BulkUsb_DbgPrint(1, ("Memory allocation for idleCallbackInfo failed\n"));
  630. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  631. IO_NO_INCREMENT,
  632. FALSE);
  633. InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
  634. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  635. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  636. }
  637. SubmitIdleRequestIrp_Exit:
  638. BulkUsb_DbgPrint(3, ("SubmitIdleRequest - ends\n"));
  639. return ntStatus;
  640. }
  641. VOID
  642. IdleNotificationCallback(
  643. IN PDEVICE_EXTENSION DeviceExtension
  644. )
  645. /*++
  646. Routine Description:
  647. "A pointer to a callback function in your driver is passed down the stack with
  648. this IOCTL, and it is this callback function that is called by USBHUB when it
  649. safe for your device to power down."
  650. "When the callback in your driver is called, all you really need to do is to
  651. to first ensure that a WaitWake Irp has been submitted for your device, if
  652. remote wake is possible for your device and then request a SetD2 (or DeviceWake)"
  653. Arguments:
  654. DeviceExtension - pointer to device extension
  655. Return Value:
  656. NT status value
  657. --*/
  658. {
  659. NTSTATUS ntStatus;
  660. POWER_STATE powerState;
  661. KEVENT irpCompletionEvent;
  662. PIRP_COMPLETION_CONTEXT irpContext;
  663. BulkUsb_DbgPrint(3, ("IdleNotificationCallback - begins\n"));
  664. //
  665. // Dont idle, if the device was just disconnected or being stopped
  666. // i.e. return for the following DeviceState(s)
  667. // NotStarted, Stopped, PendingStop, PendingRemove, SurpriseRemoved, Removed
  668. //
  669. if(DeviceExtension->DeviceState != Working) {
  670. return;
  671. }
  672. //
  673. // If there is not already a WW IRP pending, submit one now
  674. //
  675. if(DeviceExtension->WaitWakeEnable) {
  676. IssueWaitWake(DeviceExtension);
  677. }
  678. //
  679. // power down the device
  680. //
  681. irpContext = (PIRP_COMPLETION_CONTEXT)
  682. ExAllocatePool(NonPagedPool,
  683. sizeof(IRP_COMPLETION_CONTEXT));
  684. if(!irpContext) {
  685. BulkUsb_DbgPrint(1, ("Failed to alloc memory for irpContext\n"));
  686. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  687. }
  688. else {
  689. //
  690. // increment the count. In the HoldIoRequestWorkerRoutine, the
  691. // count is decremented twice (one for the system Irp and the
  692. // other for the device Irp. An increment here compensates for
  693. // the sytem irp..The decrement corresponding to this increment
  694. // is in the completion function
  695. //
  696. BulkUsb_DbgPrint(3, ("IdleNotificationCallback::"));
  697. BulkUsb_IoIncrement(DeviceExtension);
  698. powerState.DeviceState = DeviceExtension->PowerDownLevel;
  699. KeInitializeEvent(&irpCompletionEvent, NotificationEvent, FALSE);
  700. irpContext->DeviceExtension = DeviceExtension;
  701. irpContext->Event = &irpCompletionEvent;
  702. ntStatus = PoRequestPowerIrp(
  703. DeviceExtension->PhysicalDeviceObject,
  704. IRP_MN_SET_POWER,
  705. powerState,
  706. (PREQUEST_POWER_COMPLETE) PoIrpCompletionFunc,
  707. irpContext,
  708. NULL);
  709. if(STATUS_PENDING == ntStatus) {
  710. BulkUsb_DbgPrint(3, ("IdleNotificationCallback::"
  711. "waiting for the power irp to complete\n"));
  712. KeWaitForSingleObject(&irpCompletionEvent,
  713. Executive,
  714. KernelMode,
  715. FALSE,
  716. NULL);
  717. }
  718. }
  719. if(!NT_SUCCESS(ntStatus)) {
  720. if(irpContext) {
  721. ExFreePool(irpContext);
  722. }
  723. }
  724. BulkUsb_DbgPrint(3, ("IdleNotificationCallback - ends\n"));
  725. }
  726. NTSTATUS
  727. IdleNotificationRequestComplete(
  728. IN PDEVICE_OBJECT DeviceObject,
  729. IN PIRP Irp,
  730. IN PDEVICE_EXTENSION DeviceExtension
  731. )
  732. /*++
  733. Routine Description:
  734. Completion routine for idle notification irp
  735. Arguments:
  736. DeviceObject - pointer to device object
  737. Irp - I/O request packet
  738. DeviceExtension - pointer to device extension
  739. Return Value:
  740. NT status value
  741. --*/
  742. {
  743. NTSTATUS ntStatus;
  744. POWER_STATE powerState;
  745. KIRQL oldIrql;
  746. LARGE_INTEGER dueTime;
  747. PIRP idleIrp;
  748. PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
  749. BulkUsb_DbgPrint(3, ("IdleNotificationRequestCompete - begins\n"));
  750. idleIrp = NULL;
  751. //
  752. // check the Irp status
  753. //
  754. ntStatus = Irp->IoStatus.Status;
  755. if(!NT_SUCCESS(ntStatus) && ntStatus != STATUS_NOT_SUPPORTED) {
  756. BulkUsb_DbgPrint(1, ("Idle irp completes with error::"));
  757. switch(ntStatus) {
  758. case STATUS_INVALID_DEVICE_REQUEST:
  759. BulkUsb_DbgPrint(1, ("STATUS_INVALID_DEVICE_REQUEST\n"));
  760. break;
  761. case STATUS_CANCELLED:
  762. BulkUsb_DbgPrint(1, ("STATUS_CANCELLED\n"));
  763. break;
  764. case STATUS_POWER_STATE_INVALID:
  765. BulkUsb_DbgPrint(1, ("STATUS_POWER_STATE_INVALID\n"));
  766. goto IdleNotificationRequestComplete_Exit;
  767. case STATUS_DEVICE_BUSY:
  768. BulkUsb_DbgPrint(1, ("STATUS_DEVICE_BUSY\n"));
  769. break;
  770. default:
  771. BulkUsb_DbgPrint(1, ("default: status = %X\n", ntStatus));
  772. break;
  773. }
  774. //
  775. // if in error, issue a SetD0 (only when not in D0)
  776. //
  777. if(PowerDeviceD0 != DeviceExtension->DevPower) {
  778. BulkUsb_DbgPrint(3, ("IdleNotificationRequestComplete::"));
  779. BulkUsb_IoIncrement(DeviceExtension);
  780. powerState.DeviceState = PowerDeviceD0;
  781. ntStatus = PoRequestPowerIrp(
  782. DeviceExtension->PhysicalDeviceObject,
  783. IRP_MN_SET_POWER,
  784. powerState,
  785. (PREQUEST_POWER_COMPLETE) PoIrpAsyncCompletionFunc,
  786. DeviceExtension,
  787. NULL);
  788. if(!NT_SUCCESS(ntStatus)) {
  789. BulkUsb_DbgPrint(1, ("PoRequestPowerIrp failed\n"));
  790. }
  791. }
  792. }
  793. IdleNotificationRequestComplete_Exit:
  794. KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
  795. idleCallbackInfo = DeviceExtension->IdleCallbackInfo;
  796. DeviceExtension->IdleCallbackInfo = NULL;
  797. idleIrp = (PIRP) InterlockedExchangePointer(
  798. &DeviceExtension->PendingIdleIrp,
  799. NULL);
  800. InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
  801. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  802. if(idleCallbackInfo) {
  803. ExFreePool(idleCallbackInfo);
  804. }
  805. //
  806. // since the irp was created using IoAllocateIrp,
  807. // the Irp needs to be freed using IoFreeIrp.
  808. // Also return STATUS_MORE_PROCESSING_REQUIRED so that
  809. // the kernel does not reference this in the near future.
  810. //
  811. if(idleIrp) {
  812. BulkUsb_DbgPrint(3, ("completion routine has a valid irp and frees it\n"));
  813. IoFreeIrp(Irp);
  814. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  815. IO_NO_INCREMENT,
  816. FALSE);
  817. }
  818. else {
  819. //
  820. // The CancelSelectiveSuspend routine has grabbed the Irp from the device
  821. // extension. Now the last one to decrement the FreeIdleIrpCount should
  822. // free the irp.
  823. //
  824. if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount)) {
  825. BulkUsb_DbgPrint(3, ("completion routine frees the irp\n"));
  826. IoFreeIrp(Irp);
  827. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  828. IO_NO_INCREMENT,
  829. FALSE);
  830. }
  831. }
  832. if(DeviceExtension->SSEnable) {
  833. BulkUsb_DbgPrint(3, ("Set the timer to fire DPCs\n"));
  834. dueTime.QuadPart = -10000 * IDLE_INTERVAL; // 5000 ms
  835. KeSetTimerEx(&DeviceExtension->Timer,
  836. dueTime,
  837. IDLE_INTERVAL, // 5000 ms
  838. &DeviceExtension->DeferredProcCall);
  839. BulkUsb_DbgPrint(3, ("IdleNotificationRequestCompete - ends\n"));
  840. }
  841. return STATUS_MORE_PROCESSING_REQUIRED;
  842. }
  843. VOID
  844. CancelSelectSuspend(
  845. IN PDEVICE_EXTENSION DeviceExtension
  846. )
  847. /*++
  848. Routine Description:
  849. This routine is invoked to cancel selective suspend request.
  850. Arguments:
  851. DeviceExtension - pointer to device extension
  852. Return Value:
  853. None.
  854. --*/
  855. {
  856. PIRP irp;
  857. KIRQL oldIrql;
  858. irp = NULL;
  859. BulkUsb_DbgPrint(3, ("CancelSelectSuspend - begins\n"));
  860. KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
  861. if(!CanDeviceSuspend(DeviceExtension))
  862. {
  863. BulkUsb_DbgPrint(3, ("Device is not idle\n"));
  864. irp = (PIRP) InterlockedExchangePointer(
  865. &DeviceExtension->PendingIdleIrp,
  866. NULL);
  867. }
  868. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  869. //
  870. // since we have a valid Irp ptr,
  871. // we can call IoCancelIrp on it,
  872. // without the fear of the irp
  873. // being freed underneath us.
  874. //
  875. if(irp) {
  876. //
  877. // This routine has the irp pointer.
  878. // It is safe to call IoCancelIrp because we know that
  879. // the compleiton routine will not free this irp unless...
  880. //
  881. //
  882. if(IoCancelIrp(irp)) {
  883. BulkUsb_DbgPrint(3, ("IoCancelIrp returns TRUE\n"));
  884. }
  885. else {
  886. BulkUsb_DbgPrint(3, ("IoCancelIrp returns FALSE\n"));
  887. }
  888. //
  889. // ....we decrement the FreeIdleIrpCount from 2 to 1.
  890. // if completion routine runs ahead of us, then this routine
  891. // decrements the FreeIdleIrpCount from 1 to 0 and hence shall
  892. // free the irp.
  893. //
  894. if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount)) {
  895. BulkUsb_DbgPrint(3, ("CancelSelectSuspend frees the irp\n"));
  896. IoFreeIrp(irp);
  897. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  898. IO_NO_INCREMENT,
  899. FALSE);
  900. }
  901. }
  902. BulkUsb_DbgPrint(3, ("CancelSelectSuspend - ends\n"));
  903. return;
  904. }
  905. VOID
  906. PoIrpCompletionFunc(
  907. IN PDEVICE_OBJECT DeviceObject,
  908. IN UCHAR MinorFunction,
  909. IN POWER_STATE PowerState,
  910. IN PVOID Context,
  911. IN PIO_STATUS_BLOCK IoStatus
  912. )
  913. /*++
  914. Routine Description:
  915. Completion routine for power irp PoRequested in
  916. IdleNotificationCallback.
  917. Arguments:
  918. DeviceObject - pointer to device object
  919. MinorFunciton - minor function for the irp.
  920. PowerState - irp power state
  921. Context - context passed to the completion function
  922. IoStatus - status block.
  923. Return Value:
  924. None
  925. --*/
  926. {
  927. PIRP_COMPLETION_CONTEXT irpContext;
  928. //
  929. // initialize variables
  930. //
  931. irpContext = NULL;
  932. if(Context) {
  933. irpContext = (PIRP_COMPLETION_CONTEXT) Context;
  934. }
  935. //
  936. // all we do is set the event and decrement the count
  937. //
  938. if(irpContext) {
  939. KeSetEvent(irpContext->Event, 0, FALSE);
  940. BulkUsb_DbgPrint(3, ("PoIrpCompletionFunc::"));
  941. BulkUsb_IoDecrement(irpContext->DeviceExtension);
  942. ExFreePool(irpContext);
  943. }
  944. return;
  945. }
  946. VOID
  947. PoIrpAsyncCompletionFunc(
  948. IN PDEVICE_OBJECT DeviceObject,
  949. IN UCHAR MinorFunction,
  950. IN POWER_STATE PowerState,
  951. IN PVOID Context,
  952. IN PIO_STATUS_BLOCK IoStatus
  953. )
  954. /*++
  955. Routine Description:
  956. Completion routine for power irp PoRequested in IdleNotification
  957. RequestComplete routine.
  958. Arguments:
  959. DeviceObject - pointer to device object
  960. MinorFunciton - minor function for the irp.
  961. PowerState - irp power state
  962. Context - context passed to the completion function
  963. IoStatus - status block.
  964. Return Value:
  965. None
  966. --*/
  967. {
  968. PDEVICE_EXTENSION DeviceExtension;
  969. //
  970. // initialize variables
  971. //
  972. DeviceExtension = (PDEVICE_EXTENSION) Context;
  973. //
  974. // all we do is decrement the count
  975. //
  976. BulkUsb_DbgPrint(3, ("PoIrpAsyncCompletionFunc::"));
  977. BulkUsb_IoDecrement(DeviceExtension);
  978. return;
  979. }
  980. VOID
  981. WWIrpCompletionFunc(
  982. IN PDEVICE_OBJECT DeviceObject,
  983. IN UCHAR MinorFunction,
  984. IN POWER_STATE PowerState,
  985. IN PVOID Context,
  986. IN PIO_STATUS_BLOCK IoStatus
  987. )
  988. /*++
  989. Routine Description:
  990. Completion routine for PoRequest wait wake irp
  991. Arguments:
  992. DeviceObject - pointer to device object
  993. MinorFunciton - minor function for the irp.
  994. PowerState - irp power state
  995. Context - context passed to the completion function
  996. IoStatus - status block.
  997. Return Value:
  998. None
  999. --*/
  1000. {
  1001. PDEVICE_EXTENSION DeviceExtension;
  1002. //
  1003. // initialize variables
  1004. //
  1005. DeviceExtension = (PDEVICE_EXTENSION) Context;
  1006. //
  1007. // all we do is decrement the count
  1008. //
  1009. BulkUsb_DbgPrint(3, ("WWIrpCompletionFunc::"));
  1010. BulkUsb_IoDecrement(DeviceExtension);
  1011. return;
  1012. }