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.

2870 lines
73 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. isopnp.c
  5. Abstract:
  6. Isoch USB device driver for Intel 82930 USB test board
  7. Plug and Play module
  8. Environment:
  9. Kernel mode
  10. Notes:
  11. Copyright (c) 2000 Microsoft Corporation.
  12. All Rights Reserved.
  13. --*/
  14. #include "isousb.h"
  15. #include "isopnp.h"
  16. #include "isopwr.h"
  17. #include "isodev.h"
  18. #include "isowmi.h"
  19. #include "isousr.h"
  20. #include "isorwr.h"
  21. #include "isostrm.h"
  22. NTSTATUS
  23. IsoUsb_DispatchPnP(
  24. IN PDEVICE_OBJECT DeviceObject,
  25. IN PIRP Irp
  26. )
  27. /*++
  28. Routine Description:
  29. The plug and play dispatch routines.
  30. Most of these requests the driver will completely ignore.
  31. In all cases it must pass on the IRP to the lower driver.
  32. Arguments:
  33. DeviceObject - pointer to a device object.
  34. Irp - pointer to an I/O Request Packet.
  35. Return Value:
  36. NT status code
  37. --*/
  38. {
  39. PIO_STACK_LOCATION irpStack;
  40. PDEVICE_EXTENSION deviceExtension;
  41. KEVENT startDeviceEvent;
  42. NTSTATUS ntStatus;
  43. //
  44. // initialize variables
  45. //
  46. irpStack = IoGetCurrentIrpStackLocation(Irp);
  47. deviceExtension = DeviceObject->DeviceExtension;
  48. //
  49. // since the device is removed, fail the Irp.
  50. //
  51. if(Removed == deviceExtension->DeviceState) {
  52. ntStatus = STATUS_DELETE_PENDING;
  53. Irp->IoStatus.Status = ntStatus;
  54. Irp->IoStatus.Information = 0;
  55. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  56. return ntStatus;
  57. }
  58. IsoUsb_DbgPrint(3, ("///////////////////////////////////////////\n"));
  59. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchPnP::"));
  60. IsoUsb_IoIncrement(deviceExtension);
  61. if(irpStack->MinorFunction == IRP_MN_START_DEVICE) {
  62. ASSERT(deviceExtension->IdleReqPend == 0);
  63. }
  64. else {
  65. if(deviceExtension->SSEnable) {
  66. CancelSelectSuspend(deviceExtension);
  67. }
  68. }
  69. IsoUsb_DbgPrint(2, (PnPMinorFunctionString(irpStack->MinorFunction)));
  70. switch(irpStack->MinorFunction) {
  71. case IRP_MN_START_DEVICE:
  72. ntStatus = HandleStartDevice(DeviceObject, Irp);
  73. break;
  74. case IRP_MN_QUERY_STOP_DEVICE:
  75. //
  76. // if we cannot stop the device, we fail the query stop irp
  77. //
  78. ntStatus = CanStopDevice(DeviceObject, Irp);
  79. if(NT_SUCCESS(ntStatus)) {
  80. ntStatus = HandleQueryStopDevice(DeviceObject, Irp);
  81. return ntStatus;
  82. }
  83. break;
  84. case IRP_MN_CANCEL_STOP_DEVICE:
  85. ntStatus = HandleCancelStopDevice(DeviceObject, Irp);
  86. break;
  87. case IRP_MN_STOP_DEVICE:
  88. ntStatus = HandleStopDevice(DeviceObject, Irp);
  89. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchPnP::IRP_MN_STOP_DEVICE::"));
  90. IsoUsb_IoDecrement(deviceExtension);
  91. return ntStatus;
  92. case IRP_MN_QUERY_REMOVE_DEVICE:
  93. //
  94. // if we cannot remove the device, we fail the query remove irp
  95. //
  96. ntStatus = CanRemoveDevice(DeviceObject, Irp);
  97. if(NT_SUCCESS(ntStatus)) {
  98. ntStatus = HandleQueryRemoveDevice(DeviceObject, Irp);
  99. return ntStatus;
  100. }
  101. break;
  102. case IRP_MN_CANCEL_REMOVE_DEVICE:
  103. ntStatus = HandleCancelRemoveDevice(DeviceObject, Irp);
  104. break;
  105. case IRP_MN_SURPRISE_REMOVAL:
  106. ntStatus = HandleSurpriseRemoval(DeviceObject, Irp);
  107. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchPnP::IRP_MN_SURPRISE_REMOVAL::"));
  108. IsoUsb_IoDecrement(deviceExtension);
  109. return ntStatus;
  110. case IRP_MN_REMOVE_DEVICE:
  111. ntStatus = HandleRemoveDevice(DeviceObject, Irp);
  112. return ntStatus;
  113. case IRP_MN_QUERY_CAPABILITIES:
  114. ntStatus = HandleQueryCapabilities(DeviceObject, Irp);
  115. break;
  116. default:
  117. IoSkipCurrentIrpStackLocation(Irp);
  118. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  119. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchPnP::default::"));
  120. IsoUsb_IoDecrement(deviceExtension);
  121. return ntStatus;
  122. } // switch
  123. //
  124. // complete request
  125. //
  126. Irp->IoStatus.Status = ntStatus;
  127. Irp->IoStatus.Information = 0;
  128. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  129. //
  130. // decrement count
  131. //
  132. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchPnP::"));
  133. IsoUsb_IoDecrement(deviceExtension);
  134. return ntStatus;
  135. }
  136. NTSTATUS
  137. HandleStartDevice(
  138. IN PDEVICE_OBJECT DeviceObject,
  139. IN PIRP Irp
  140. )
  141. /*++
  142. Routine Description:
  143. This is the dispatch routine for IRP_MN_START_DEVICE
  144. Arguments:
  145. DeviceObject - pointer to a device object.
  146. Irp - I/O request packet
  147. Return Value:
  148. NT status value
  149. --*/
  150. {
  151. KIRQL oldIrql;
  152. KEVENT startDeviceEvent;
  153. NTSTATUS ntStatus;
  154. PDEVICE_EXTENSION deviceExtension;
  155. LARGE_INTEGER dueTime;
  156. IsoUsb_DbgPrint(3, ("HandleStartDevice - begins\n"));
  157. //
  158. // initialize variables
  159. //
  160. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  161. deviceExtension->UsbConfigurationDescriptor = NULL;
  162. deviceExtension->UsbInterface = NULL;
  163. //
  164. // We cannot touch the device (send it any non pnp irps) until a
  165. // start device has been passed down to the lower drivers.
  166. // first pass the Irp down
  167. //
  168. KeInitializeEvent(&startDeviceEvent, NotificationEvent, FALSE);
  169. IoCopyCurrentIrpStackLocationToNext(Irp);
  170. IoSetCompletionRoutine(Irp,
  171. (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
  172. (PVOID)&startDeviceEvent,
  173. TRUE,
  174. TRUE,
  175. TRUE);
  176. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  177. if(ntStatus == STATUS_PENDING) {
  178. KeWaitForSingleObject(&startDeviceEvent,
  179. Executive,
  180. KernelMode,
  181. FALSE,
  182. NULL);
  183. ntStatus = Irp->IoStatus.Status;
  184. }
  185. if(!NT_SUCCESS(ntStatus)) {
  186. IsoUsb_DbgPrint(1, ("Lower drivers failed this Irp\n"));
  187. return ntStatus;
  188. }
  189. //
  190. // Read the device descriptor, configuration descriptor
  191. // and select the interface descriptors
  192. //
  193. ntStatus = ReadandSelectDescriptors(DeviceObject);
  194. if(!NT_SUCCESS(ntStatus)) {
  195. IsoUsb_DbgPrint(1, ("ReadandSelectDescriptors failed\n"));
  196. return ntStatus;
  197. }
  198. //
  199. // enable the symbolic links for system components to open
  200. // handles to the device
  201. //
  202. ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName,
  203. TRUE);
  204. if(!NT_SUCCESS(ntStatus)) {
  205. IsoUsb_DbgPrint(1, ("IoSetDeviceInterfaceState:enable:failed\n"));
  206. return ntStatus;
  207. }
  208. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  209. SET_NEW_PNP_STATE(deviceExtension, Working);
  210. deviceExtension->QueueState = AllowRequests;
  211. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  212. //
  213. // initialize wait wake outstanding flag to false.
  214. // and issue a wait wake.
  215. deviceExtension->FlagWWOutstanding = 0;
  216. deviceExtension->FlagWWCancel = 0;
  217. deviceExtension->WaitWakeIrp = NULL;
  218. if(deviceExtension->WaitWakeEnable) {
  219. IssueWaitWake(deviceExtension);
  220. }
  221. ProcessQueuedRequests(deviceExtension);
  222. if(WinXpOrBetter == deviceExtension->WdmVersion) {
  223. deviceExtension->SSEnable = deviceExtension->SSRegistryEnable;
  224. //
  225. // set timer for selective suspend requests.
  226. //
  227. if(deviceExtension->SSEnable) {
  228. dueTime.QuadPart = -10000 * IDLE_INTERVAL; // 5000 ms
  229. KeSetTimerEx(&deviceExtension->Timer,
  230. dueTime,
  231. IDLE_INTERVAL, // 5000 ms
  232. &deviceExtension->DeferredProcCall);
  233. deviceExtension->FreeIdleIrpCount = 0;
  234. }
  235. }
  236. if((Win2kOrBetter == deviceExtension->WdmVersion) ||
  237. (WinXpOrBetter == deviceExtension->WdmVersion)) {
  238. deviceExtension->IsDeviceHighSpeed = 0;
  239. GetBusInterfaceVersion(DeviceObject);
  240. }
  241. IsoUsb_DbgPrint(3, ("HandleStartDevice - ends\n"));
  242. return ntStatus;
  243. }
  244. NTSTATUS
  245. ReadandSelectDescriptors(
  246. IN PDEVICE_OBJECT DeviceObject
  247. )
  248. /*++
  249. Routine Description:
  250. This routine configures the USB device.
  251. In this routines we get the device descriptor,
  252. the configuration descriptor and select the
  253. configuration descriptor.
  254. Arguments:
  255. DeviceObject - pointer to a device object
  256. Return Value:
  257. NTSTATUS - NT status value.
  258. --*/
  259. {
  260. PURB urb;
  261. ULONG siz;
  262. NTSTATUS ntStatus;
  263. PUSB_DEVICE_DESCRIPTOR deviceDescriptor;
  264. //
  265. // initialize variables
  266. //
  267. urb = NULL;
  268. deviceDescriptor = NULL;
  269. //
  270. // 1. Read the device descriptor
  271. //
  272. urb = ExAllocatePool(NonPagedPool,
  273. sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  274. if(urb) {
  275. siz = sizeof(USB_DEVICE_DESCRIPTOR);
  276. deviceDescriptor = ExAllocatePool(NonPagedPool, siz);
  277. if(deviceDescriptor) {
  278. UsbBuildGetDescriptorRequest(
  279. urb,
  280. (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  281. USB_DEVICE_DESCRIPTOR_TYPE,
  282. 0,
  283. 0,
  284. deviceDescriptor,
  285. NULL,
  286. siz,
  287. NULL);
  288. ntStatus = CallUSBD(DeviceObject, urb);
  289. if(NT_SUCCESS(ntStatus)) {
  290. ASSERT(deviceDescriptor->bNumConfigurations);
  291. ntStatus = ConfigureDevice(DeviceObject);
  292. }
  293. ExFreePool(urb);
  294. ExFreePool(deviceDescriptor);
  295. }
  296. else {
  297. IsoUsb_DbgPrint(1, ("Failed to allocate memory for deviceDescriptor\n"));
  298. ExFreePool(urb);
  299. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  300. }
  301. }
  302. else {
  303. IsoUsb_DbgPrint(1, ("Failed to allocate memory for urb\n"));
  304. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  305. }
  306. return ntStatus;
  307. }
  308. NTSTATUS
  309. ConfigureDevice(
  310. IN PDEVICE_OBJECT DeviceObject
  311. )
  312. /*++
  313. Routine Description:
  314. This helper routine reads the configuration descriptor
  315. for the device in couple of steps.
  316. Arguments:
  317. DeviceObject - pointer to a device object
  318. Return Value:
  319. NTSTATUS - NT status value
  320. --*/
  321. {
  322. PURB urb;
  323. ULONG siz;
  324. NTSTATUS ntStatus;
  325. PDEVICE_EXTENSION deviceExtension;
  326. PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
  327. //
  328. // initialize the variables
  329. //
  330. urb = NULL;
  331. configurationDescriptor = NULL;
  332. deviceExtension = DeviceObject->DeviceExtension;
  333. //
  334. // Read the first configuration descriptor
  335. // This requires two steps:
  336. // 1. Read the fixed sized configuration desciptor (CD)
  337. // 2. Read the CD with all embedded interface and endpoint descriptors
  338. //
  339. urb = ExAllocatePool(NonPagedPool,
  340. sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  341. if(urb) {
  342. siz = sizeof(USB_CONFIGURATION_DESCRIPTOR);
  343. configurationDescriptor = ExAllocatePool(NonPagedPool, siz);
  344. if(configurationDescriptor) {
  345. UsbBuildGetDescriptorRequest(
  346. urb,
  347. (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  348. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  349. 0,
  350. 0,
  351. configurationDescriptor,
  352. NULL,
  353. sizeof(USB_CONFIGURATION_DESCRIPTOR),
  354. NULL);
  355. ntStatus = CallUSBD(DeviceObject, urb);
  356. if(!NT_SUCCESS(ntStatus)) {
  357. IsoUsb_DbgPrint(1, ("UsbBuildGetDescriptorRequest failed\n"));
  358. goto ConfigureDevice_Exit;
  359. }
  360. }
  361. else {
  362. IsoUsb_DbgPrint(1, ("Failed to allocate mem for config Descriptor\n"));
  363. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  364. goto ConfigureDevice_Exit;
  365. }
  366. siz = configurationDescriptor->wTotalLength;
  367. ExFreePool(configurationDescriptor);
  368. configurationDescriptor = ExAllocatePool(NonPagedPool, siz);
  369. if(configurationDescriptor) {
  370. UsbBuildGetDescriptorRequest(
  371. urb,
  372. (USHORT)sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  373. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  374. 0,
  375. 0,
  376. configurationDescriptor,
  377. NULL,
  378. siz,
  379. NULL);
  380. ntStatus = CallUSBD(DeviceObject, urb);
  381. if(!NT_SUCCESS(ntStatus)) {
  382. IsoUsb_DbgPrint(1,("Failed to read configuration descriptor\n"));
  383. goto ConfigureDevice_Exit;
  384. }
  385. }
  386. else {
  387. IsoUsb_DbgPrint(1, ("Failed to alloc mem for config Descriptor\n"));
  388. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  389. goto ConfigureDevice_Exit;
  390. }
  391. }
  392. else {
  393. IsoUsb_DbgPrint(1, ("Failed to allocate memory for urb\n"));
  394. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  395. goto ConfigureDevice_Exit;
  396. }
  397. if(configurationDescriptor) {
  398. //
  399. // save a copy of configurationDescriptor in deviceExtension
  400. // remember to free it later.
  401. //
  402. deviceExtension->UsbConfigurationDescriptor = configurationDescriptor;
  403. if(configurationDescriptor->bmAttributes & REMOTE_WAKEUP_MASK)
  404. {
  405. //
  406. // this configuration supports remote wakeup
  407. //
  408. deviceExtension->WaitWakeEnable = 1;
  409. }
  410. else
  411. {
  412. deviceExtension->WaitWakeEnable = 0;
  413. }
  414. ntStatus = SelectInterfaces(DeviceObject, configurationDescriptor);
  415. }
  416. else {
  417. deviceExtension->UsbConfigurationDescriptor = NULL;
  418. }
  419. ConfigureDevice_Exit:
  420. if(urb) {
  421. ExFreePool(urb);
  422. }
  423. return ntStatus;
  424. }
  425. NTSTATUS
  426. SelectInterfaces(
  427. IN PDEVICE_OBJECT DeviceObject,
  428. IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
  429. )
  430. /*++
  431. Routine Description:
  432. This helper routine selects the configuration
  433. Arguments:
  434. DeviceObject - pointer to device object
  435. ConfigurationDescriptor - pointer to the configuration
  436. descriptor for the device
  437. Return Value:
  438. NT status value
  439. --*/
  440. {
  441. LONG numberOfInterfaces,
  442. interfaceNumber,
  443. interfaceindex;
  444. ULONG i;
  445. PURB urb;
  446. PUCHAR pInf;
  447. NTSTATUS ntStatus;
  448. PDEVICE_EXTENSION deviceExtension;
  449. PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
  450. PUSBD_INTERFACE_LIST_ENTRY interfaceList,
  451. tmp;
  452. PUSBD_INTERFACE_INFORMATION Interface;
  453. //
  454. // initialize the variables
  455. //
  456. urb = NULL;
  457. Interface = NULL;
  458. interfaceDescriptor = NULL;
  459. deviceExtension = DeviceObject->DeviceExtension;
  460. numberOfInterfaces = ConfigurationDescriptor->bNumInterfaces;
  461. interfaceindex = interfaceNumber = 0;
  462. //
  463. // Parse the configuration descriptor for the interface;
  464. //
  465. tmp = interfaceList =
  466. ExAllocatePool(
  467. NonPagedPool,
  468. sizeof(USBD_INTERFACE_LIST_ENTRY) * (numberOfInterfaces + 1));
  469. if(!tmp) {
  470. IsoUsb_DbgPrint(1, ("Failed to allocate mem for interfaceList\n"));
  471. return STATUS_INSUFFICIENT_RESOURCES;
  472. }
  473. while(interfaceNumber < numberOfInterfaces) {
  474. interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
  475. ConfigurationDescriptor,
  476. ConfigurationDescriptor,
  477. interfaceindex,
  478. 0, -1, -1, -1);
  479. if(interfaceDescriptor) {
  480. interfaceList->InterfaceDescriptor = interfaceDescriptor;
  481. interfaceList->Interface = NULL;
  482. interfaceList++;
  483. interfaceNumber++;
  484. }
  485. interfaceindex++;
  486. }
  487. interfaceList->InterfaceDescriptor = NULL;
  488. interfaceList->Interface = NULL;
  489. urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor, tmp);
  490. if(urb) {
  491. Interface = &urb->UrbSelectConfiguration.Interface;
  492. for(i=0; i<Interface->NumberOfPipes; i++) {
  493. //
  494. // perform pipe initialization here
  495. // set the transfer size and any pipe flags we use
  496. // USBD sets the rest of the Interface struct members
  497. //
  498. Interface->Pipes[i].MaximumTransferSize =
  499. USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
  500. }
  501. ntStatus = CallUSBD(DeviceObject, urb);
  502. if(NT_SUCCESS(ntStatus)) {
  503. //
  504. // save a copy of interface information in the device extension.
  505. //
  506. deviceExtension->UsbInterface = ExAllocatePool(NonPagedPool,
  507. Interface->Length);
  508. if(deviceExtension->UsbInterface) {
  509. RtlCopyMemory(deviceExtension->UsbInterface,
  510. Interface,
  511. Interface->Length);
  512. }
  513. else {
  514. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  515. IsoUsb_DbgPrint(1, ("memory alloc for UsbInterface failed\n"));
  516. }
  517. //
  518. // Dump the interface to the debugger
  519. //
  520. Interface = &urb->UrbSelectConfiguration.Interface;
  521. IsoUsb_DbgPrint(3, ("---------\n"));
  522. IsoUsb_DbgPrint(3, ("NumberOfPipes 0x%x\n",
  523. Interface->NumberOfPipes));
  524. IsoUsb_DbgPrint(3, ("Length 0x%x\n",
  525. Interface->Length));
  526. IsoUsb_DbgPrint(3, ("Alt Setting 0x%x\n",
  527. Interface->AlternateSetting));
  528. IsoUsb_DbgPrint(3, ("Interface Number 0x%x\n",
  529. Interface->InterfaceNumber));
  530. IsoUsb_DbgPrint(3, ("Class, subclass, protocol 0x%x 0x%x 0x%x\n",
  531. Interface->Class,
  532. Interface->SubClass,
  533. Interface->Protocol));
  534. for(i=0; i<Interface->NumberOfPipes; i++) {
  535. IsoUsb_DbgPrint(3, ("---------\n"));
  536. IsoUsb_DbgPrint(3, ("PipeType 0x%x\n",
  537. Interface->Pipes[i].PipeType));
  538. IsoUsb_DbgPrint(3, ("EndpointAddress 0x%x\n",
  539. Interface->Pipes[i].EndpointAddress));
  540. IsoUsb_DbgPrint(3, ("MaxPacketSize 0x%x\n",
  541. Interface->Pipes[i].MaximumPacketSize));
  542. IsoUsb_DbgPrint(3, ("Interval 0x%x\n",
  543. Interface->Pipes[i].Interval));
  544. IsoUsb_DbgPrint(3, ("Handle 0x%x\n",
  545. Interface->Pipes[i].PipeHandle));
  546. IsoUsb_DbgPrint(3, ("MaximumTransferSize 0x%x\n",
  547. Interface->Pipes[i].MaximumTransferSize));
  548. }
  549. IsoUsb_DbgPrint(3, ("---------\n"));
  550. }
  551. else {
  552. IsoUsb_DbgPrint(1, ("Failed to select an interface\n"));
  553. }
  554. }
  555. else {
  556. IsoUsb_DbgPrint(1, ("USBD_CreateConfigurationRequestEx failed\n"));
  557. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  558. }
  559. if(tmp) {
  560. ExFreePool(tmp);
  561. }
  562. if(urb) {
  563. ExFreePool(urb);
  564. }
  565. return ntStatus;
  566. }
  567. NTSTATUS
  568. DeconfigureDevice(
  569. IN PDEVICE_OBJECT DeviceObject
  570. )
  571. /*++
  572. Routine Description:
  573. This routine is invoked when the device is removed or stopped.
  574. This routine de-configures the usb device.
  575. Arguments:
  576. DeviceObject - pointer to device object
  577. Return Value:
  578. NT status value
  579. --*/
  580. {
  581. PURB urb;
  582. ULONG siz;
  583. NTSTATUS ntStatus;
  584. //
  585. // initialize variables
  586. //
  587. siz = sizeof(struct _URB_SELECT_CONFIGURATION);
  588. urb = ExAllocatePool(NonPagedPool, siz);
  589. if(urb) {
  590. UsbBuildSelectConfigurationRequest(urb, (USHORT)siz, NULL);
  591. ntStatus = CallUSBD(DeviceObject, urb);
  592. if(!NT_SUCCESS(ntStatus)) {
  593. IsoUsb_DbgPrint(3, ("Failed to deconfigure device\n"));
  594. }
  595. ExFreePool(urb);
  596. }
  597. else {
  598. IsoUsb_DbgPrint(1, ("Failed to allocate urb\n"));
  599. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  600. }
  601. return ntStatus;
  602. }
  603. NTSTATUS
  604. CallUSBD(
  605. IN PDEVICE_OBJECT DeviceObject,
  606. IN PURB Urb
  607. )
  608. /*++
  609. Routine Description:
  610. This routine synchronously submits an urb down the stack.
  611. Arguments:
  612. DeviceObject - pointer to device object
  613. Urb - USB request block
  614. Return Value:
  615. NT status value
  616. --*/
  617. {
  618. PIRP irp;
  619. KEVENT event;
  620. NTSTATUS ntStatus;
  621. IO_STATUS_BLOCK ioStatus;
  622. PIO_STACK_LOCATION nextStack;
  623. PDEVICE_EXTENSION deviceExtension;
  624. //
  625. // initialize the variables
  626. //
  627. irp = NULL;
  628. deviceExtension = DeviceObject->DeviceExtension;
  629. KeInitializeEvent(&event, NotificationEvent, FALSE);
  630. irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
  631. deviceExtension->TopOfStackDeviceObject,
  632. NULL,
  633. 0,
  634. NULL,
  635. 0,
  636. TRUE,
  637. &event,
  638. &ioStatus);
  639. if(!irp) {
  640. IsoUsb_DbgPrint(1, ("IoBuildDeviceIoControlRequest failed\n"));
  641. return STATUS_INSUFFICIENT_RESOURCES;
  642. }
  643. nextStack = IoGetNextIrpStackLocation(irp);
  644. ASSERT(nextStack != NULL);
  645. nextStack->Parameters.Others.Argument1 = Urb;
  646. IsoUsb_DbgPrint(3, ("CallUSBD::"));
  647. IsoUsb_IoIncrement(deviceExtension);
  648. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
  649. if(ntStatus == STATUS_PENDING) {
  650. KeWaitForSingleObject(&event,
  651. Executive,
  652. KernelMode,
  653. FALSE,
  654. NULL);
  655. ntStatus = ioStatus.Status;
  656. }
  657. IsoUsb_DbgPrint(3, ("CallUSBD::"));
  658. IsoUsb_IoDecrement(deviceExtension);
  659. return ntStatus;
  660. }
  661. NTSTATUS
  662. HandleQueryStopDevice(
  663. IN PDEVICE_OBJECT DeviceObject,
  664. IN PIRP Irp
  665. )
  666. /*++
  667. Routine Description:
  668. This routine services the Irps of minor type IRP_MN_QUERY_STOP_DEVICE
  669. Arguments:
  670. DeviceObject - pointer to device object
  671. Irp - I/O request packet sent by the pnp manager.
  672. Return Value:
  673. NT status value
  674. --*/
  675. {
  676. KIRQL oldIrql;
  677. NTSTATUS ntStatus;
  678. PDEVICE_EXTENSION deviceExtension;
  679. IsoUsb_DbgPrint(3, ("HandleQueryStopDevice - begins\n"));
  680. //
  681. // initialize variables
  682. //
  683. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  684. //
  685. // If we can stop the device, we need to set the QueueState to
  686. // HoldRequests so further requests will be queued.
  687. //
  688. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  689. SET_NEW_PNP_STATE(deviceExtension, PendingStop);
  690. deviceExtension->QueueState = HoldRequests;
  691. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  692. //
  693. // wait for the existing ones to be finished.
  694. // first, decrement this operation
  695. //
  696. IsoUsb_DbgPrint(3, ("HandleQueryStopDevice::"));
  697. IsoUsb_IoDecrement(deviceExtension);
  698. KeWaitForSingleObject(&deviceExtension->StopEvent,
  699. Executive,
  700. KernelMode,
  701. FALSE,
  702. NULL);
  703. Irp->IoStatus.Status = STATUS_SUCCESS;
  704. Irp->IoStatus.Information = 0;
  705. IoSkipCurrentIrpStackLocation(Irp);
  706. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  707. IsoUsb_DbgPrint(3, ("HandleQueryStopDevice - ends\n"));
  708. return ntStatus;
  709. }
  710. NTSTATUS
  711. HandleCancelStopDevice(
  712. IN PDEVICE_OBJECT DeviceObject,
  713. IN PIRP Irp
  714. )
  715. /*++
  716. Routine Description:
  717. This routine services Irp of minor type IRP_MN_CANCEL_STOP_DEVICE
  718. Arguments:
  719. DeviceObject - pointer to device object
  720. Irp - I/O request packet sent by the pnp manager.
  721. Return Value:
  722. NT value
  723. --*/
  724. {
  725. KIRQL oldIrql;
  726. KEVENT event;
  727. NTSTATUS ntStatus;
  728. PDEVICE_EXTENSION deviceExtension;
  729. IsoUsb_DbgPrint(3, ("HandleCancelStopDevice - begins\n"));
  730. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  731. //
  732. // Send this IRP down and wait for it to come back.
  733. // Set the QueueState flag to AllowRequests,
  734. // and process all the previously queued up IRPs.
  735. //
  736. // First check to see whether you have received cancel-stop
  737. // without first receiving a query-stop. This could happen if someone
  738. // above us fails a query-stop and passes down the subsequent
  739. // cancel-stop.
  740. //
  741. if(PendingStop == deviceExtension->DeviceState) {
  742. KeInitializeEvent(&event, NotificationEvent, FALSE);
  743. IoCopyCurrentIrpStackLocationToNext(Irp);
  744. IoSetCompletionRoutine(Irp,
  745. (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
  746. (PVOID)&event,
  747. TRUE,
  748. TRUE,
  749. TRUE);
  750. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  751. if(ntStatus == STATUS_PENDING) {
  752. KeWaitForSingleObject(&event,
  753. Executive,
  754. KernelMode,
  755. FALSE,
  756. NULL);
  757. ntStatus = Irp->IoStatus.Status;
  758. }
  759. if(NT_SUCCESS(ntStatus)) {
  760. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  761. RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
  762. deviceExtension->QueueState = AllowRequests;
  763. ASSERT(deviceExtension->DeviceState == Working);
  764. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  765. ProcessQueuedRequests(deviceExtension);
  766. }
  767. }
  768. else {
  769. // spurious Irp
  770. ntStatus = STATUS_SUCCESS;
  771. }
  772. IsoUsb_DbgPrint(3, ("HandleCancelStopDevice - ends\n"));
  773. return ntStatus;
  774. }
  775. NTSTATUS
  776. HandleStopDevice(
  777. IN PDEVICE_OBJECT DeviceObject,
  778. IN PIRP Irp
  779. )
  780. /*++
  781. Routine Description:
  782. This routine services Irp of minor type IRP_MN_STOP_DEVICE
  783. Arguments:
  784. DeviceObject - pointer to device object
  785. Irp - I/O request packet sent by the pnp manager.
  786. Return Value:
  787. NT status value
  788. --*/
  789. {
  790. KIRQL oldIrql;
  791. NTSTATUS ntStatus;
  792. PDEVICE_EXTENSION deviceExtension;
  793. IsoUsb_DbgPrint(3, ("HandleStopDevice - begins\n"));
  794. //
  795. // initialize variables
  796. //
  797. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  798. if(WinXpOrBetter == deviceExtension->WdmVersion) {
  799. if(deviceExtension->SSEnable) {
  800. //
  801. // Cancel the timer so that the DPCs are no longer fired.
  802. // we do not need DPCs because the device is stopping.
  803. // The timers are re-initialized while handling the start
  804. // device irp.
  805. //
  806. KeCancelTimer(&deviceExtension->Timer);
  807. //
  808. // after the device is stopped, it can be surprise removed.
  809. // we set this to 0, so that we do not attempt to cancel
  810. // the timer while handling surprise remove or remove irps.
  811. // when we get the start device request, this flag will be
  812. // reinitialized.
  813. //
  814. deviceExtension->SSEnable = 0;
  815. //
  816. // make sure that if a DPC was fired before we called cancel timer,
  817. // then the DPC and work-time have run to their completion
  818. //
  819. KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent,
  820. Executive,
  821. KernelMode,
  822. FALSE,
  823. NULL);
  824. //
  825. // make sure that the selective suspend request has been completed.
  826. //
  827. KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
  828. Executive,
  829. KernelMode,
  830. FALSE,
  831. NULL);
  832. }
  833. }
  834. //
  835. // after the stop Irp is sent to the lower driver object,
  836. // the driver must not send any more Irps down that touch
  837. // the device until another Start has occurred.
  838. //
  839. if(deviceExtension->WaitWakeEnable) {
  840. CancelWaitWake(deviceExtension);
  841. }
  842. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  843. SET_NEW_PNP_STATE(deviceExtension, Stopped);
  844. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  845. //
  846. // This is the right place to actually give up all the resources used
  847. // This might include calls to IoDisconnectInterrupt, MmUnmapIoSpace,
  848. // etc.
  849. //
  850. ReleaseMemory(DeviceObject);
  851. ntStatus = DeconfigureDevice(DeviceObject);
  852. Irp->IoStatus.Status = ntStatus;
  853. Irp->IoStatus.Information = 0;
  854. IoSkipCurrentIrpStackLocation(Irp);
  855. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  856. IsoUsb_DbgPrint(3, ("HandleStopDevice - ends\n"));
  857. return ntStatus;
  858. }
  859. NTSTATUS
  860. HandleQueryRemoveDevice(
  861. IN PDEVICE_OBJECT DeviceObject,
  862. IN PIRP Irp
  863. )
  864. /*++
  865. Routine Description:
  866. This routine services Irp of minor type IRP_MN_QUERY_REMOVE_DEVICE
  867. Arguments:
  868. DeviceObject - pointer to device object
  869. Irp - I/O request packet sent by the pnp manager.
  870. Return Value:
  871. NT status value
  872. --*/
  873. {
  874. KIRQL oldIrql;
  875. NTSTATUS ntStatus;
  876. PDEVICE_EXTENSION deviceExtension;
  877. IsoUsb_DbgPrint(3, ("HandleQueryRemoveDevice - begins\n"));
  878. //
  879. // initialize variables
  880. //
  881. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  882. //
  883. // If we can allow removal of the device, we should set the QueueState
  884. // to HoldRequests so further requests will be queued. This is required
  885. // so that we can process queued up requests in cancel-remove just in
  886. // case somebody else in the stack fails the query-remove.
  887. //
  888. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  889. deviceExtension->QueueState = HoldRequests;
  890. SET_NEW_PNP_STATE(deviceExtension, PendingRemove);
  891. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  892. IsoUsb_DbgPrint(3, ("HandleQueryRemoveDevice::"));
  893. IsoUsb_IoDecrement(deviceExtension);
  894. //
  895. // wait for all the requests to be completed
  896. //
  897. KeWaitForSingleObject(&deviceExtension->StopEvent,
  898. Executive,
  899. KernelMode,
  900. FALSE,
  901. NULL);
  902. Irp->IoStatus.Status = STATUS_SUCCESS;
  903. Irp->IoStatus.Information = 0;
  904. IoSkipCurrentIrpStackLocation(Irp);
  905. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  906. IsoUsb_DbgPrint(3, ("HandleQueryRemoveDevice - ends\n"));
  907. return ntStatus;
  908. }
  909. NTSTATUS
  910. HandleCancelRemoveDevice(
  911. IN PDEVICE_OBJECT DeviceObject,
  912. IN PIRP Irp
  913. )
  914. /*++
  915. Routine Description:
  916. This routine services Irp of minor type IRP_MN_CANCEL_REMOVE_DEVICE
  917. Arguments:
  918. DeviceObject - pointer to device object
  919. Irp - I/O request packet sent by the pnp manager.
  920. Return Value:
  921. NT status value
  922. --*/
  923. {
  924. KIRQL oldIrql;
  925. KEVENT event;
  926. NTSTATUS ntStatus;
  927. PDEVICE_EXTENSION deviceExtension;
  928. IsoUsb_DbgPrint(3, ("HandleCancelRemoveDevice - begins\n"));
  929. //
  930. // initialize variables
  931. //
  932. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  933. //
  934. // We need to reset the QueueState flag to ProcessRequest,
  935. // since the device resume its normal activities.
  936. //
  937. //
  938. // First check to see whether you have received cancel-remove
  939. // without first receiving a query-remove. This could happen if
  940. // someone above us fails a query-remove and passes down the
  941. // subsequent cancel-remove.
  942. //
  943. if(PendingRemove == deviceExtension->DeviceState) {
  944. KeInitializeEvent(&event, NotificationEvent, FALSE);
  945. IoCopyCurrentIrpStackLocationToNext(Irp);
  946. IoSetCompletionRoutine(Irp,
  947. (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
  948. (PVOID)&event,
  949. TRUE,
  950. TRUE,
  951. TRUE);
  952. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  953. if(ntStatus == STATUS_PENDING) {
  954. KeWaitForSingleObject(&event,
  955. Executive,
  956. KernelMode,
  957. FALSE,
  958. NULL);
  959. ntStatus = Irp->IoStatus.Status;
  960. }
  961. if(NT_SUCCESS(ntStatus)) {
  962. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  963. deviceExtension->QueueState = AllowRequests;
  964. RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
  965. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  966. //
  967. // process the queued requests that arrive between
  968. // QUERY_REMOVE and CANCEL_REMOVE
  969. //
  970. ProcessQueuedRequests(deviceExtension);
  971. }
  972. }
  973. else {
  974. //
  975. // spurious cancel-remove
  976. //
  977. ntStatus = STATUS_SUCCESS;
  978. }
  979. IsoUsb_DbgPrint(3, ("HandleCancelRemoveDevice - ends\n"));
  980. return ntStatus;
  981. }
  982. NTSTATUS
  983. HandleSurpriseRemoval(
  984. IN PDEVICE_OBJECT DeviceObject,
  985. IN PIRP Irp
  986. )
  987. /*++
  988. Routine Description:
  989. This routine services Irp of minor type IRP_MN_SURPRISE_REMOVAL
  990. Arguments:
  991. DeviceObject - pointer to device object
  992. Irp - I/O request packet sent by the pnp manager.
  993. Return Value:
  994. NT status value
  995. --*/
  996. {
  997. KIRQL oldIrql;
  998. NTSTATUS ntStatus;
  999. PDEVICE_EXTENSION deviceExtension;
  1000. IsoUsb_DbgPrint(3, ("HandleSurpriseRemoval - begins\n"));
  1001. //
  1002. // initialize variables
  1003. //
  1004. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1005. //
  1006. // 1. fail pending requests
  1007. // 2. return device and memory resources
  1008. // 3. disable interfaces
  1009. //
  1010. if(deviceExtension->WaitWakeEnable) {
  1011. CancelWaitWake(deviceExtension);
  1012. }
  1013. if(WinXpOrBetter == deviceExtension->WdmVersion) {
  1014. if(deviceExtension->SSEnable) {
  1015. KeCancelTimer(&deviceExtension->Timer);
  1016. deviceExtension->SSEnable = 0;
  1017. //
  1018. // make sure that if a DPC was fired before we called cancel timer,
  1019. // then the DPC and work-time have run to their completion
  1020. //
  1021. KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent,
  1022. Executive,
  1023. KernelMode,
  1024. FALSE,
  1025. NULL);
  1026. //
  1027. // make sure that the selective suspend request has been completed.
  1028. //
  1029. KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
  1030. Executive,
  1031. KernelMode,
  1032. FALSE,
  1033. NULL);
  1034. }
  1035. }
  1036. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  1037. deviceExtension->QueueState = FailRequests;
  1038. SET_NEW_PNP_STATE(deviceExtension, SurpriseRemoved);
  1039. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  1040. ProcessQueuedRequests(deviceExtension);
  1041. ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName,
  1042. FALSE);
  1043. if(!NT_SUCCESS(ntStatus)) {
  1044. IsoUsb_DbgPrint(1, ("IoSetDeviceInterfaceState::disable:failed\n"));
  1045. }
  1046. RtlFreeUnicodeString(&deviceExtension->InterfaceName);
  1047. IsoUsb_AbortPipes(DeviceObject);
  1048. Irp->IoStatus.Status = STATUS_SUCCESS;
  1049. Irp->IoStatus.Information = 0;
  1050. IoSkipCurrentIrpStackLocation(Irp);
  1051. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  1052. IsoUsb_DbgPrint(3, ("HandleSurpriseRemoval - ends\n"));
  1053. return ntStatus;
  1054. }
  1055. NTSTATUS
  1056. HandleRemoveDevice(
  1057. IN PDEVICE_OBJECT DeviceObject,
  1058. IN PIRP Irp
  1059. )
  1060. /*++
  1061. Routine Description:
  1062. This routine services Irp of minor type IRP_MN_REMOVE_DEVICE
  1063. Arguments:
  1064. DeviceObject - pointer to device object
  1065. Irp - I/O request packet sent by the pnp manager.
  1066. Return Value:
  1067. NT status value
  1068. --*/
  1069. {
  1070. KIRQL oldIrql;
  1071. KEVENT event;
  1072. ULONG requestCount;
  1073. NTSTATUS ntStatus;
  1074. PDEVICE_EXTENSION deviceExtension;
  1075. IsoUsb_DbgPrint(3, ("HandleRemoveDevice - begins\n"));
  1076. //
  1077. // initialize variables
  1078. //
  1079. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1080. //
  1081. // The Plug & Play system has dictated the removal of this device. We
  1082. // have no choice but to detach and delete the device object.
  1083. // (If we wanted to express an interest in preventing this removal,
  1084. // we should have failed the query remove IRP).
  1085. //
  1086. if(SurpriseRemoved != deviceExtension->DeviceState) {
  1087. //
  1088. // we are here after QUERY_REMOVE
  1089. //
  1090. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  1091. deviceExtension->QueueState = FailRequests;
  1092. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  1093. if(deviceExtension->WaitWakeEnable) {
  1094. CancelWaitWake(deviceExtension);
  1095. }
  1096. if(WinXpOrBetter == deviceExtension->WdmVersion) {
  1097. if(deviceExtension->SSEnable) {
  1098. //
  1099. // Cancel the timer so that the DPCs are no longer fired.
  1100. // we do not need DPCs because the device has been removed
  1101. //
  1102. KeCancelTimer(&deviceExtension->Timer);
  1103. deviceExtension->SSEnable = 0;
  1104. //
  1105. // make sure that if a DPC was fired before we called cancel timer,
  1106. // then the DPC and work-time have run to their completion
  1107. //
  1108. KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent,
  1109. Executive,
  1110. KernelMode,
  1111. FALSE,
  1112. NULL);
  1113. //
  1114. // make sure that the selective suspend request has been completed.
  1115. //
  1116. KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
  1117. Executive,
  1118. KernelMode,
  1119. FALSE,
  1120. NULL);
  1121. }
  1122. }
  1123. ProcessQueuedRequests(deviceExtension);
  1124. ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName,
  1125. FALSE);
  1126. if(!NT_SUCCESS(ntStatus)) {
  1127. IsoUsb_DbgPrint(1, ("IoSetDeviceInterfaceState::disable:failed\n"));
  1128. }
  1129. RtlFreeUnicodeString(&deviceExtension->InterfaceName);
  1130. IsoUsb_AbortPipes(DeviceObject);
  1131. }
  1132. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  1133. SET_NEW_PNP_STATE(deviceExtension, Removed);
  1134. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  1135. IsoUsb_WmiDeRegistration(deviceExtension);
  1136. //
  1137. // need 2 decrements
  1138. //
  1139. IsoUsb_DbgPrint(3, ("HandleRemoveDevice::"));
  1140. requestCount = IsoUsb_IoDecrement(deviceExtension);
  1141. ASSERT(requestCount > 0);
  1142. IsoUsb_DbgPrint(3, ("HandleRemoveDevice::"));
  1143. requestCount = IsoUsb_IoDecrement(deviceExtension);
  1144. KeWaitForSingleObject(&deviceExtension->RemoveEvent,
  1145. Executive,
  1146. KernelMode,
  1147. FALSE,
  1148. NULL);
  1149. ReleaseMemory(DeviceObject);
  1150. //
  1151. // We need to send the remove down the stack before we detach,
  1152. // but we don't need to wait for the completion of this operation
  1153. // (and to register a completion routine).
  1154. //
  1155. Irp->IoStatus.Status = STATUS_SUCCESS;
  1156. Irp->IoStatus.Information = 0;
  1157. IoSkipCurrentIrpStackLocation(Irp);
  1158. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  1159. //
  1160. // Detach the FDO from the device stack
  1161. //
  1162. IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
  1163. IoDeleteDevice(DeviceObject);
  1164. IsoUsb_DbgPrint(3, ("HandleRemoveDevice - ends\n"));
  1165. return ntStatus;
  1166. }
  1167. NTSTATUS
  1168. HandleQueryCapabilities(
  1169. IN PDEVICE_OBJECT DeviceObject,
  1170. IN PIRP Irp
  1171. )
  1172. /*++
  1173. Routine Description:
  1174. This routine services Irp of minor type IRP_MN_QUERY_CAPABILITIES
  1175. Arguments:
  1176. DeviceObject - pointer to device object
  1177. Irp - I/O request packet sent by the pnp manager.
  1178. Return Value:
  1179. NT status value
  1180. --*/
  1181. {
  1182. ULONG i;
  1183. KEVENT event;
  1184. NTSTATUS ntStatus;
  1185. PDEVICE_EXTENSION deviceExtension;
  1186. PDEVICE_CAPABILITIES pdc;
  1187. PIO_STACK_LOCATION irpStack;
  1188. IsoUsb_DbgPrint(3, ("HandleQueryCapabilities - begins\n"));
  1189. //
  1190. // initialize variables
  1191. //
  1192. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1193. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1194. pdc = irpStack->Parameters.DeviceCapabilities.Capabilities;
  1195. //
  1196. // We will provide here an example of an IRP that is processed
  1197. // both on its way down and on its way up: there might be no need for
  1198. // a function driver process this Irp (the bus driver will do that).
  1199. // The driver will wait for the lower drivers (the bus driver among
  1200. // them) to process this IRP, then it processes it again.
  1201. //
  1202. if(pdc->Version < 1 || pdc->Size < sizeof(DEVICE_CAPABILITIES)) {
  1203. IsoUsb_DbgPrint(1, ("HandleQueryCapabilities::request failed\n"));
  1204. ntStatus = STATUS_UNSUCCESSFUL;
  1205. return ntStatus;
  1206. }
  1207. //
  1208. // Set some values in deviceCapabilities here...
  1209. //
  1210. //.............................................
  1211. //
  1212. //
  1213. // Prepare to pass the IRP down
  1214. //
  1215. //
  1216. // Add in the SurpriseRemovalOK bit before passing it down.
  1217. //
  1218. pdc->SurpriseRemovalOK = TRUE;
  1219. Irp->IoStatus.Status = STATUS_SUCCESS;
  1220. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1221. IoCopyCurrentIrpStackLocationToNext(Irp);
  1222. IoSetCompletionRoutine(Irp,
  1223. (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
  1224. (PVOID)&event,
  1225. TRUE,
  1226. TRUE,
  1227. TRUE);
  1228. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  1229. if(ntStatus == STATUS_PENDING) {
  1230. KeWaitForSingleObject(&event,
  1231. Executive,
  1232. KernelMode,
  1233. FALSE,
  1234. NULL);
  1235. ntStatus = Irp->IoStatus.Status;
  1236. }
  1237. //
  1238. // initialize PowerDownLevel to disabled
  1239. //
  1240. deviceExtension->PowerDownLevel = PowerDeviceUnspecified;
  1241. if(NT_SUCCESS(ntStatus)) {
  1242. deviceExtension->DeviceCapabilities = *pdc;
  1243. for(i = PowerSystemSleeping1; i <= PowerSystemSleeping3; i++) {
  1244. if(deviceExtension->DeviceCapabilities.DeviceState[i] <
  1245. PowerDeviceD3) {
  1246. deviceExtension->PowerDownLevel =
  1247. deviceExtension->DeviceCapabilities.DeviceState[i];
  1248. }
  1249. }
  1250. //
  1251. // since its safe to surprise-remove this device, we shall
  1252. // set the SurpriseRemoveOK flag to supress any dialog to
  1253. // user.
  1254. //
  1255. pdc->SurpriseRemovalOK = 1;
  1256. }
  1257. if(deviceExtension->PowerDownLevel == PowerDeviceUnspecified ||
  1258. deviceExtension->PowerDownLevel <= PowerDeviceD0) {
  1259. deviceExtension->PowerDownLevel = PowerDeviceD2;
  1260. }
  1261. IsoUsb_DbgPrint(3, ("HandleQueryCapabilities - ends\n"));
  1262. return ntStatus;
  1263. }
  1264. VOID
  1265. DpcRoutine(
  1266. IN PKDPC Dpc,
  1267. IN PVOID DeferredContext,
  1268. IN PVOID SystemArgument1,
  1269. IN PVOID SystemArgument2
  1270. )
  1271. /*++
  1272. Routine Description:
  1273. DPC routine triggered by the timer to check the idle state
  1274. of the device and submit an idle request for the device.
  1275. Arguments:
  1276. DeferredContext - context for the dpc routine.
  1277. DeviceObject in our case.
  1278. Return Value:
  1279. None
  1280. --*/
  1281. {
  1282. NTSTATUS ntStatus;
  1283. PDEVICE_OBJECT deviceObject;
  1284. PDEVICE_EXTENSION deviceExtension;
  1285. PIO_WORKITEM item;
  1286. IsoUsb_DbgPrint(3, ("DpcRoutine - begins\n"));
  1287. deviceObject = (PDEVICE_OBJECT)DeferredContext;
  1288. deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
  1289. //
  1290. // Clear this event since a DPC has been fired!
  1291. //
  1292. KeClearEvent(&deviceExtension->NoDpcWorkItemPendingEvent);
  1293. if(CanDeviceSuspend(deviceExtension)) {
  1294. IsoUsb_DbgPrint(3, ("Device is Idle\n"));
  1295. item = IoAllocateWorkItem(deviceObject);
  1296. if(item) {
  1297. IoQueueWorkItem(item,
  1298. IdleRequestWorkerRoutine,
  1299. DelayedWorkQueue,
  1300. item);
  1301. ntStatus = STATUS_PENDING;
  1302. }
  1303. else {
  1304. IsoUsb_DbgPrint(3, ("Cannot alloc memory for work item\n"));
  1305. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1306. //
  1307. // signal the NoDpcWorkItemPendingEvent.
  1308. //
  1309. KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent,
  1310. IO_NO_INCREMENT,
  1311. FALSE);
  1312. }
  1313. }
  1314. else {
  1315. IsoUsb_DbgPrint(3, ("Idle event not signaled\n"));
  1316. //
  1317. // signal the NoDpcWorkItemPendingEvent.
  1318. //
  1319. KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent,
  1320. IO_NO_INCREMENT,
  1321. FALSE);
  1322. }
  1323. IsoUsb_DbgPrint(3, ("DpcRoutine - ends\n"));
  1324. }
  1325. VOID
  1326. IdleRequestWorkerRoutine(
  1327. IN PDEVICE_OBJECT DeviceObject,
  1328. IN PVOID Context
  1329. )
  1330. /*++
  1331. Routine Description:
  1332. This is the work item fired from the DPC.
  1333. This workitem checks the idle state of the device
  1334. and submits an idle request.
  1335. Arguments:
  1336. DeviceObject - pointer to device object
  1337. Context - context for the work item.
  1338. Return Value:
  1339. None
  1340. --*/
  1341. {
  1342. PIRP irp;
  1343. NTSTATUS ntStatus;
  1344. PDEVICE_EXTENSION deviceExtension;
  1345. PIO_WORKITEM workItem;
  1346. IsoUsb_DbgPrint(3, ("IdleRequestWorkerRoutine - begins\n"));
  1347. //
  1348. // initialize variables
  1349. //
  1350. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1351. workItem = (PIO_WORKITEM) Context;
  1352. if(CanDeviceSuspend(deviceExtension)) {
  1353. IsoUsb_DbgPrint(3, ("Device is idle\n"));
  1354. ntStatus = SubmitIdleRequestIrp(deviceExtension);
  1355. if(!NT_SUCCESS(ntStatus)) {
  1356. IsoUsb_DbgPrint(1, ("SubmitIdleRequestIrp failed\n"));
  1357. }
  1358. }
  1359. else {
  1360. IsoUsb_DbgPrint(3, ("Device is not idle\n"));
  1361. }
  1362. IoFreeWorkItem(workItem);
  1363. //
  1364. // signal the NoDpcWorkItemPendingEvent.
  1365. //
  1366. KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent,
  1367. IO_NO_INCREMENT,
  1368. FALSE);
  1369. IsoUsb_DbgPrint(3, ("IdleRequestsWorkerRoutine - ends\n"));
  1370. }
  1371. VOID
  1372. ProcessQueuedRequests(
  1373. IN OUT PDEVICE_EXTENSION DeviceExtension
  1374. )
  1375. /*++
  1376. Routine Description:
  1377. Remove and process the entries in the queue. If this routine is called
  1378. when processing IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE
  1379. or IRP_MN_START_DEVICE, the requests are passed to the next lower driver.
  1380. If the routine is called when IRP_MN_REMOVE_DEVICE is received, the IRPs
  1381. are complete with STATUS_DELETE_PENDING
  1382. Arguments:
  1383. DeviceExtension - pointer to device extension
  1384. Return Value:
  1385. None
  1386. --*/
  1387. {
  1388. KIRQL oldIrql;
  1389. PIRP nextIrp,
  1390. cancelledIrp;
  1391. PVOID cancelRoutine;
  1392. LIST_ENTRY cancelledIrpList;
  1393. PLIST_ENTRY listEntry;
  1394. IsoUsb_DbgPrint(3, ("ProcessQueuedRequests - begins\n"));
  1395. //
  1396. // initialize variables
  1397. //
  1398. cancelRoutine = NULL;
  1399. InitializeListHead(&cancelledIrpList);
  1400. //
  1401. // 1. dequeue the entries in the queue
  1402. // 2. reset the cancel routine
  1403. // 3. process them
  1404. // 3a. if the device is active, send them down
  1405. // 3b. else complete with STATUS_DELETE_PENDING
  1406. //
  1407. while(1) {
  1408. KeAcquireSpinLock(&DeviceExtension->QueueLock, &oldIrql);
  1409. if(IsListEmpty(&DeviceExtension->NewRequestsQueue)) {
  1410. KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
  1411. break;
  1412. }
  1413. //
  1414. // Remove a request from the queue
  1415. //
  1416. listEntry = RemoveHeadList(&DeviceExtension->NewRequestsQueue);
  1417. nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  1418. //
  1419. // set the cancel routine to NULL
  1420. //
  1421. cancelRoutine = IoSetCancelRoutine(nextIrp, NULL);
  1422. //
  1423. // check if its already cancelled
  1424. //
  1425. if(nextIrp->Cancel) {
  1426. if(cancelRoutine) {
  1427. //
  1428. // the cancel routine for this IRP hasnt been called yet
  1429. // so queue the IRP in the cancelledIrp list and complete
  1430. // after releasing the lock
  1431. //
  1432. InsertTailList(&cancelledIrpList, listEntry);
  1433. }
  1434. else {
  1435. //
  1436. // the cancel routine has run
  1437. // it must be waiting to hold the queue lock
  1438. // so initialize the IRPs listEntry
  1439. //
  1440. InitializeListHead(listEntry);
  1441. }
  1442. KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
  1443. }
  1444. else {
  1445. KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
  1446. if(FailRequests == DeviceExtension->QueueState) {
  1447. nextIrp->IoStatus.Information = 0;
  1448. nextIrp->IoStatus.Status = STATUS_DELETE_PENDING;
  1449. IoCompleteRequest(nextIrp, IO_NO_INCREMENT);
  1450. }
  1451. else {
  1452. PIO_STACK_LOCATION irpStack;
  1453. IsoUsb_DbgPrint(3, ("ProcessQueuedRequests::"));
  1454. IsoUsb_IoIncrement(DeviceExtension);
  1455. IoSkipCurrentIrpStackLocation(nextIrp);
  1456. IoCallDriver(DeviceExtension->TopOfStackDeviceObject, nextIrp);
  1457. IsoUsb_DbgPrint(3, ("ProcessQueuedRequests::"));
  1458. IsoUsb_IoDecrement(DeviceExtension);
  1459. }
  1460. }
  1461. } // while loop
  1462. //
  1463. // walk through the cancelledIrp list and cancel them
  1464. //
  1465. while(!IsListEmpty(&cancelledIrpList)) {
  1466. PLIST_ENTRY cancelEntry = RemoveHeadList(&cancelledIrpList);
  1467. cancelledIrp = CONTAINING_RECORD(cancelEntry, IRP, Tail.Overlay.ListEntry);
  1468. cancelledIrp->IoStatus.Status = STATUS_CANCELLED;
  1469. cancelledIrp->IoStatus.Information = 0;
  1470. IoCompleteRequest(cancelledIrp, IO_NO_INCREMENT);
  1471. }
  1472. IsoUsb_DbgPrint(3, ("ProcessQueuedRequests - ends\n"));
  1473. return;
  1474. }
  1475. VOID
  1476. GetBusInterfaceVersion(
  1477. IN PDEVICE_OBJECT DeviceObject
  1478. )
  1479. /*++
  1480. Routine Description:
  1481. This routine queries the bus interface version
  1482. Arguments:
  1483. DeviceExtension
  1484. Return Value:
  1485. VOID
  1486. --*/
  1487. {
  1488. PIRP irp;
  1489. KEVENT event;
  1490. NTSTATUS ntStatus;
  1491. PDEVICE_EXTENSION deviceExtension;
  1492. PIO_STACK_LOCATION nextStack;
  1493. USB_BUS_INTERFACE_USBDI_V1 busInterfaceVer1;
  1494. //
  1495. // initialize vars
  1496. //
  1497. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1498. IsoUsb_DbgPrint(3, ("GetBusInterfaceVersion - begins\n"));
  1499. irp = IoAllocateIrp(deviceExtension->TopOfStackDeviceObject->StackSize,
  1500. FALSE);
  1501. if(NULL == irp) {
  1502. IsoUsb_DbgPrint(1, ("Failed to alloc irp in GetBusInterfaceVersion\n"));
  1503. return;
  1504. }
  1505. //
  1506. // All pnp Irp's need the status field initialized to
  1507. // STATUS_NOT_SUPPORTED
  1508. //
  1509. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1510. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1511. IoSetCompletionRoutine(irp,
  1512. (PIO_COMPLETION_ROUTINE) IrpCompletionRoutine,
  1513. &event,
  1514. TRUE,
  1515. TRUE,
  1516. TRUE);
  1517. nextStack = IoGetNextIrpStackLocation(irp);
  1518. ASSERT(nextStack);
  1519. nextStack->MajorFunction = IRP_MJ_PNP;
  1520. nextStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  1521. //
  1522. // Allocate memory for an interface of type
  1523. // USB_BUS_INTERFACE_USBDI_V0 and have the IRP point to it:
  1524. //
  1525. nextStack->Parameters.QueryInterface.Interface =
  1526. (PINTERFACE) &busInterfaceVer1;
  1527. //
  1528. // Assign the InterfaceSpecificData member of the IRP to be NULL
  1529. //
  1530. nextStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  1531. //
  1532. // Set the interface type to the appropriate GUID
  1533. //
  1534. nextStack->Parameters.QueryInterface.InterfaceType =
  1535. &USB_BUS_INTERFACE_USBDI_GUID;
  1536. //
  1537. // Set the size and version of interface in the IRP
  1538. // Currently, there is only one valid version of
  1539. // this interface available to clients.
  1540. //
  1541. nextStack->Parameters.QueryInterface.Size =
  1542. sizeof(USB_BUS_INTERFACE_USBDI_V1);
  1543. nextStack->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_1;
  1544. IsoUsb_IoIncrement(deviceExtension);
  1545. ntStatus = IoCallDriver(DeviceObject,
  1546. irp);
  1547. if(STATUS_PENDING == ntStatus) {
  1548. KeWaitForSingleObject(&event,
  1549. Executive,
  1550. KernelMode,
  1551. FALSE,
  1552. NULL);
  1553. ntStatus = irp->IoStatus.Status;
  1554. }
  1555. if(NT_SUCCESS(ntStatus)) {
  1556. deviceExtension->IsDeviceHighSpeed =
  1557. busInterfaceVer1.IsDeviceHighSpeed(
  1558. busInterfaceVer1.BusContext);
  1559. IsoUsb_DbgPrint(1, ("IsDeviceHighSpeed = %x\n",
  1560. deviceExtension->IsDeviceHighSpeed));
  1561. }
  1562. IoFreeIrp(irp);
  1563. IsoUsb_DbgPrint(3, ("GetBusInterfaceVersion::"));
  1564. IsoUsb_IoDecrement(deviceExtension);
  1565. IsoUsb_DbgPrint(3, ("GetBusInterfaceVersion - ends\n"));
  1566. }
  1567. NTSTATUS
  1568. IrpCompletionRoutine(
  1569. IN PDEVICE_OBJECT DeviceObject,
  1570. IN PIRP Irp,
  1571. IN PVOID Context
  1572. )
  1573. /*++
  1574. Routine Description:
  1575. This routine is a completion routine.
  1576. In this routine we set an event.
  1577. Since the completion routine returns
  1578. STATUS_MORE_PROCESSING_REQUIRED, the Irps,
  1579. which set this routine as the completion routine,
  1580. should be marked pending.
  1581. Arguments:
  1582. DeviceObject - pointer to device object
  1583. Irp - I/O request packet
  1584. Context -
  1585. Return Value:
  1586. NT status value
  1587. --*/
  1588. {
  1589. PKEVENT event = Context;
  1590. KeSetEvent(event, 0, FALSE);
  1591. return STATUS_MORE_PROCESSING_REQUIRED;
  1592. }
  1593. NTSTATUS
  1594. IsoUsb_GetRegistryDword(
  1595. IN PWCHAR RegPath,
  1596. IN PWCHAR ValueName,
  1597. IN OUT PULONG Value
  1598. )
  1599. /*++
  1600. Routine Description:
  1601. This routine reads the specified reqistry value.
  1602. Arguments:
  1603. RegPath - registry path
  1604. ValueName - property to be fetched from the registry
  1605. Value - corresponding value read from the registry.
  1606. Return Value:
  1607. NT status value
  1608. --*/
  1609. {
  1610. ULONG defaultData;
  1611. WCHAR buffer[MAXIMUM_FILENAME_LENGTH];
  1612. NTSTATUS ntStatus;
  1613. UNICODE_STRING regPath;
  1614. RTL_QUERY_REGISTRY_TABLE paramTable[2];
  1615. IsoUsb_DbgPrint(3, ("IsoUsb_GetRegistryDword - begins\n"));
  1616. regPath.Length = 0;
  1617. regPath.MaximumLength = MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR);
  1618. regPath.Buffer = buffer;
  1619. RtlZeroMemory(regPath.Buffer, regPath.MaximumLength);
  1620. RtlMoveMemory(regPath.Buffer,
  1621. RegPath,
  1622. wcslen(RegPath) * sizeof(WCHAR));
  1623. RtlZeroMemory(paramTable, sizeof(paramTable));
  1624. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1625. paramTable[0].Name = ValueName;
  1626. paramTable[0].EntryContext = Value;
  1627. paramTable[0].DefaultType = REG_DWORD;
  1628. paramTable[0].DefaultData = &defaultData;
  1629. paramTable[0].DefaultLength = sizeof(ULONG);
  1630. ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE |
  1631. RTL_REGISTRY_OPTIONAL,
  1632. regPath.Buffer,
  1633. paramTable,
  1634. NULL,
  1635. NULL);
  1636. if(NT_SUCCESS(ntStatus)) {
  1637. IsoUsb_DbgPrint(3, ("success Value = %X\n", *Value));
  1638. return STATUS_SUCCESS;
  1639. }
  1640. else {
  1641. *Value = 0;
  1642. return STATUS_UNSUCCESSFUL;
  1643. }
  1644. }
  1645. NTSTATUS
  1646. IsoUsb_AbortPipes(
  1647. IN PDEVICE_OBJECT DeviceObject
  1648. )
  1649. /*++
  1650. Routine Description:
  1651. This routine sends an irp/urb pair with
  1652. URB_FUNCTION_ABORT_PIPE request down the stack
  1653. Arguments:
  1654. DeviceObject - pointer to device object
  1655. Return Value:
  1656. NT status value
  1657. --*/
  1658. {
  1659. PURB urb;
  1660. ULONG i;
  1661. NTSTATUS ntStatus;
  1662. PDEVICE_EXTENSION deviceExtension;
  1663. PUSBD_PIPE_INFORMATION pipeInformation;
  1664. PUSBD_INTERFACE_INFORMATION interfaceInfo;
  1665. //
  1666. // initialize variables
  1667. //
  1668. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1669. interfaceInfo = deviceExtension->UsbInterface;
  1670. IsoUsb_DbgPrint(3, ("IsoUsb_AbortPipes - begins\n"));
  1671. if(interfaceInfo == NULL) {
  1672. return STATUS_SUCCESS;
  1673. }
  1674. for(i = 0; i < interfaceInfo->NumberOfPipes; i++) {
  1675. urb = ExAllocatePool(NonPagedPool,
  1676. sizeof(struct _URB_PIPE_REQUEST));
  1677. if(urb) {
  1678. urb->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST);
  1679. urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
  1680. urb->UrbPipeRequest.PipeHandle =
  1681. interfaceInfo->Pipes[i].PipeHandle;
  1682. ntStatus = CallUSBD(DeviceObject, urb);
  1683. ExFreePool(urb);
  1684. }
  1685. else {
  1686. IsoUsb_DbgPrint(1, ("Failed to alloc memory for urb for input pipe\n"));
  1687. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1688. return ntStatus;
  1689. }
  1690. }
  1691. IsoUsb_DbgPrint(3, ("IsoUsb_AbortPipes - ends\n"));
  1692. return STATUS_SUCCESS;
  1693. }
  1694. NTSTATUS
  1695. IsoUsb_DispatchClean(
  1696. IN PDEVICE_OBJECT DeviceObject,
  1697. IN PIRP Irp
  1698. )
  1699. /*++
  1700. Routine Description:
  1701. Dispatch routine for IRP_MJ_CLEANUP
  1702. Arguments:
  1703. DeviceObject - pointer to device object
  1704. Irp - I/O request packet sent by the pnp manager
  1705. Return Value:
  1706. NT status value
  1707. --*/
  1708. {
  1709. PDEVICE_EXTENSION deviceExtension;
  1710. KIRQL oldIrql;
  1711. LIST_ENTRY cleanupList;
  1712. PLIST_ENTRY thisEntry,
  1713. nextEntry,
  1714. listHead;
  1715. PIRP pendingIrp;
  1716. PIO_STACK_LOCATION pendingIrpStack,
  1717. irpStack;
  1718. NTSTATUS ntStatus;
  1719. PFILE_OBJECT fileObject;
  1720. PFILE_OBJECT_CONTENT fileObjectContent;
  1721. PISOUSB_STREAM_OBJECT tempStreamObject;
  1722. //
  1723. // initialize variables
  1724. //
  1725. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1726. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1727. fileObject = irpStack->FileObject;
  1728. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchClean::"));
  1729. IsoUsb_IoIncrement(deviceExtension);
  1730. //
  1731. // check if any stream objects need to be cleaned
  1732. //
  1733. if(fileObject && fileObject->FsContext) {
  1734. fileObjectContent = (PFILE_OBJECT_CONTENT)
  1735. fileObject->FsContext;
  1736. if(fileObjectContent->StreamInformation) {
  1737. tempStreamObject = (PISOUSB_STREAM_OBJECT)
  1738. InterlockedExchangePointer(
  1739. &fileObjectContent->StreamInformation,
  1740. NULL);
  1741. if(tempStreamObject &&
  1742. (tempStreamObject->DeviceObject == DeviceObject)) {
  1743. IsoUsb_DbgPrint(3, ("clean dispatch routine"
  1744. " found a stream object match\n"));
  1745. IsoUsb_StreamObjectCleanup(tempStreamObject, deviceExtension);
  1746. }
  1747. }
  1748. }
  1749. InitializeListHead(&cleanupList);
  1750. //
  1751. // acquire queue lock
  1752. //
  1753. KeAcquireSpinLock(&deviceExtension->QueueLock, &oldIrql);
  1754. //
  1755. // remove all Irp's that belong to input Irp's fileobject
  1756. //
  1757. listHead = &deviceExtension->NewRequestsQueue;
  1758. for(thisEntry = listHead->Flink, nextEntry = thisEntry->Flink;
  1759. thisEntry != listHead;
  1760. thisEntry = nextEntry, nextEntry = thisEntry->Flink) {
  1761. pendingIrp = CONTAINING_RECORD(thisEntry, IRP, Tail.Overlay.ListEntry);
  1762. pendingIrpStack = IoGetCurrentIrpStackLocation(pendingIrp);
  1763. if(irpStack->FileObject == pendingIrpStack->FileObject) {
  1764. RemoveEntryList(thisEntry);
  1765. //
  1766. // set the cancel routine to NULL
  1767. //
  1768. if(NULL == IoSetCancelRoutine(pendingIrp, NULL)) {
  1769. InitializeListHead(thisEntry);
  1770. }
  1771. else {
  1772. InsertTailList(&cleanupList, thisEntry);
  1773. }
  1774. }
  1775. }
  1776. //
  1777. // Release the spin lock
  1778. //
  1779. KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql);
  1780. //
  1781. // walk thru the cleanup list and cancel all the Irps
  1782. //
  1783. while(!IsListEmpty(&cleanupList)) {
  1784. //
  1785. // complete the Irp
  1786. //
  1787. thisEntry = RemoveHeadList(&cleanupList);
  1788. pendingIrp = CONTAINING_RECORD(thisEntry, IRP, Tail.Overlay.ListEntry);
  1789. pendingIrp->IoStatus.Information = 0;
  1790. pendingIrp->IoStatus.Status = STATUS_CANCELLED;
  1791. IoCompleteRequest(pendingIrp, IO_NO_INCREMENT);
  1792. }
  1793. Irp->IoStatus.Information = 0;
  1794. Irp->IoStatus.Status = STATUS_SUCCESS;
  1795. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1796. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchClean::"));
  1797. IsoUsb_IoDecrement(deviceExtension);
  1798. return STATUS_SUCCESS;
  1799. }
  1800. BOOLEAN
  1801. CanDeviceSuspend(
  1802. IN PDEVICE_EXTENSION DeviceExtension
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. This is the routine where we check if the device
  1807. can selectively suspend.
  1808. Arguments:
  1809. DeviceExtension - pointer to device extension
  1810. Return Value:
  1811. TRUE - if the device can suspend
  1812. FALSE - otherwise.
  1813. --*/
  1814. {
  1815. IsoUsb_DbgPrint(3, ("CanDeviceSuspend\n"));
  1816. if((DeviceExtension->OpenHandleCount == 0) &&
  1817. (DeviceExtension->OutStandingIO == 1)) {
  1818. return TRUE;
  1819. }
  1820. else {
  1821. return FALSE;
  1822. }
  1823. }
  1824. LONG
  1825. IsoUsb_IoIncrement(
  1826. IN OUT PDEVICE_EXTENSION DeviceExtension
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. This routine bumps up the I/O count.
  1831. This routine is typically invoked when any of the
  1832. dispatch routines handle new irps for the driver.
  1833. Arguments:
  1834. DeviceExtension - pointer to device extension
  1835. Return Value:
  1836. new value
  1837. --*/
  1838. {
  1839. LONG result = 0;
  1840. KIRQL oldIrql;
  1841. KeAcquireSpinLock(&DeviceExtension->IOCountLock, &oldIrql);
  1842. result = InterlockedIncrement(&DeviceExtension->OutStandingIO);
  1843. //
  1844. // when OutStandingIO bumps from 1 to 2, clear the StopEvent
  1845. //
  1846. if(result == 2) {
  1847. KeClearEvent(&DeviceExtension->StopEvent);
  1848. }
  1849. KeReleaseSpinLock(&DeviceExtension->IOCountLock, oldIrql);
  1850. IsoUsb_DbgPrint(3, ("IsoUsb_IoIncrement::%d\n", result));
  1851. return result;
  1852. }
  1853. LONG
  1854. IsoUsb_IoDecrement(
  1855. IN OUT PDEVICE_EXTENSION DeviceExtension
  1856. )
  1857. /*++
  1858. Routine Description:
  1859. This routine decrements the outstanding I/O count
  1860. This is typically invoked after the dispatch routine
  1861. has finished processing the irp.
  1862. Arguments:
  1863. DeviceExtension - pointer to device extension
  1864. Return Value:
  1865. new value
  1866. --*/
  1867. {
  1868. LONG result = 0;
  1869. KIRQL oldIrql;
  1870. KeAcquireSpinLock(&DeviceExtension->IOCountLock, &oldIrql);
  1871. result = InterlockedDecrement(&DeviceExtension->OutStandingIO);
  1872. if(result == 1) {
  1873. KeSetEvent(&DeviceExtension->StopEvent, IO_NO_INCREMENT, FALSE);
  1874. }
  1875. if(result == 0) {
  1876. ASSERT(Removed == DeviceExtension->DeviceState);
  1877. KeSetEvent(&DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE);
  1878. }
  1879. KeReleaseSpinLock(&DeviceExtension->IOCountLock, oldIrql);
  1880. IsoUsb_DbgPrint(3, ("IsoUsb_IoDecrement::%d\n", result));
  1881. return result;
  1882. }
  1883. NTSTATUS
  1884. CanStopDevice(
  1885. IN PDEVICE_OBJECT DeviceObject,
  1886. IN PIRP Irp
  1887. )
  1888. /*++
  1889. Routine Description:
  1890. This routine determines whether the device can be safely stopped. In our
  1891. particular case, we'll assume we can always stop the device.
  1892. A device might fail the request if it doesn't have a queue for the
  1893. requests it might come or if it was notified that it is in the paging
  1894. path.
  1895. Arguments:
  1896. DeviceObject - pointer to the device object.
  1897. Irp - pointer to the current IRP.
  1898. Return Value:
  1899. STATUS_SUCCESS if the device can be safely stopped, an appropriate
  1900. NT Status if not.
  1901. --*/
  1902. {
  1903. //
  1904. // We assume we can stop the device
  1905. //
  1906. UNREFERENCED_PARAMETER(DeviceObject);
  1907. UNREFERENCED_PARAMETER(Irp);
  1908. return STATUS_SUCCESS;
  1909. }
  1910. NTSTATUS
  1911. CanRemoveDevice(
  1912. IN PDEVICE_OBJECT DeviceObject,
  1913. IN PIRP Irp
  1914. )
  1915. /*++
  1916. Routine Description:
  1917. This routine determines whether the device can be safely removed. In our
  1918. particular case, we'll assume we can always remove the device.
  1919. A device shouldn't be removed if, for example, it has open handles or
  1920. removing the device could result in losing data (plus the reasons
  1921. mentioned at CanStopDevice). The PnP manager on Windows 2000 fails
  1922. on its own any attempt to remove, if there any open handles to the device.
  1923. However on Win9x, the driver must keep count of open handles and fail
  1924. query_remove if there are any open handles.
  1925. Arguments:
  1926. DeviceObject - pointer to the device object.
  1927. Irp - pointer to the current IRP.
  1928. Return Value:
  1929. STATUS_SUCCESS if the device can be safely removed, an appropriate
  1930. NT Status if not.
  1931. --*/
  1932. {
  1933. //
  1934. // We assume we can remove the device
  1935. //
  1936. UNREFERENCED_PARAMETER(DeviceObject);
  1937. UNREFERENCED_PARAMETER(Irp);
  1938. return STATUS_SUCCESS;
  1939. }
  1940. NTSTATUS
  1941. ReleaseMemory(
  1942. IN PDEVICE_OBJECT DeviceObject
  1943. )
  1944. /*++
  1945. Routine Description:
  1946. This routine returns all the memory allocations acquired during
  1947. device startup.
  1948. Arguments:
  1949. DeviceObject - pointer to the device object.
  1950. Return Value:
  1951. STATUS_SUCCESS if the device can be safely removed, an appropriate
  1952. NT Status if not.
  1953. --*/
  1954. {
  1955. //
  1956. // Disconnect from the interrupt and unmap any I/O ports
  1957. //
  1958. PDEVICE_EXTENSION deviceExtension;
  1959. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1960. if(deviceExtension->UsbConfigurationDescriptor) {
  1961. ExFreePool(deviceExtension->UsbConfigurationDescriptor);
  1962. deviceExtension->UsbConfigurationDescriptor = NULL;
  1963. }
  1964. if(deviceExtension->UsbInterface) {
  1965. ExFreePool(deviceExtension->UsbInterface);
  1966. deviceExtension->UsbInterface = NULL;
  1967. }
  1968. return STATUS_SUCCESS;
  1969. }
  1970. PCHAR
  1971. PnPMinorFunctionString (
  1972. UCHAR MinorFunction
  1973. )
  1974. /*++
  1975. Routine Description:
  1976. Arguments:
  1977. Return Value:
  1978. --*/
  1979. {
  1980. switch (MinorFunction) {
  1981. case IRP_MN_START_DEVICE:
  1982. return "IRP_MN_START_DEVICE\n";
  1983. case IRP_MN_QUERY_REMOVE_DEVICE:
  1984. return "IRP_MN_QUERY_REMOVE_DEVICE\n";
  1985. case IRP_MN_REMOVE_DEVICE:
  1986. return "IRP_MN_REMOVE_DEVICE\n";
  1987. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1988. return "IRP_MN_CANCEL_REMOVE_DEVICE\n";
  1989. case IRP_MN_STOP_DEVICE:
  1990. return "IRP_MN_STOP_DEVICE\n";
  1991. case IRP_MN_QUERY_STOP_DEVICE:
  1992. return "IRP_MN_QUERY_STOP_DEVICE\n";
  1993. case IRP_MN_CANCEL_STOP_DEVICE:
  1994. return "IRP_MN_CANCEL_STOP_DEVICE\n";
  1995. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1996. return "IRP_MN_QUERY_DEVICE_RELATIONS\n";
  1997. case IRP_MN_QUERY_INTERFACE:
  1998. return "IRP_MN_QUERY_INTERFACE\n";
  1999. case IRP_MN_QUERY_CAPABILITIES:
  2000. return "IRP_MN_QUERY_CAPABILITIES\n";
  2001. case IRP_MN_QUERY_RESOURCES:
  2002. return "IRP_MN_QUERY_RESOURCES\n";
  2003. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  2004. return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n";
  2005. case IRP_MN_QUERY_DEVICE_TEXT:
  2006. return "IRP_MN_QUERY_DEVICE_TEXT\n";
  2007. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  2008. return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n";
  2009. case IRP_MN_READ_CONFIG:
  2010. return "IRP_MN_READ_CONFIG\n";
  2011. case IRP_MN_WRITE_CONFIG:
  2012. return "IRP_MN_WRITE_CONFIG\n";
  2013. case IRP_MN_EJECT:
  2014. return "IRP_MN_EJECT\n";
  2015. case IRP_MN_SET_LOCK:
  2016. return "IRP_MN_SET_LOCK\n";
  2017. case IRP_MN_QUERY_ID:
  2018. return "IRP_MN_QUERY_ID\n";
  2019. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  2020. return "IRP_MN_QUERY_PNP_DEVICE_STATE\n";
  2021. case IRP_MN_QUERY_BUS_INFORMATION:
  2022. return "IRP_MN_QUERY_BUS_INFORMATION\n";
  2023. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  2024. return "IRP_MN_DEVICE_USAGE_NOTIFICATION\n";
  2025. case IRP_MN_SURPRISE_REMOVAL:
  2026. return "IRP_MN_SURPRISE_REMOVAL\n";
  2027. default:
  2028. return "IRP_MN_?????\n";
  2029. }
  2030. }