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