isopnp.c
上传用户:leituo004
上传日期:2014-11-03
资源大小:159k
文件大小:73k
源码类别:

驱动编程

开发平台:

Visual C++

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