xref: /reactos/drivers/bluetooth/fbtusb/fbtdev.c (revision 1734f297)
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 "fbtusb.h"
14 #include "fbtpnp.h"
15 #include "fbtpwr.h"
16 #include "fbtdev.h"
17 #include "fbtwmi.h"
18 #include "fbtrwr.h"
19 
20 #include "fbtusr.h"
21 
22 // Dispatch routine for CreateHandle
23 NTSTATUS NTAPI FreeBT_DispatchCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
24 {
25     //ULONG                       i;
26     NTSTATUS                    ntStatus;
27     PFILE_OBJECT                fileObject;
28     PDEVICE_EXTENSION           deviceExtension;
29     PIO_STACK_LOCATION          irpStack;
30     //PFREEBT_PIPE_CONTEXT        pipeContext;
31     PUSBD_INTERFACE_INFORMATION interface;
32 
33     PAGED_CODE();
34 
35     FreeBT_DbgPrint(3, ("FreeBT_DispatchCreate: Entered\n"));
36 
37     irpStack = IoGetCurrentIrpStackLocation(Irp);
38     fileObject = irpStack->FileObject;
39     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
40 
41     if (deviceExtension->DeviceState != Working)
42     {
43         ntStatus = STATUS_INVALID_DEVICE_STATE;
44         goto FreeBT_DispatchCreate_Exit;
45 
46     }
47 
48     if (deviceExtension->UsbInterface)
49     {
50         interface = deviceExtension->UsbInterface;
51 
52     }
53 
54     else
55     {
56         FreeBT_DbgPrint(1, ("UsbInterface not found\n"));
57         ntStatus = STATUS_INVALID_DEVICE_STATE;
58         goto FreeBT_DispatchCreate_Exit;
59 
60     }
61 
62     if (fileObject)
63     {
64         fileObject->FsContext = NULL;
65     }
66 
67     else
68     {
69         ntStatus = STATUS_INVALID_PARAMETER;
70         goto FreeBT_DispatchCreate_Exit;
71 
72     }
73 
74     if (deviceExtension->OpenHandleCount>0)
75     {
76         ntStatus = STATUS_ACCESS_VIOLATION;
77         goto FreeBT_DispatchCreate_Exit;
78 
79     }
80 
81     // opening a device as opposed to pipe.
82     ntStatus = STATUS_SUCCESS;
83 
84     InterlockedIncrement(&deviceExtension->OpenHandleCount);
85 
86     // the device is idle if it has no open handles or pending PnP Irps
87     // since we just received an open handle request, cancel idle req.
88     if (deviceExtension->SSEnable)
89         CancelSelectSuspend(deviceExtension);
90 
91 FreeBT_DispatchCreate_Exit:
92     Irp->IoStatus.Status = ntStatus;
93     Irp->IoStatus.Information = 0;
94     IoCompleteRequest(Irp, IO_NO_INCREMENT);
95 
96     FreeBT_DbgPrint(3, ("FreeBT_DispatchCreate: Leaving\n"));
97     return ntStatus;
98 
99 }
100 
101 // Dispatch routine for CloseHandle
102 NTSTATUS NTAPI FreeBT_DispatchClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
103 {
104     NTSTATUS               ntStatus;
105     PFILE_OBJECT           fileObject;
106     PDEVICE_EXTENSION      deviceExtension;
107     PIO_STACK_LOCATION     irpStack;
108     //PFREEBT_PIPE_CONTEXT  pipeContext;
109     //PUSBD_PIPE_INFORMATION pipeInformation;
110 
111     PAGED_CODE();
112 
113     irpStack = IoGetCurrentIrpStackLocation(Irp);
114     fileObject = irpStack->FileObject;
115     //pipeContext = NULL;
116     //pipeInformation = NULL;
117     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
118 
119     FreeBT_DbgPrint(3, ("FreeBT_DispatchClose: Entered\n"));
120 
121     ntStatus = STATUS_SUCCESS;
122     Irp->IoStatus.Status = ntStatus;
123     Irp->IoStatus.Information = 0;
124     IoCompleteRequest(Irp, IO_NO_INCREMENT);
125 
126     InterlockedDecrement(&deviceExtension->OpenHandleCount);
127 
128     FreeBT_DbgPrint(3, ("FreeBT_DispatchClose: Leaving\n"));
129 
130     return ntStatus;
131 
132 }
133 
134 // Called when a HCI Send on the control pipe completes
135 NTSTATUS NTAPI FreeBT_HCISendCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
136 {
137     //ULONG               stageLength;
138     NTSTATUS            ntStatus;
139 
140     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_HCISendCompletion, status=0x%08X\n", Irp->IoStatus.Status));
141 
142     if (Irp->PendingReturned)
143         IoMarkIrpPending(Irp);
144 
145     ExFreePool(Context);
146     FreeBT_IoDecrement(DeviceObject->DeviceExtension);
147     ntStatus = Irp->IoStatus.Status;
148     Irp->IoStatus.Information = 0;
149 
150     return ntStatus;
151 
152 }
153 
154 // Called the DeviceIOControl handler to send an HCI command received from the user
155 // HCI Commands are sent on the (default) control pipe
156 NTSTATUS NTAPI FreeBT_SendHCICommand(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID IoBuffer, IN ULONG InputBufferLength)
157 {
158     PDEVICE_EXTENSION   deviceExtension;
159     //ULONG               urbFlags;
160     //ULONG               stageLength;
161     //PVOID               pBuffer;
162     PURB                urb;
163     NTSTATUS            ntStatus;
164     PIO_STACK_LOCATION  nextStack;
165     //PFBT_HCI_CMD_HEADER pHCICommand;
166     //LARGE_INTEGER       delay;
167 
168     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
169     if (!deviceExtension)
170     {
171         ntStatus=STATUS_INVALID_PARAMETER;
172         FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Failed to get DeviceExtension\n"));
173         Irp->IoStatus.Status = ntStatus;
174         Irp->IoStatus.Information = 0;
175         IoCompleteRequest(Irp, IO_NO_INCREMENT);
176         return ntStatus;
177 
178     }
179 
180     // The user is doing a reset, reset all the pipes as well, so that any
181     // old events or data are removed
182     /*pHCICommand=(PFBT_HCI_CMD_HEADER)IoBuffer;
183     if (pHCICommand->OpCode==FBT_HCI_CMD_RESET)
184     {
185         FreeBT_ResetPipe(DeviceObject, deviceExtension->EventPipe.PipeHandle);
186         FreeBT_ResetPipe(DeviceObject, deviceExtension->DataInPipe.PipeHandle);
187         FreeBT_ResetPipe(DeviceObject, deviceExtension->DataOutPipe.PipeHandle);
188         FreeBT_ResetPipe(DeviceObject, deviceExtension->AudioInPipe.PipeHandle);
189         FreeBT_ResetPipe(DeviceObject, deviceExtension->AudioOutPipe.PipeHandle);
190 
191         // Wait a second for the device to recover
192         FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Sleeping\n"));
193         delay.QuadPart = -10000 * 5000; // 5s
194         KeWaitForSingleObject(&deviceExtension->DelayEvent,
195                               Executive,
196                               UserMode,
197                               FALSE,
198                               &delay);
199 
200         FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Finished sleeping\n"));
201 
202 
203     }*/
204 
205     // Create the URB
206     urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
207     if(urb == NULL)
208     {
209         FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Failed to alloc mem for urb\n"));
210         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
211         Irp->IoStatus.Status = ntStatus;
212         Irp->IoStatus.Information = 0;
213         IoCompleteRequest(Irp, IO_NO_INCREMENT);
214         return ntStatus;
215 
216     }
217 
218     UsbBuildVendorRequest(
219         urb,
220         URB_FUNCTION_CLASS_DEVICE, // This works, for CSR and Silicon Wave
221         sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
222         0,
223         0,
224         0,
225         0,
226         0,
227         IoBuffer,
228         NULL,
229         InputBufferLength,
230         NULL);
231 
232     // use the original irp as an internal device control irp
233     nextStack = IoGetNextIrpStackLocation(Irp);
234     nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
235     nextStack->Parameters.Others.Argument1 = (PVOID) urb;
236     nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
237 
238     IoSetCompletionRoutine(
239         Irp,
240         (PIO_COMPLETION_ROUTINE)FreeBT_HCISendCompletion,
241         urb,
242         TRUE,
243         TRUE,
244         TRUE);
245 
246     // We return STATUS_PENDING; call IoMarkIrpPending.
247     IoMarkIrpPending(Irp);
248 
249     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand::"));
250     FreeBT_IoIncrement(deviceExtension);
251 
252     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: Sending IRP %X to underlying driver\n", Irp));
253     ntStatus=IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
254     if(!NT_SUCCESS(ntStatus))
255     {
256         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: IoCallDriver fails with status %X\n", ntStatus));
257 
258         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand::"));
259         FreeBT_IoDecrement(deviceExtension);
260 
261         // If the device was surprise removed out, the pipeInformation field is invalid.
262         // similarly if the request was cancelled, then we need not reset the device.
263         if((ntStatus != STATUS_CANCELLED) && (ntStatus != STATUS_DEVICE_NOT_CONNECTED))
264             ntStatus = FreeBT_ResetDevice(DeviceObject);
265 
266         else
267             FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n"));
268 
269         Irp->IoStatus.Status = ntStatus;
270         Irp->IoStatus.Information = 0;
271         IoCompleteRequest(Irp, IO_NO_INCREMENT);
272 
273         return ntStatus;
274 
275     }
276 
277     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: Completed successfully\n"));
278 
279     return STATUS_PENDING;
280 
281 }
282 
283 // Called when a HCI Get on the event pipe completes
284 NTSTATUS NTAPI FreeBT_HCIEventCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
285 {
286     //ULONG               stageLength;
287     NTSTATUS            ntStatus;
288     PIO_STACK_LOCATION  nextStack;
289     PURB                urb;
290 
291     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_HCIEventCompletion, status=0x%08X\n", Irp->IoStatus.Status));
292 
293     if (Irp->PendingReturned)
294         IoMarkIrpPending(Irp);
295 
296     // initialize variables
297     urb=(PURB)Context;
298     ntStatus = Irp->IoStatus.Status;
299     Irp->IoStatus.Information = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
300     nextStack = IoGetNextIrpStackLocation(Irp);
301 
302     ExFreePool(Context);
303     FreeBT_IoDecrement(DeviceObject->DeviceExtension);
304 
305     return ntStatus;
306 
307 }
308 
309 // Called from the DeviceIOControl handler to wait for an event on the interrupt pipe
310 NTSTATUS NTAPI FreeBT_GetHCIEvent(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID IoBuffer, IN ULONG InputBufferLength)
311 {
312     PDEVICE_EXTENSION   deviceExtension;
313     PURB                urb;
314     NTSTATUS            ntStatus;
315     PIO_STACK_LOCATION  nextStack;
316 
317     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: Entered\n"));
318 
319     urb = NULL;
320     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
321 
322     urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
323     if (urb==NULL)
324     {
325         FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_GetHCIEvent: Failed to alloc mem for urb\n"));
326         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
327         goto FreeBT_GetHCIEvent_Exit;
328 
329     }
330 
331     UsbBuildInterruptOrBulkTransferRequest(
332                             urb,
333                             sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
334                             deviceExtension->EventPipe.PipeHandle,
335                             IoBuffer,
336                             NULL,
337                             InputBufferLength,
338                             USBD_SHORT_TRANSFER_OK|USBD_TRANSFER_DIRECTION_IN,
339                             NULL);
340 
341     // use the original irp as an internal device control irp, which we send down to the
342     // USB class driver in order to get our request out on the wire
343     nextStack = IoGetNextIrpStackLocation(Irp);
344     nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
345     nextStack->Parameters.Others.Argument1 = (PVOID) urb;
346     nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
347 
348     IoSetCompletionRoutine(
349         Irp,
350         (PIO_COMPLETION_ROUTINE)FreeBT_HCIEventCompletion,
351         urb,
352         TRUE,
353         TRUE,
354         TRUE);
355 
356     // We return STATUS_PENDING; call IoMarkIrpPending.
357     IoMarkIrpPending(Irp);
358 
359     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent::"));
360     FreeBT_IoIncrement(deviceExtension);
361 
362     ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
363     if (!NT_SUCCESS(ntStatus))
364     {
365         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: IoCallDriver fails with status %X\n", ntStatus));
366 
367         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent::"));
368         FreeBT_IoDecrement(deviceExtension);
369 
370         // If the device was surprise removed out, the pipeInformation field is invalid.
371         // similarly if the request was cancelled, then we need not reset the pipe.
372         if((ntStatus != STATUS_CANCELLED) && (ntStatus != STATUS_DEVICE_NOT_CONNECTED))
373         {
374             ntStatus = FreeBT_ResetPipe(DeviceObject, deviceExtension->EventPipe.PipeHandle);
375             if(!NT_SUCCESS(ntStatus))
376             {
377                 FreeBT_DbgPrint(1, ("FreeBT_ResetPipe failed\n"));
378                 ntStatus = FreeBT_ResetDevice(DeviceObject);
379 
380             }
381 
382         }
383 
384         else
385         {
386             FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n"));
387 
388         }
389 
390         goto FreeBT_GetHCIEvent_Exit;
391 
392     }
393 
394     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: Leaving\n"));
395 
396     // Return STATUS_PENDING, when the lower driver completes the request,
397     // the FreeBT_HCIEventCompletion completion routine.
398     return STATUS_PENDING;
399 
400 FreeBT_GetHCIEvent_Exit:
401     Irp->IoStatus.Status=ntStatus;
402     Irp->IoStatus.Information=0;
403 
404     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: Failure (0x%08x), completing IRP\n", ntStatus));
405     IoCompleteRequest(Irp, IO_NO_INCREMENT);
406 
407     return ntStatus;
408 
409 }
410 
411 // DeviceIOControl dispatch
412 NTSTATUS NTAPI FreeBT_DispatchDevCtrl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
413 {
414     ULONG              code;
415     PVOID              ioBuffer;
416     ULONG              inputBufferLength;
417     ULONG              outputBufferLength;
418     ULONG              info;
419     NTSTATUS           ntStatus;
420     PDEVICE_EXTENSION  deviceExtension;
421     PIO_STACK_LOCATION irpStack;
422 
423     info = 0;
424     irpStack = IoGetCurrentIrpStackLocation(Irp);
425     code = irpStack->Parameters.DeviceIoControl.IoControlCode;
426     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
427 
428     ioBuffer           = Irp->AssociatedIrp.SystemBuffer;
429     inputBufferLength  = irpStack->Parameters.DeviceIoControl.InputBufferLength;
430     outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
431 
432     if (deviceExtension->DeviceState != Working)
433     {
434         FreeBT_DbgPrint(1, ("FBTUSB: Invalid device state\n"));
435         ntStatus = STATUS_INVALID_DEVICE_STATE;
436         goto FreeBT_DispatchDevCtrlExit;
437 
438     }
439 
440     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchDevCtrl::"));
441 
442     // Make sure that any selective suspend request has been completed.
443     if (deviceExtension->SSEnable)
444     {
445         FreeBT_DbgPrint(3, ("Waiting on the IdleReqPendEvent\n"));
446         KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
447                               Executive,
448                               KernelMode,
449                               FALSE,
450                               NULL);
451 
452     }
453 
454     switch(code)
455     {
456     case IOCTL_FREEBT_HCI_SEND_CMD:
457         FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_SEND_CMD received\n"));
458         if (inputBufferLength<FBT_HCI_CMD_MIN_SIZE)
459         {
460             ntStatus = STATUS_BUFFER_TOO_SMALL;
461             FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_SEND_CMD: Buffer too small\n"));
462             goto FreeBT_DispatchDevCtrlExit;
463 
464         }
465 
466         if (inputBufferLength>FBT_HCI_CMD_MAX_SIZE)
467         {
468             ntStatus = STATUS_INVALID_BUFFER_SIZE;
469             FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_SEND_CMD: Buffer too long\n"));
470             goto FreeBT_DispatchDevCtrlExit;
471 
472         }
473 
474         return FreeBT_SendHCICommand(DeviceObject, Irp, ioBuffer, inputBufferLength);
475         break;
476 
477     case IOCTL_FREEBT_HCI_GET_EVENT:
478         FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_GET_EVENT received\n"));
479         if (outputBufferLength<FBT_HCI_EVENT_MAX_SIZE)
480         {
481             ntStatus = STATUS_BUFFER_TOO_SMALL;
482             FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_GET_EVENT: Buffer too small\n"));
483             goto FreeBT_DispatchDevCtrlExit;
484 
485         }
486 
487         return FreeBT_GetHCIEvent(DeviceObject, Irp, ioBuffer, outputBufferLength);
488         break;
489 
490     default:
491         FreeBT_DbgPrint(3, ("FBTUSB: Invalid IOCTL 0x%08x received\n", code));
492         ntStatus = STATUS_INVALID_DEVICE_REQUEST;
493         break;
494 
495     }
496 
497 FreeBT_DispatchDevCtrlExit:
498     Irp->IoStatus.Information = 0;
499     Irp->IoStatus.Status = ntStatus;
500     IoCompleteRequest(Irp, IO_NO_INCREMENT);
501 
502     return ntStatus;
503 }
504 
505 // Submit URB_FUNCTION_RESET_PIPE
506 NTSTATUS NTAPI FreeBT_ResetPipe(IN PDEVICE_OBJECT DeviceObject, IN USBD_PIPE_HANDLE PipeHandle)
507 {
508     PURB              urb;
509     NTSTATUS          ntStatus;
510     PDEVICE_EXTENSION deviceExtension;
511 
512     urb = NULL;
513     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
514 
515     urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
516     if (urb)
517     {
518         urb->UrbHeader.Length = (USHORT) sizeof(struct _URB_PIPE_REQUEST);
519         urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
520         urb->UrbPipeRequest.PipeHandle = PipeHandle;
521 
522         ntStatus = CallUSBD(DeviceObject, urb);
523 
524         ExFreePool(urb);
525 
526     }
527 
528     else
529         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
530 
531     if(NT_SUCCESS(ntStatus))
532     {
533         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ResetPipe - success\n"));
534         ntStatus = STATUS_SUCCESS;
535 
536     }
537 
538     else
539         FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ResetPipe - failed\n"));
540 
541     return ntStatus;
542 
543 }
544 
545 // Call FreeBT_ResetParentPort to reset the device
546 NTSTATUS NTAPI FreeBT_ResetDevice(IN PDEVICE_OBJECT DeviceObject)
547 {
548     NTSTATUS ntStatus;
549     ULONG    portStatus;
550 
551     FreeBT_DbgPrint(3, ("FreeBT_ResetDevice: Entered\n"));
552 
553     ntStatus = FreeBT_GetPortStatus(DeviceObject, &portStatus);
554 
555     if ( (NT_SUCCESS(ntStatus)) && (!(portStatus & USBD_PORT_ENABLED)) && (portStatus & USBD_PORT_CONNECTED))
556         ntStatus=FreeBT_ResetParentPort(DeviceObject);
557 
558     FreeBT_DbgPrint(3, ("FreeBT_ResetDevice: Leaving\n"));
559 
560     return ntStatus;
561 
562 }
563 
564 // Read port status from the lower driver (USB class driver)
565 NTSTATUS NTAPI FreeBT_GetPortStatus(IN PDEVICE_OBJECT DeviceObject, IN OUT PULONG PortStatus)
566 {
567     NTSTATUS           ntStatus;
568     KEVENT             event;
569     PIRP               irp;
570     IO_STATUS_BLOCK    ioStatus;
571     PIO_STACK_LOCATION nextStack;
572     PDEVICE_EXTENSION  deviceExtension;
573 
574     FreeBT_DbgPrint(3, ("FreeBT_GetPortStatus: Entered\n"));
575 
576     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
577     *PortStatus = 0;
578 
579     KeInitializeEvent(&event, NotificationEvent, FALSE);
580     irp = IoBuildDeviceIoControlRequest(
581                     IOCTL_INTERNAL_USB_GET_PORT_STATUS,
582                     deviceExtension->TopOfStackDeviceObject,
583                     NULL,
584                     0,
585                     NULL,
586                     0,
587                     TRUE,
588                     &event,
589                     &ioStatus);
590 
591     if (NULL == irp)
592     {
593         FreeBT_DbgPrint(1, ("memory alloc for irp failed\n"));
594         return STATUS_INSUFFICIENT_RESOURCES;
595 
596     }
597 
598     nextStack = IoGetNextIrpStackLocation(irp);
599     ASSERT(nextStack != NULL);
600     nextStack->Parameters.Others.Argument1 = PortStatus;
601 
602     ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
603     if (STATUS_PENDING==ntStatus)
604         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
605 
606     else
607         ioStatus.Status = ntStatus;
608 
609     ntStatus = ioStatus.Status;
610     FreeBT_DbgPrint(3, ("FreeBT_GetPortStatus: Leaving\n"));
611 
612     return ntStatus;
613 
614 }
615 
616 // Sends an IOCTL_INTERNAL_USB_RESET_PORT via the lower driver
617 NTSTATUS NTAPI FreeBT_ResetParentPort(IN PDEVICE_OBJECT DeviceObject)
618 {
619     NTSTATUS           ntStatus;
620     KEVENT             event;
621     PIRP               irp;
622     IO_STATUS_BLOCK    ioStatus;
623     PIO_STACK_LOCATION nextStack;
624     PDEVICE_EXTENSION  deviceExtension;
625 
626     FreeBT_DbgPrint(3, ("FreeBT_ResetParentPort: Entered\n"));
627 
628     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
629 
630     KeInitializeEvent(&event, NotificationEvent, FALSE);
631     irp = IoBuildDeviceIoControlRequest(
632                     IOCTL_INTERNAL_USB_RESET_PORT,
633                     deviceExtension->TopOfStackDeviceObject,
634                     NULL,
635                     0,
636                     NULL,
637                     0,
638                     TRUE,
639                     &event,
640                     &ioStatus);
641 
642     if (NULL == irp)
643     {
644         FreeBT_DbgPrint(1, ("memory alloc for irp failed\n"));
645         return STATUS_INSUFFICIENT_RESOURCES;
646 
647     }
648 
649     nextStack = IoGetNextIrpStackLocation(irp);
650     ASSERT(nextStack != NULL);
651 
652     ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
653     if(STATUS_PENDING == ntStatus)
654         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
655 
656     else
657         ioStatus.Status = ntStatus;
658 
659 
660     ntStatus = ioStatus.Status;
661 
662     FreeBT_DbgPrint(3, ("FreeBT_ResetParentPort: Leaving\n"));
663 
664     return ntStatus;
665 
666 }
667 
668 // Send an idle request to the lower driver
669 NTSTATUS NTAPI SubmitIdleRequestIrp(IN PDEVICE_EXTENSION DeviceExtension)
670 {
671     PIRP                    irp;
672     NTSTATUS                ntStatus;
673     KIRQL                   oldIrql;
674     PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
675     PIO_STACK_LOCATION      nextStack;
676 
677     FreeBT_DbgPrint(3, ("SubmitIdleRequest: Entered\n"));
678 
679     irp = NULL;
680     idleCallbackInfo = NULL;
681 
682     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
683 
684     if(PowerDeviceD0 != DeviceExtension->DevPower) {
685 
686         ntStatus = STATUS_POWER_STATE_INVALID;
687 
688         goto SubmitIdleRequestIrp_Exit;
689     }
690 
691     KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
692 
693     if(InterlockedExchange(&DeviceExtension->IdleReqPend, 1)) {
694 
695         FreeBT_DbgPrint(1, ("Idle request pending..\n"));
696 
697         KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
698 
699         ntStatus = STATUS_DEVICE_BUSY;
700 
701         goto SubmitIdleRequestIrp_Exit;
702     }
703 
704     //
705     // clear the NoIdleReqPendEvent because we are about
706     // to submit an idle request. Since we are so early
707     // to clear this event, make sure that if we fail this
708     // request we set back the event.
709     //
710     KeClearEvent(&DeviceExtension->NoIdleReqPendEvent);
711 
712     idleCallbackInfo = (PUSB_IDLE_CALLBACK_INFO)ExAllocatePool(NonPagedPool, sizeof(struct _USB_IDLE_CALLBACK_INFO));
713 
714     if(idleCallbackInfo) {
715 
716         idleCallbackInfo->IdleCallback = (USB_IDLE_CALLBACK)IdleNotificationCallback;
717 
718         idleCallbackInfo->IdleContext = (PVOID)DeviceExtension;
719 
720         ASSERT(DeviceExtension->IdleCallbackInfo == NULL);
721 
722         DeviceExtension->IdleCallbackInfo = idleCallbackInfo;
723 
724         //
725         // we use IoAllocateIrp to create an irp to selectively suspend the
726         // device. This irp lies pending with the hub driver. When appropriate
727         // the hub driver will invoked callback, where we power down. The completion
728         // routine is invoked when we power back.
729         //
730         irp = IoAllocateIrp(DeviceExtension->TopOfStackDeviceObject->StackSize,
731                             FALSE);
732 
733         if(irp == NULL) {
734 
735             FreeBT_DbgPrint(1, ("cannot build idle request irp\n"));
736 
737             KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
738                        IO_NO_INCREMENT,
739                        FALSE);
740 
741             InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
742 
743             KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
744 
745             ExFreePool(idleCallbackInfo);
746 
747             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
748 
749             goto SubmitIdleRequestIrp_Exit;
750         }
751 
752         nextStack = IoGetNextIrpStackLocation(irp);
753 
754         nextStack->MajorFunction =
755                     IRP_MJ_INTERNAL_DEVICE_CONTROL;
756 
757         nextStack->Parameters.DeviceIoControl.IoControlCode =
758                     IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
759 
760         nextStack->Parameters.DeviceIoControl.Type3InputBuffer =
761                     idleCallbackInfo;
762 
763         nextStack->Parameters.DeviceIoControl.InputBufferLength =
764                     sizeof(struct _USB_IDLE_CALLBACK_INFO);
765 
766 
767         IoSetCompletionRoutine(irp,
768                                (PIO_COMPLETION_ROUTINE)IdleNotificationRequestComplete,
769                                DeviceExtension,
770                                TRUE,
771                                TRUE,
772                                TRUE);
773 
774         DeviceExtension->PendingIdleIrp = irp;
775 
776         //
777         // we initialize the count to 2.
778         // The reason is, if the CancelSelectSuspend routine manages
779         // to grab the irp from the device extension, then the last of the
780         // CancelSelectSuspend routine/IdleNotificationRequestComplete routine
781         // to execute will free this irp. We need to have this schema so that
782         // 1. completion routine does not attempt to touch the irp freed by
783         //    CancelSelectSuspend routine.
784         // 2. CancelSelectSuspend routine doesnt wait for ever for the completion
785         //    routine to complete!
786         //
787         DeviceExtension->FreeIdleIrpCount = 2;
788 
789         KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
790 
791         //
792         // check if the device is idle.
793         // A check here ensures that a race condition did not
794         // completely reverse the call sequence of SubmitIdleRequestIrp
795         // and CancelSelectiveSuspend
796         //
797 
798         if(!CanDeviceSuspend(DeviceExtension) ||
799            PowerDeviceD0 != DeviceExtension->DevPower) {
800 
801             //
802             // IRPs created using IoBuildDeviceIoControlRequest should be
803             // completed by calling IoCompleteRequest and not merely
804             // deallocated.
805             //
806 
807             FreeBT_DbgPrint(1, ("Device is not idle\n"));
808 
809             KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
810 
811             DeviceExtension->IdleCallbackInfo = NULL;
812 
813             DeviceExtension->PendingIdleIrp = NULL;
814 
815             KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
816                        IO_NO_INCREMENT,
817                        FALSE);
818 
819             InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
820 
821             KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
822 
823             if(idleCallbackInfo) {
824 
825                 ExFreePool(idleCallbackInfo);
826             }
827 
828             //
829             // it is still safe to touch the local variable "irp" here.
830             // the irp has not been passed down the stack, the irp has
831             // no cancellation routine. The worse position is that the
832             // CancelSelectSuspend has run after we released the spin
833             // lock above. It is still essential to free the irp.
834             //
835             if(irp) {
836 
837                 IoFreeIrp(irp);
838             }
839 
840             ntStatus = STATUS_UNSUCCESSFUL;
841 
842             goto SubmitIdleRequestIrp_Exit;
843         }
844 
845         FreeBT_DbgPrint(3, ("Cancel the timers\n"));
846         //
847         // Cancel the timer so that the DPCs are no longer fired.
848         // Thus, we are making judicious usage of our resources.
849         // we do not need DPCs because we already have an idle irp pending.
850         // The timers are re-initialized in the completion routine.
851         //
852         KeCancelTimer(&DeviceExtension->Timer);
853 
854         ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);
855 
856         if(!NT_SUCCESS(ntStatus)) {
857 
858             FreeBT_DbgPrint(1, ("IoCallDriver failed\n"));
859 
860             goto SubmitIdleRequestIrp_Exit;
861         }
862     }
863     else {
864 
865         FreeBT_DbgPrint(1, ("Memory allocation for idleCallbackInfo failed\n"));
866 
867         KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
868                    IO_NO_INCREMENT,
869                    FALSE);
870 
871         InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
872 
873         KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
874 
875         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
876     }
877 
878 SubmitIdleRequestIrp_Exit:
879 
880     FreeBT_DbgPrint(3, ("SubmitIdleRequest: Leaving\n"));
881 
882     return ntStatus;
883 }
884 
885 
886 VOID NTAPI IdleNotificationCallback(IN PDEVICE_EXTENSION DeviceExtension)
887 {
888     NTSTATUS                ntStatus;
889     POWER_STATE             powerState;
890     KEVENT                  irpCompletionEvent;
891     PIRP_COMPLETION_CONTEXT irpContext;
892 
893     FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback: Entered\n"));
894 
895     //
896     // Dont idle, if the device was just disconnected or being stopped
897     // i.e. return for the following DeviceState(s)
898     // NotStarted, Stopped, PendingStop, PendingRemove, SurpriseRemoved, Removed
899     //
900 
901     if(DeviceExtension->DeviceState != Working) {
902 
903         return;
904     }
905 
906     //
907     // If there is not already a WW IRP pending, submit one now
908     //
909     if(DeviceExtension->WaitWakeEnable) {
910 
911         IssueWaitWake(DeviceExtension);
912     }
913 
914 
915     //
916     // power down the device
917     //
918 
919     irpContext = (PIRP_COMPLETION_CONTEXT)
920                  ExAllocatePool(NonPagedPool,
921                                 sizeof(IRP_COMPLETION_CONTEXT));
922 
923     if(!irpContext) {
924 
925         FreeBT_DbgPrint(1, ("FBTUSB: IdleNotificationCallback: Failed to alloc memory for irpContext\n"));
926         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
927     }
928     else {
929 
930         //
931         // increment the count. In the HoldIoRequestWorkerRoutine, the
932         // count is decremented twice (one for the system Irp and the
933         // other for the device Irp. An increment here compensates for
934         // the sytem irp..The decrement corresponding to this increment
935         // is in the completion function
936         //
937 
938         FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback::"));
939         FreeBT_IoIncrement(DeviceExtension);
940 
941         powerState.DeviceState = (DEVICE_POWER_STATE) DeviceExtension->PowerDownLevel;
942 
943         KeInitializeEvent(&irpCompletionEvent, NotificationEvent, FALSE);
944 
945         irpContext->DeviceExtension = DeviceExtension;
946         irpContext->Event = &irpCompletionEvent;
947 
948         ntStatus = PoRequestPowerIrp(
949                           DeviceExtension->PhysicalDeviceObject,
950                           IRP_MN_SET_POWER,
951                           powerState,
952                           (PREQUEST_POWER_COMPLETE) PoIrpCompletionFunc,
953                           irpContext,
954                           NULL);
955 
956         if(STATUS_PENDING == ntStatus) {
957 
958             FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback::"
959                            "waiting for the power irp to complete\n"));
960 
961             KeWaitForSingleObject(&irpCompletionEvent,
962                                   Executive,
963                                   KernelMode,
964                                   FALSE,
965                                   NULL);
966         }
967     }
968 
969     if(!NT_SUCCESS(ntStatus)) {
970 
971         if(irpContext) {
972 
973             ExFreePool(irpContext);
974         }
975     }
976 
977     FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback: Leaving\n"));
978 }
979 
980 
981 NTSTATUS NTAPI IdleNotificationRequestComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
982 {
983     NTSTATUS                ntStatus;
984     POWER_STATE             powerState;
985     KIRQL                   oldIrql;
986     LARGE_INTEGER           dueTime;
987     PIRP                    idleIrp;
988     PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
989 
990     FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationRequestCompete: Entered\n"));
991 
992     idleIrp = NULL;
993 
994     ntStatus = Irp->IoStatus.Status;
995     if(!NT_SUCCESS(ntStatus) && ntStatus != STATUS_NOT_SUPPORTED)
996     {
997         FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationRequestCompete: Idle irp completes with error::"));
998         switch(ntStatus)
999         {
1000         case STATUS_INVALID_DEVICE_REQUEST:
1001             FreeBT_DbgPrint(3, ("STATUS_INVALID_DEVICE_REQUEST\n"));
1002             break;
1003 
1004         case STATUS_CANCELLED:
1005             FreeBT_DbgPrint(3, ("STATUS_CANCELLED\n"));
1006             break;
1007 
1008         case STATUS_DEVICE_BUSY:
1009             FreeBT_DbgPrint(3, ("STATUS_DEVICE_BUSY\n"));
1010             break;
1011 
1012         case STATUS_POWER_STATE_INVALID:
1013             FreeBT_DbgPrint(3, ("STATUS_POWER_STATE_INVALID\n"));
1014             goto IdleNotificationRequestComplete_Exit;
1015 
1016         default:
1017             FreeBT_DbgPrint(3, ("default: status = %X\n", ntStatus));
1018             break;
1019 
1020         }
1021 
1022         // if in error, issue a SetD0
1023         FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationRequestComplete::"));
1024         FreeBT_IoIncrement(DeviceExtension);
1025 
1026         powerState.DeviceState = PowerDeviceD0;
1027         ntStatus = PoRequestPowerIrp(
1028                           DeviceExtension->PhysicalDeviceObject,
1029                           IRP_MN_SET_POWER,
1030                           powerState,
1031                           (PREQUEST_POWER_COMPLETE) PoIrpAsyncCompletionFunc,
1032                           DeviceExtension,
1033                           NULL);
1034 
1035         if(!NT_SUCCESS(ntStatus))
1036             FreeBT_DbgPrint(1, ("PoRequestPowerIrp failed\n"));
1037 
1038     }
1039 
1040 IdleNotificationRequestComplete_Exit:
1041     KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
1042     idleCallbackInfo = DeviceExtension->IdleCallbackInfo;
1043     DeviceExtension->IdleCallbackInfo = NULL;
1044 
1045     idleIrp = (PIRP) InterlockedExchangePointer((PVOID*)&DeviceExtension->PendingIdleIrp, NULL);
1046     InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
1047 
1048     KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
1049 
1050     if(idleCallbackInfo)
1051         ExFreePool(idleCallbackInfo);
1052 
1053     // Since the irp was created using IoAllocateIrp,
1054     // the Irp needs to be freed using IoFreeIrp.
1055     // Also return STATUS_MORE_PROCESSING_REQUIRED so that
1056     // the kernel does not reference this in the near future.
1057     if(idleIrp)
1058     {
1059         FreeBT_DbgPrint(3, ("completion routine has a valid irp and frees it\n"));
1060         IoFreeIrp(Irp);
1061         KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE);
1062 
1063     }
1064 
1065     else
1066     {
1067         // The CancelSelectiveSuspend routine has grabbed the Irp from the device
1068         // extension. Now the last one to decrement the FreeIdleIrpCount should
1069         // free the irp.
1070         if (0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount))
1071         {
1072             FreeBT_DbgPrint(3, ("completion routine frees the irp\n"));
1073             IoFreeIrp(Irp);
1074             KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE);
1075 
1076         }
1077 
1078     }
1079 
1080     if(DeviceExtension->SSEnable)
1081     {
1082         FreeBT_DbgPrint(3, ("Set the timer to fire DPCs\n"));
1083         dueTime.QuadPart = -10000 * IDLE_INTERVAL;               // 5000 ms
1084         KeSetTimerEx(&DeviceExtension->Timer, dueTime, IDLE_INTERVAL, &DeviceExtension->DeferredProcCall);
1085         FreeBT_DbgPrint(3, ("IdleNotificationRequestCompete: Leaving\n"));
1086 
1087     }
1088 
1089     return STATUS_MORE_PROCESSING_REQUIRED;
1090 
1091 }
1092 
1093 VOID NTAPI CancelSelectSuspend(IN PDEVICE_EXTENSION DeviceExtension)
1094 {
1095     PIRP  irp;
1096     KIRQL oldIrql;
1097 
1098     FreeBT_DbgPrint(3, ("CancelSelectSuspend: Entered\n"));
1099 
1100     irp = NULL;
1101 
1102     KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
1103 
1104     if(!CanDeviceSuspend(DeviceExtension))
1105     {
1106         FreeBT_DbgPrint(3, ("Device is not idle\n"));
1107         irp = (PIRP) InterlockedExchangePointer((PVOID*)&DeviceExtension->PendingIdleIrp, NULL);
1108 
1109     }
1110 
1111     KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
1112 
1113     // since we have a valid Irp ptr,
1114     // we can call IoCancelIrp on it,
1115     // without the fear of the irp
1116     // being freed underneath us.
1117     if(irp)
1118     {
1119         // This routine has the irp pointer.
1120         // It is safe to call IoCancelIrp because we know that
1121         // the compleiton routine will not free this irp unless...
1122         //
1123         //
1124         if(IoCancelIrp(irp))
1125         {
1126             FreeBT_DbgPrint(3, ("IoCancelIrp returns TRUE\n"));
1127 
1128         }
1129 
1130         else
1131         {
1132             FreeBT_DbgPrint(3, ("IoCancelIrp returns FALSE\n"));
1133 
1134         }
1135 
1136         // ....we decrement the FreeIdleIrpCount from 2 to 1.
1137         // if completion routine runs ahead of us, then this routine
1138         // decrements the FreeIdleIrpCount from 1 to 0 and hence shall
1139         // free the irp.
1140         if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount))
1141         {
1142             FreeBT_DbgPrint(3, ("CancelSelectSuspend frees the irp\n"));
1143             IoFreeIrp(irp);
1144             KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE);
1145 
1146         }
1147 
1148     }
1149 
1150     FreeBT_DbgPrint(3, ("CancelSelectSuspend: Leaving\n"));
1151 
1152     return;
1153 
1154 }
1155 
1156 VOID NTAPI PoIrpCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus)
1157 {
1158     PIRP_COMPLETION_CONTEXT irpContext;
1159     irpContext = NULL;
1160 
1161     FreeBT_DbgPrint(3, ("PoIrpCompletionFunc::"));
1162 
1163     if(Context)
1164         irpContext = (PIRP_COMPLETION_CONTEXT) Context;
1165 
1166     // all we do is set the event and decrement the count
1167     if(irpContext)
1168     {
1169         KeSetEvent(irpContext->Event, 0, FALSE);
1170         FreeBT_IoDecrement(irpContext->DeviceExtension);
1171         ExFreePool(irpContext);
1172 
1173     }
1174 
1175     return;
1176 
1177 }
1178 
1179 VOID NTAPI PoIrpAsyncCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus)
1180 {
1181     PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Context;
1182     FreeBT_DbgPrint(3, ("PoIrpAsyncCompletionFunc::"));
1183     FreeBT_IoDecrement(DeviceExtension);
1184 
1185     return;
1186 
1187 }
1188 
1189 VOID NTAPI WWIrpCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus)
1190 {
1191     PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Context;
1192 
1193     FreeBT_DbgPrint(3, ("WWIrpCompletionFunc::"));
1194     FreeBT_IoDecrement(DeviceExtension);
1195 
1196     return;
1197 
1198 }
1199