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.

1523 lines
38 KiB

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