--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE group SYSTEM "../../tools/rbuild/project.dtd">
+<group xmlns:xi="http://www.w3.org/2001/XInclude">
+<!--directory name="fbtusb">
+ <xi:include href="fbtusb/fbtusb.rbuild" />
+</directory-->
+</group>
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#include "fbtusb.h"
+#include "fbtpnp.h"
+#include "fbtpwr.h"
+#include "fbtdev.h"
+#include "fbtwmi.h"
+#include "fbtrwr.h"
+
+#include "fbtusr.h"
+
+// Dispatch routine for CreateHandle
+NTSTATUS FreeBT_DispatchCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ ULONG i;
+ NTSTATUS ntStatus;
+ PFILE_OBJECT fileObject;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpStack;
+ PFREEBT_PIPE_CONTEXT pipeContext;
+ PUSBD_INTERFACE_INFORMATION interface;
+
+ PAGED_CODE();
+
+ FreeBT_DbgPrint(3, ("FreeBT_DispatchCreate: Entered\n"));
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ fileObject = irpStack->FileObject;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ if (deviceExtension->DeviceState != Working)
+ {
+ ntStatus = STATUS_INVALID_DEVICE_STATE;
+ goto FreeBT_DispatchCreate_Exit;
+
+ }
+
+ if (deviceExtension->UsbInterface)
+ {
+ interface = deviceExtension->UsbInterface;
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("UsbInterface not found\n"));
+ ntStatus = STATUS_INVALID_DEVICE_STATE;
+ goto FreeBT_DispatchCreate_Exit;
+
+ }
+
+ if (fileObject)
+ {
+ fileObject->FsContext = NULL;
+ }
+
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ goto FreeBT_DispatchCreate_Exit;
+
+ }
+
+ if (deviceExtension->OpenHandleCount>0)
+ {
+ ntStatus = STATUS_ACCESS_VIOLATION;
+ goto FreeBT_DispatchCreate_Exit;
+
+ }
+
+ // opening a device as opposed to pipe.
+ ntStatus = STATUS_SUCCESS;
+
+ InterlockedIncrement(&deviceExtension->OpenHandleCount);
+
+ // the device is idle if it has no open handles or pending PnP Irps
+ // since we just received an open handle request, cancel idle req.
+ if (deviceExtension->SSEnable)
+ CancelSelectSuspend(deviceExtension);
+
+FreeBT_DispatchCreate_Exit:
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FreeBT_DispatchCreate: Leaving\n"));
+ return ntStatus;
+
+}
+
+// Dispatch routine for CloseHandle
+NTSTATUS FreeBT_DispatchClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ NTSTATUS ntStatus;
+ PFILE_OBJECT fileObject;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpStack;
+ PFREEBT_PIPE_CONTEXT pipeContext;
+ PUSBD_PIPE_INFORMATION pipeInformation;
+
+ PAGED_CODE();
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ fileObject = irpStack->FileObject;
+ pipeContext = NULL;
+ pipeInformation = NULL;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ FreeBT_DbgPrint(3, ("FreeBT_DispatchClose: Entered\n"));
+
+ ntStatus = STATUS_SUCCESS;
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ InterlockedDecrement(&deviceExtension->OpenHandleCount);
+
+ FreeBT_DbgPrint(3, ("FreeBT_DispatchClose: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+// Called when a HCI Send on the control pipe completes
+NTSTATUS FreeBT_HCISendCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
+{
+ ULONG stageLength;
+ NTSTATUS ntStatus;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_HCISendCompletion, status=0x%08X\n", Irp->IoStatus.Status));
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ ExFreePool(Context);
+ FreeBT_IoDecrement(DeviceObject->DeviceExtension);
+ ntStatus = Irp->IoStatus.Status;
+ Irp->IoStatus.Information = 0;
+
+ return ntStatus;
+
+}
+
+// Called the DeviceIOControl handler to send an HCI command received from the user
+// HCI Commands are sent on the (default) control pipe
+NTSTATUS FreeBT_SendHCICommand(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID IoBuffer, IN ULONG InputBufferLength)
+{
+ PDEVICE_EXTENSION deviceExtension;
+ ULONG urbFlags;
+ ULONG stageLength;
+ PVOID pBuffer;
+ PURB urb;
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION nextStack;
+ //PFBT_HCI_CMD_HEADER pHCICommand;
+ //LARGE_INTEGER delay;
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ if (!deviceExtension)
+ {
+ ntStatus=STATUS_INVALID_PARAMETER;
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Failed to get DeviceExtension\n"));
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return ntStatus;
+
+ }
+
+ // The user is doing a reset, reset all the pipes as well, so that any
+ // old events or data are removed
+ /*pHCICommand=(PFBT_HCI_CMD_HEADER)IoBuffer;
+ if (pHCICommand->OpCode==FBT_HCI_CMD_RESET)
+ {
+ FreeBT_ResetPipe(DeviceObject, deviceExtension->EventPipe.PipeHandle);
+ FreeBT_ResetPipe(DeviceObject, deviceExtension->DataInPipe.PipeHandle);
+ FreeBT_ResetPipe(DeviceObject, deviceExtension->DataOutPipe.PipeHandle);
+ FreeBT_ResetPipe(DeviceObject, deviceExtension->AudioInPipe.PipeHandle);
+ FreeBT_ResetPipe(DeviceObject, deviceExtension->AudioOutPipe.PipeHandle);
+
+ // Wait a second for the device to recover
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Sleeping\n"));
+ delay.QuadPart = -10000 * 5000; // 5s
+ KeWaitForSingleObject(&deviceExtension->DelayEvent,
+ Executive,
+ UserMode,
+ FALSE,
+ &delay);
+
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Finished sleeping\n"));
+
+
+ }*/
+
+ // Create the URB
+ urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+ if(urb == NULL)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_SendHCICommand: Failed to alloc mem for urb\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return ntStatus;
+
+ }
+
+ UsbBuildVendorRequest(
+ urb,
+ URB_FUNCTION_CLASS_DEVICE, // This works, for CSR and Silicon Wave
+ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ IoBuffer,
+ NULL,
+ InputBufferLength,
+ NULL);
+
+ // use the original irp as an internal device control irp
+ nextStack = IoGetNextIrpStackLocation(Irp);
+ nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ nextStack->Parameters.Others.Argument1 = (PVOID) urb;
+ nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+ IoSetCompletionRoutine(
+ Irp,
+ (PIO_COMPLETION_ROUTINE)FreeBT_HCISendCompletion,
+ urb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ // We return STATUS_PENDING; call IoMarkIrpPending.
+ IoMarkIrpPending(Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: Sending IRP %X to underlying driver\n", Irp));
+ ntStatus=IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: IoCallDriver fails with status %X\n", ntStatus));
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ // If the device was surprise removed out, the pipeInformation field is invalid.
+ // similarly if the request was cancelled, then we need not reset the device.
+ if((ntStatus != STATUS_CANCELLED) && (ntStatus != STATUS_DEVICE_NOT_CONNECTED))
+ ntStatus = FreeBT_ResetDevice(DeviceObject);
+
+ else
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n"));
+
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SendHCICommand: Completed successfully\n"));
+
+ return STATUS_PENDING;
+
+}
+
+// Called when a HCI Get on the event pipe completes
+NTSTATUS FreeBT_HCIEventCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
+{
+ ULONG stageLength;
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION nextStack;
+ PURB urb;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_HCIEventCompletion, status=0x%08X\n", Irp->IoStatus.Status));
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ // initialize variables
+ urb=(PURB)Context;
+ ntStatus = Irp->IoStatus.Status;
+ Irp->IoStatus.Information = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
+ nextStack = IoGetNextIrpStackLocation(Irp);
+
+ ExFreePool(Context);
+ FreeBT_IoDecrement(DeviceObject->DeviceExtension);
+
+ return ntStatus;
+
+}
+
+// Called from the DeviceIOControl handler to wait for an event on the interrupt pipe
+NTSTATUS FreeBT_GetHCIEvent(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID IoBuffer, IN ULONG InputBufferLength)
+{
+ PDEVICE_EXTENSION deviceExtension;
+ PURB urb;
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION nextStack;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: Entered\n"));
+
+ urb = NULL;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
+ if (urb==NULL)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_GetHCIEvent: Failed to alloc mem for urb\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto FreeBT_GetHCIEvent_Exit;
+
+ }
+
+ UsbBuildInterruptOrBulkTransferRequest(
+ urb,
+ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+ deviceExtension->EventPipe.PipeHandle,
+ IoBuffer,
+ NULL,
+ InputBufferLength,
+ USBD_SHORT_TRANSFER_OK|USBD_TRANSFER_DIRECTION_IN,
+ NULL);
+
+ // use the original irp as an internal device control irp, which we send down to the
+ // USB class driver in order to get our request out on the wire
+ nextStack = IoGetNextIrpStackLocation(Irp);
+ nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ nextStack->Parameters.Others.Argument1 = (PVOID) urb;
+ nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+ IoSetCompletionRoutine(
+ Irp,
+ (PIO_COMPLETION_ROUTINE)FreeBT_HCIEventCompletion,
+ urb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ // We return STATUS_PENDING; call IoMarkIrpPending.
+ IoMarkIrpPending(Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: IoCallDriver fails with status %X\n", ntStatus));
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ // If the device was surprise removed out, the pipeInformation field is invalid.
+ // similarly if the request was cancelled, then we need not reset the pipe.
+ if((ntStatus != STATUS_CANCELLED) && (ntStatus != STATUS_DEVICE_NOT_CONNECTED))
+ {
+ ntStatus = FreeBT_ResetPipe(DeviceObject, deviceExtension->EventPipe.PipeHandle);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FreeBT_ResetPipe failed\n"));
+ ntStatus = FreeBT_ResetDevice(DeviceObject);
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n"));
+
+ }
+
+ goto FreeBT_GetHCIEvent_Exit;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: Leaving\n"));
+
+ // Return STATUS_PENDING, when the lower driver completes the request,
+ // the FreeBT_HCIEventCompletion completion routine.
+ return STATUS_PENDING;
+
+FreeBT_GetHCIEvent_Exit:
+ Irp->IoStatus.Status=ntStatus;
+ Irp->IoStatus.Information=0;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetHCIEvent: Failure (0x%08x), completing IRP\n", ntStatus));
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+
+}
+
+// DeviceIOControl dispatch
+NTSTATUS FreeBT_DispatchDevCtrl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ ULONG code;
+ PVOID ioBuffer;
+ ULONG inputBufferLength;
+ ULONG outputBufferLength;
+ ULONG info;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpStack;
+
+ info = 0;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ code = irpStack->Parameters.DeviceIoControl.IoControlCode;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ ioBuffer = Irp->AssociatedIrp.SystemBuffer;
+ inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
+ outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (deviceExtension->DeviceState != Working)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: Invalid device state\n"));
+ ntStatus = STATUS_INVALID_DEVICE_STATE;
+ goto FreeBT_DispatchDevCtrlExit;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchDevCtrl::"));
+
+ // Make sure that any selective suspend request has been completed.
+ if (deviceExtension->SSEnable)
+ {
+ FreeBT_DbgPrint(3, ("Waiting on the IdleReqPendEvent\n"));
+ KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ }
+
+ switch(code)
+ {
+ case IOCTL_FREEBT_HCI_SEND_CMD:
+ FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_SEND_CMD received\n"));
+ if (inputBufferLength<FBT_HCI_CMD_MIN_SIZE)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_SEND_CMD: Buffer too small\n"));
+ goto FreeBT_DispatchDevCtrlExit;
+
+ }
+
+ if (inputBufferLength>FBT_HCI_CMD_MAX_SIZE)
+ {
+ ntStatus = STATUS_INVALID_BUFFER_SIZE;
+ FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_SEND_CMD: Buffer too long\n"));
+ goto FreeBT_DispatchDevCtrlExit;
+
+ }
+
+ return FreeBT_SendHCICommand(DeviceObject, Irp, ioBuffer, inputBufferLength);
+ break;
+
+ case IOCTL_FREEBT_HCI_GET_EVENT:
+ FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_GET_EVENT received\n"));
+ if (outputBufferLength<FBT_HCI_EVENT_MAX_SIZE)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ FreeBT_DbgPrint(3, ("FBTUSB: IOCTL_FREEBT_HCI_GET_EVENT: Buffer too small\n"));
+ goto FreeBT_DispatchDevCtrlExit;
+
+ }
+
+ return FreeBT_GetHCIEvent(DeviceObject, Irp, ioBuffer, outputBufferLength);
+ break;
+
+ default:
+ FreeBT_DbgPrint(3, ("FBTUSB: Invalid IOCTL 0x%08x received\n", code));
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+
+ }
+
+FreeBT_DispatchDevCtrlExit:
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = ntStatus;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+}
+
+// Submit URB_FUNCTION_RESET_PIPE
+NTSTATUS FreeBT_ResetPipe(IN PDEVICE_OBJECT DeviceObject, IN USBD_PIPE_HANDLE PipeHandle)
+{
+ PURB urb;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+
+ urb = NULL;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
+ if (urb)
+ {
+ urb->UrbHeader.Length = (USHORT) sizeof(struct _URB_PIPE_REQUEST);
+ urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
+ urb->UrbPipeRequest.PipeHandle = PipeHandle;
+
+ ntStatus = CallUSBD(DeviceObject, urb);
+
+ ExFreePool(urb);
+
+ }
+
+ else
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ if(NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ResetPipe - success\n"));
+ ntStatus = STATUS_SUCCESS;
+
+ }
+
+ else
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ResetPipe - failed\n"));
+
+ return ntStatus;
+
+}
+
+// Call FreeBT_ResetParentPort to reset the device
+NTSTATUS FreeBT_ResetDevice(IN PDEVICE_OBJECT DeviceObject)
+{
+ NTSTATUS ntStatus;
+ ULONG portStatus;
+
+ FreeBT_DbgPrint(3, ("FreeBT_ResetDevice: Entered\n"));
+
+ ntStatus = FreeBT_GetPortStatus(DeviceObject, &portStatus);
+
+ if ( (NT_SUCCESS(ntStatus)) && (!(portStatus & USBD_PORT_ENABLED)) && (portStatus & USBD_PORT_CONNECTED))
+ ntStatus=FreeBT_ResetParentPort(DeviceObject);
+
+ FreeBT_DbgPrint(3, ("FreeBT_ResetDevice: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+// Read port status from the lower driver (USB class driver)
+NTSTATUS FreeBT_GetPortStatus(IN PDEVICE_OBJECT DeviceObject, IN OUT PULONG PortStatus)
+{
+ NTSTATUS ntStatus;
+ KEVENT event;
+ PIRP irp;
+ IO_STATUS_BLOCK ioStatus;
+ PIO_STACK_LOCATION nextStack;
+ PDEVICE_EXTENSION deviceExtension;
+
+ FreeBT_DbgPrint(3, ("FreeBT_GetPortStatus: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ *PortStatus = 0;
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+ irp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_USB_GET_PORT_STATUS,
+ deviceExtension->TopOfStackDeviceObject,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ TRUE,
+ &event,
+ &ioStatus);
+
+ if (NULL == irp)
+ {
+ FreeBT_DbgPrint(1, ("memory alloc for irp failed\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ nextStack = IoGetNextIrpStackLocation(irp);
+ ASSERT(nextStack != NULL);
+ nextStack->Parameters.Others.Argument1 = PortStatus;
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
+ if (STATUS_PENDING==ntStatus)
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+
+ else
+ ioStatus.Status = ntStatus;
+
+ ntStatus = ioStatus.Status;
+ FreeBT_DbgPrint(3, ("FreeBT_GetPortStatus: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+// Sends an IOCTL_INTERNAL_USB_RESET_PORT via the lower driver
+NTSTATUS FreeBT_ResetParentPort(IN PDEVICE_OBJECT DeviceObject)
+{
+ NTSTATUS ntStatus;
+ KEVENT event;
+ PIRP irp;
+ IO_STATUS_BLOCK ioStatus;
+ PIO_STACK_LOCATION nextStack;
+ PDEVICE_EXTENSION deviceExtension;
+
+ FreeBT_DbgPrint(3, ("FreeBT_ResetParentPort: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+ irp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_USB_RESET_PORT,
+ deviceExtension->TopOfStackDeviceObject,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ TRUE,
+ &event,
+ &ioStatus);
+
+ if (NULL == irp)
+ {
+ FreeBT_DbgPrint(1, ("memory alloc for irp failed\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ nextStack = IoGetNextIrpStackLocation(irp);
+ ASSERT(nextStack != NULL);
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
+ if(STATUS_PENDING == ntStatus)
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+
+ else
+ ioStatus.Status = ntStatus;
+
+
+ ntStatus = ioStatus.Status;
+
+ FreeBT_DbgPrint(3, ("FreeBT_ResetParentPort: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+// Send an idle request to the lower driver
+NTSTATUS SubmitIdleRequestIrp(IN PDEVICE_EXTENSION DeviceExtension)
+{
+ PIRP irp;
+ NTSTATUS ntStatus;
+ KIRQL oldIrql;
+ PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
+ PIO_STACK_LOCATION nextStack;
+
+ FreeBT_DbgPrint(3, ("SubmitIdleRequest: Entered\n"));
+
+ irp = NULL;
+ idleCallbackInfo = NULL;
+
+ ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ if(PowerDeviceD0 != DeviceExtension->DevPower) {
+
+ ntStatus = STATUS_POWER_STATE_INVALID;
+
+ goto SubmitIdleRequestIrp_Exit;
+ }
+
+ KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
+
+ if(InterlockedExchange(&DeviceExtension->IdleReqPend, 1)) {
+
+ FreeBT_DbgPrint(1, ("Idle request pending..\n"));
+
+ KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
+
+ ntStatus = STATUS_DEVICE_BUSY;
+
+ goto SubmitIdleRequestIrp_Exit;
+ }
+
+ //
+ // clear the NoIdleReqPendEvent because we are about
+ // to submit an idle request. Since we are so early
+ // to clear this event, make sure that if we fail this
+ // request we set back the event.
+ //
+ KeClearEvent(&DeviceExtension->NoIdleReqPendEvent);
+
+ idleCallbackInfo = (PUSB_IDLE_CALLBACK_INFO)ExAllocatePool(NonPagedPool, sizeof(struct _USB_IDLE_CALLBACK_INFO));
+
+ if(idleCallbackInfo) {
+
+ idleCallbackInfo->IdleCallback = (USB_IDLE_CALLBACK)IdleNotificationCallback;
+
+ idleCallbackInfo->IdleContext = (PVOID)DeviceExtension;
+
+ ASSERT(DeviceExtension->IdleCallbackInfo == NULL);
+
+ DeviceExtension->IdleCallbackInfo = idleCallbackInfo;
+
+ //
+ // we use IoAllocateIrp to create an irp to selectively suspend the
+ // device. This irp lies pending with the hub driver. When appropriate
+ // the hub driver will invoked callback, where we power down. The completion
+ // routine is invoked when we power back.
+ //
+ irp = IoAllocateIrp(DeviceExtension->TopOfStackDeviceObject->StackSize,
+ FALSE);
+
+ if(irp == NULL) {
+
+ FreeBT_DbgPrint(1, ("cannot build idle request irp\n"));
+
+ KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
+ IO_NO_INCREMENT,
+ FALSE);
+
+ InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
+
+ KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
+
+ ExFreePool(idleCallbackInfo);
+
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ goto SubmitIdleRequestIrp_Exit;
+ }
+
+ nextStack = IoGetNextIrpStackLocation(irp);
+
+ nextStack->MajorFunction =
+ IRP_MJ_INTERNAL_DEVICE_CONTROL;
+
+ nextStack->Parameters.DeviceIoControl.IoControlCode =
+ IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
+
+ nextStack->Parameters.DeviceIoControl.Type3InputBuffer =
+ idleCallbackInfo;
+
+ nextStack->Parameters.DeviceIoControl.InputBufferLength =
+ sizeof(struct _USB_IDLE_CALLBACK_INFO);
+
+
+ IoSetCompletionRoutine(irp,
+ (PIO_COMPLETION_ROUTINE)IdleNotificationRequestComplete,
+ DeviceExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ DeviceExtension->PendingIdleIrp = irp;
+
+ //
+ // we initialize the count to 2.
+ // The reason is, if the CancelSelectSuspend routine manages
+ // to grab the irp from the device extension, then the last of the
+ // CancelSelectSuspend routine/IdleNotificationRequestComplete routine
+ // to execute will free this irp. We need to have this schema so that
+ // 1. completion routine does not attempt to touch the irp freed by
+ // CancelSelectSuspend routine.
+ // 2. CancelSelectSuspend routine doesnt wait for ever for the completion
+ // routine to complete!
+ //
+ DeviceExtension->FreeIdleIrpCount = 2;
+
+ KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
+
+ //
+ // check if the device is idle.
+ // A check here ensures that a race condition did not
+ // completely reverse the call sequence of SubmitIdleRequestIrp
+ // and CancelSelectiveSuspend
+ //
+
+ if(!CanDeviceSuspend(DeviceExtension) ||
+ PowerDeviceD0 != DeviceExtension->DevPower) {
+
+ //
+ // IRPs created using IoBuildDeviceIoControlRequest should be
+ // completed by calling IoCompleteRequest and not merely
+ // deallocated.
+ //
+
+ FreeBT_DbgPrint(1, ("Device is not idle\n"));
+
+ KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
+
+ DeviceExtension->IdleCallbackInfo = NULL;
+
+ DeviceExtension->PendingIdleIrp = NULL;
+
+ KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
+ IO_NO_INCREMENT,
+ FALSE);
+
+ InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
+
+ KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
+
+ if(idleCallbackInfo) {
+
+ ExFreePool(idleCallbackInfo);
+ }
+
+ //
+ // it is still safe to touch the local variable "irp" here.
+ // the irp has not been passed down the stack, the irp has
+ // no cancellation routine. The worse position is that the
+ // CancelSelectSuspend has run after we released the spin
+ // lock above. It is still essential to free the irp.
+ //
+ if(irp) {
+
+ IoFreeIrp(irp);
+ }
+
+ ntStatus = STATUS_UNSUCCESSFUL;
+
+ goto SubmitIdleRequestIrp_Exit;
+ }
+
+ FreeBT_DbgPrint(3, ("Cancel the timers\n"));
+ //
+ // Cancel the timer so that the DPCs are no longer fired.
+ // Thus, we are making judicious usage of our resources.
+ // we do not need DPCs because we already have an idle irp pending.
+ // The timers are re-initialized in the completion routine.
+ //
+ KeCancelTimer(&DeviceExtension->Timer);
+
+ ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);
+
+ if(!NT_SUCCESS(ntStatus)) {
+
+ FreeBT_DbgPrint(1, ("IoCallDriver failed\n"));
+
+ goto SubmitIdleRequestIrp_Exit;
+ }
+ }
+ else {
+
+ FreeBT_DbgPrint(1, ("Memory allocation for idleCallbackInfo failed\n"));
+
+ KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
+ IO_NO_INCREMENT,
+ FALSE);
+
+ InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
+
+ KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
+
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+SubmitIdleRequestIrp_Exit:
+
+ FreeBT_DbgPrint(3, ("SubmitIdleRequest: Leaving\n"));
+
+ return ntStatus;
+}
+
+
+VOID IdleNotificationCallback(IN PDEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS ntStatus;
+ POWER_STATE powerState;
+ KEVENT irpCompletionEvent;
+ PIRP_COMPLETION_CONTEXT irpContext;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback: Entered\n"));
+
+ //
+ // Dont idle, if the device was just disconnected or being stopped
+ // i.e. return for the following DeviceState(s)
+ // NotStarted, Stopped, PendingStop, PendingRemove, SurpriseRemoved, Removed
+ //
+
+ if(DeviceExtension->DeviceState != Working) {
+
+ return;
+ }
+
+ //
+ // If there is not already a WW IRP pending, submit one now
+ //
+ if(DeviceExtension->WaitWakeEnable) {
+
+ IssueWaitWake(DeviceExtension);
+ }
+
+
+ //
+ // power down the device
+ //
+
+ irpContext = (PIRP_COMPLETION_CONTEXT)
+ ExAllocatePool(NonPagedPool,
+ sizeof(IRP_COMPLETION_CONTEXT));
+
+ if(!irpContext) {
+
+ FreeBT_DbgPrint(1, ("FBTUSB: IdleNotificationCallback: Failed to alloc memory for irpContext\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else {
+
+ //
+ // increment the count. In the HoldIoRequestWorkerRoutine, the
+ // count is decremented twice (one for the system Irp and the
+ // other for the device Irp. An increment here compensates for
+ // the sytem irp..The decrement corresponding to this increment
+ // is in the completion function
+ //
+
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback::"));
+ FreeBT_IoIncrement(DeviceExtension);
+
+ powerState.DeviceState = (DEVICE_POWER_STATE) DeviceExtension->PowerDownLevel;
+
+ KeInitializeEvent(&irpCompletionEvent, NotificationEvent, FALSE);
+
+ irpContext->DeviceExtension = DeviceExtension;
+ irpContext->Event = &irpCompletionEvent;
+
+ ntStatus = PoRequestPowerIrp(
+ DeviceExtension->PhysicalDeviceObject,
+ IRP_MN_SET_POWER,
+ powerState,
+ (PREQUEST_POWER_COMPLETE) PoIrpCompletionFunc,
+ irpContext,
+ NULL);
+
+ if(STATUS_PENDING == ntStatus) {
+
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback::"
+ "waiting for the power irp to complete\n"));
+
+ KeWaitForSingleObject(&irpCompletionEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+ }
+
+ if(!NT_SUCCESS(ntStatus)) {
+
+ if(irpContext) {
+
+ ExFreePool(irpContext);
+ }
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationCallback: Leaving\n"));
+}
+
+
+NTSTATUS IdleNotificationRequestComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS ntStatus;
+ POWER_STATE powerState;
+ KIRQL oldIrql;
+ LARGE_INTEGER dueTime;
+ PIRP idleIrp;
+ PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationRequestCompete: Entered\n"));
+
+ idleIrp = NULL;
+
+ ntStatus = Irp->IoStatus.Status;
+ if(!NT_SUCCESS(ntStatus) && ntStatus != STATUS_NOT_SUPPORTED)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationRequestCompete: Idle irp completes with error::"));
+ switch(ntStatus)
+ {
+ case STATUS_INVALID_DEVICE_REQUEST:
+ FreeBT_DbgPrint(3, ("STATUS_INVALID_DEVICE_REQUEST\n"));
+ break;
+
+ case STATUS_CANCELLED:
+ FreeBT_DbgPrint(3, ("STATUS_CANCELLED\n"));
+ break;
+
+ case STATUS_DEVICE_BUSY:
+ FreeBT_DbgPrint(3, ("STATUS_DEVICE_BUSY\n"));
+ break;
+
+ case STATUS_POWER_STATE_INVALID:
+ FreeBT_DbgPrint(3, ("STATUS_POWER_STATE_INVALID\n"));
+ goto IdleNotificationRequestComplete_Exit;
+
+ default:
+ FreeBT_DbgPrint(3, ("default: status = %X\n", ntStatus));
+ break;
+
+ }
+
+ // if in error, issue a SetD0
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleNotificationRequestComplete::"));
+ FreeBT_IoIncrement(DeviceExtension);
+
+ powerState.DeviceState = PowerDeviceD0;
+ ntStatus = PoRequestPowerIrp(
+ DeviceExtension->PhysicalDeviceObject,
+ IRP_MN_SET_POWER,
+ powerState,
+ (PREQUEST_POWER_COMPLETE) PoIrpAsyncCompletionFunc,
+ DeviceExtension,
+ NULL);
+
+ if(!NT_SUCCESS(ntStatus))
+ FreeBT_DbgPrint(1, ("PoRequestPowerIrp failed\n"));
+
+ }
+
+IdleNotificationRequestComplete_Exit:
+ KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
+ idleCallbackInfo = DeviceExtension->IdleCallbackInfo;
+ DeviceExtension->IdleCallbackInfo = NULL;
+
+ idleIrp = (PIRP) InterlockedExchangePointer(&DeviceExtension->PendingIdleIrp, NULL);
+ InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
+
+ KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
+
+ if(idleCallbackInfo)
+ ExFreePool(idleCallbackInfo);
+
+ // Since the irp was created using IoAllocateIrp,
+ // the Irp needs to be freed using IoFreeIrp.
+ // Also return STATUS_MORE_PROCESSING_REQUIRED so that
+ // the kernel does not reference this in the near future.
+ if(idleIrp)
+ {
+ FreeBT_DbgPrint(3, ("completion routine has a valid irp and frees it\n"));
+ IoFreeIrp(Irp);
+ KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE);
+
+ }
+
+ else
+ {
+ // The CancelSelectiveSuspend routine has grabbed the Irp from the device
+ // extension. Now the last one to decrement the FreeIdleIrpCount should
+ // free the irp.
+ if (0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount))
+ {
+ FreeBT_DbgPrint(3, ("completion routine frees the irp\n"));
+ IoFreeIrp(Irp);
+ KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE);
+
+ }
+
+ }
+
+ if(DeviceExtension->SSEnable)
+ {
+ FreeBT_DbgPrint(3, ("Set the timer to fire DPCs\n"));
+ dueTime.QuadPart = -10000 * IDLE_INTERVAL; // 5000 ms
+ KeSetTimerEx(&DeviceExtension->Timer, dueTime, IDLE_INTERVAL, &DeviceExtension->DeferredProcCall);
+ FreeBT_DbgPrint(3, ("IdleNotificationRequestCompete: Leaving\n"));
+
+ }
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+}
+
+VOID CancelSelectSuspend(IN PDEVICE_EXTENSION DeviceExtension)
+{
+ PIRP irp;
+ KIRQL oldIrql;
+
+ FreeBT_DbgPrint(3, ("CancelSelectSuspend: Entered\n"));
+
+ irp = NULL;
+
+ KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
+
+ if(!CanDeviceSuspend(DeviceExtension))
+ {
+ FreeBT_DbgPrint(3, ("Device is not idle\n"));
+ irp = (PIRP) InterlockedExchangePointer(&DeviceExtension->PendingIdleIrp, NULL);
+
+ }
+
+ KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
+
+ // since we have a valid Irp ptr,
+ // we can call IoCancelIrp on it,
+ // without the fear of the irp
+ // being freed underneath us.
+ if(irp)
+ {
+ // This routine has the irp pointer.
+ // It is safe to call IoCancelIrp because we know that
+ // the compleiton routine will not free this irp unless...
+ //
+ //
+ if(IoCancelIrp(irp))
+ {
+ FreeBT_DbgPrint(3, ("IoCancelIrp returns TRUE\n"));
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("IoCancelIrp returns FALSE\n"));
+
+ }
+
+ // ....we decrement the FreeIdleIrpCount from 2 to 1.
+ // if completion routine runs ahead of us, then this routine
+ // decrements the FreeIdleIrpCount from 1 to 0 and hence shall
+ // free the irp.
+ if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount))
+ {
+ FreeBT_DbgPrint(3, ("CancelSelectSuspend frees the irp\n"));
+ IoFreeIrp(irp);
+ KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE);
+
+ }
+
+ }
+
+ FreeBT_DbgPrint(3, ("CancelSelectSuspend: Leaving\n"));
+
+ return;
+
+}
+
+VOID PoIrpCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus)
+{
+ PIRP_COMPLETION_CONTEXT irpContext;
+ irpContext = NULL;
+
+ FreeBT_DbgPrint(3, ("PoIrpCompletionFunc::"));
+
+ if(Context)
+ irpContext = (PIRP_COMPLETION_CONTEXT) Context;
+
+ // all we do is set the event and decrement the count
+ if(irpContext)
+ {
+ KeSetEvent(irpContext->Event, 0, FALSE);
+ FreeBT_IoDecrement(irpContext->DeviceExtension);
+ ExFreePool(irpContext);
+
+ }
+
+ return;
+
+}
+
+VOID PoIrpAsyncCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus)
+{
+ PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Context;
+ FreeBT_DbgPrint(3, ("PoIrpAsyncCompletionFunc::"));
+ FreeBT_IoDecrement(DeviceExtension);
+
+ return;
+
+}
+
+VOID WWIrpCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus)
+{
+ PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Context;
+
+ FreeBT_DbgPrint(3, ("WWIrpCompletionFunc::"));
+ FreeBT_IoDecrement(DeviceExtension);
+
+ return;
+
+}
\ No newline at end of file
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#include "stdio.h"
+#include "fbtusb.h"
+#include "fbtpnp.h"
+#include "fbtpwr.h"
+#include "fbtdev.h"
+#include "fbtrwr.h"
+#include "fbtwmi.h"
+
+#include "fbtusr.h"
+
+// Handle PNP events
+NTSTATUS FreeBT_DispatchPnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ PIO_STACK_LOCATION irpStack;
+ PDEVICE_EXTENSION deviceExtension;
+ KEVENT startDeviceEvent;
+ NTSTATUS ntStatus;
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ // since the device is removed, fail the Irp.
+ if (Removed == deviceExtension->DeviceState)
+ {
+ ntStatus = STATUS_DELETE_PENDING;
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return ntStatus;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPnP::"));
+ FreeBT_IoIncrement(deviceExtension);
+ if (irpStack->MinorFunction == IRP_MN_START_DEVICE)
+ {
+ ASSERT(deviceExtension->IdleReqPend == 0);
+
+ }
+
+ else
+ {
+ if (deviceExtension->SSEnable)
+ {
+ CancelSelectSuspend(deviceExtension);
+
+ }
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: ///////////////////////////////////////////\n"));
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPnP::"));
+ FreeBT_DbgPrint(2, (PnPMinorFunctionString(irpStack->MinorFunction)));
+ switch (irpStack->MinorFunction)
+ {
+ case IRP_MN_START_DEVICE:
+ ntStatus = HandleStartDevice(DeviceObject, Irp);
+ break;
+
+ case IRP_MN_QUERY_STOP_DEVICE:
+ // if we cannot stop the device, we fail the query stop irp
+ ntStatus = CanStopDevice(DeviceObject, Irp);
+ if(NT_SUCCESS(ntStatus))
+ {
+ ntStatus = HandleQueryStopDevice(DeviceObject, Irp);
+ return ntStatus;
+
+ }
+
+ break;
+
+ case IRP_MN_CANCEL_STOP_DEVICE:
+ ntStatus = HandleCancelStopDevice(DeviceObject, Irp);
+ break;
+
+ case IRP_MN_STOP_DEVICE:
+ ntStatus = HandleStopDevice(DeviceObject, Irp);
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPnP::IRP_MN_STOP_DEVICE::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ return ntStatus;
+
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ // if we cannot remove the device, we fail the query remove irp
+ ntStatus = HandleQueryRemoveDevice(DeviceObject, Irp);
+
+ return ntStatus;
+
+ case IRP_MN_CANCEL_REMOVE_DEVICE:
+ ntStatus = HandleCancelRemoveDevice(DeviceObject, Irp);
+ break;
+
+ case IRP_MN_SURPRISE_REMOVAL:
+ ntStatus = HandleSurpriseRemoval(DeviceObject, Irp);
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPnP::IRP_MN_SURPRISE_REMOVAL::"));
+ FreeBT_IoDecrement(deviceExtension);
+ return ntStatus;
+
+ case IRP_MN_REMOVE_DEVICE:
+ ntStatus = HandleRemoveDevice(DeviceObject, Irp);
+ return ntStatus;
+
+ case IRP_MN_QUERY_CAPABILITIES:
+ ntStatus = HandleQueryCapabilities(DeviceObject, Irp);
+ break;
+
+ default:
+ IoSkipCurrentIrpStackLocation(Irp);
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPnP::default::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ return ntStatus;
+
+ }
+
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPnP::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ return ntStatus;
+
+}
+
+NTSTATUS HandleStartDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ KIRQL oldIrql;
+ KEVENT startDeviceEvent;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ LARGE_INTEGER dueTime;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleStartDevice: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ deviceExtension->UsbConfigurationDescriptor = NULL;
+ deviceExtension->UsbInterface = NULL;
+ deviceExtension->PipeContext = NULL;
+
+ // We cannot touch the device (send it any non pnp irps) until a
+ // start device has been passed down to the lower drivers.
+ // first pass the Irp down
+ KeInitializeEvent(&startDeviceEvent, NotificationEvent, FALSE);
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
+ (PVOID)&startDeviceEvent,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if (ntStatus == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&startDeviceEvent, Executive, KernelMode, FALSE, NULL);
+ ntStatus = Irp->IoStatus.Status;
+
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: HandleStartDevice: Lower drivers failed this Irp (0x%08x)\n", ntStatus));
+ return ntStatus;
+
+ }
+
+ // Read the device descriptor, configuration descriptor
+ // and select the interface descriptors
+ ntStatus = ReadandSelectDescriptors(DeviceObject);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: HandleStartDevice: ReadandSelectDescriptors failed (0x%08x)\n", ntStatus));
+ return ntStatus;
+
+ }
+
+ // enable the symbolic links for system components to open
+ // handles to the device
+ ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName, TRUE);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: HandleStartDevice: IoSetDeviceInterfaceState failed (0x%08x)\n", ntStatus));
+ return ntStatus;
+
+ }
+
+ KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
+
+ SET_NEW_PNP_STATE(deviceExtension, Working);
+ deviceExtension->QueueState = AllowRequests;
+
+ KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
+
+ deviceExtension->FlagWWOutstanding = 0;
+ deviceExtension->FlagWWCancel = 0;
+ deviceExtension->WaitWakeIrp = NULL;
+
+ if (deviceExtension->WaitWakeEnable)
+ {
+ IssueWaitWake(deviceExtension);
+
+ }
+
+ ProcessQueuedRequests(deviceExtension);
+ if (WinXpOrBetter == deviceExtension->WdmVersion)
+ {
+ deviceExtension->SSEnable = deviceExtension->SSRegistryEnable;
+
+ // set timer.for selective suspend requests
+ if (deviceExtension->SSEnable)
+ {
+ dueTime.QuadPart = -10000 * IDLE_INTERVAL; // 5000 ms
+ KeSetTimerEx(&deviceExtension->Timer, dueTime, IDLE_INTERVAL, &deviceExtension->DeferredProcCall);
+ deviceExtension->FreeIdleIrpCount = 0;
+
+ }
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleStartDevice: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+
+NTSTATUS ReadandSelectDescriptors(IN PDEVICE_OBJECT DeviceObject)
+{
+ PURB urb;
+ ULONG siz;
+ NTSTATUS ntStatus;
+ PUSB_DEVICE_DESCRIPTOR deviceDescriptor;
+
+ urb = NULL;
+ deviceDescriptor = NULL;
+
+ // 1. Read the device descriptor
+ urb = (PURB) ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+ if(urb)
+ {
+ siz = sizeof(USB_DEVICE_DESCRIPTOR);
+ deviceDescriptor = (PUSB_DEVICE_DESCRIPTOR) ExAllocatePool(NonPagedPool, siz);
+ if (deviceDescriptor)
+ {
+ UsbBuildGetDescriptorRequest(
+ urb,
+ (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+ USB_DEVICE_DESCRIPTOR_TYPE,
+ 0,
+ 0,
+ deviceDescriptor,
+ NULL,
+ siz,
+ NULL);
+
+ ntStatus = CallUSBD(DeviceObject, urb);
+ if (NT_SUCCESS(ntStatus))
+ {
+ ASSERT(deviceDescriptor->bNumConfigurations);
+ ntStatus = ConfigureDevice(DeviceObject);
+
+ }
+
+ ExFreePool(urb);
+ ExFreePool(deviceDescriptor);
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: ReadandSelectDescriptors: Failed to allocate memory for deviceDescriptor"));
+ ExFreePool(urb);
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: ReadandSelectDescriptors: Failed to allocate memory for urb"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+
+ return ntStatus;
+
+}
+
+NTSTATUS ConfigureDevice(IN PDEVICE_OBJECT DeviceObject)
+{
+ PURB urb;
+ ULONG siz;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
+
+ urb = NULL;
+ configurationDescriptor = NULL;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ // Read the first configuration descriptor
+ // This requires two steps:
+ // 1. Read the fixed sized configuration desciptor (CD)
+ // 2. Read the CD with all embedded interface and endpoint descriptors
+ urb = (PURB) ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+ if (urb)
+ {
+ siz = sizeof(USB_CONFIGURATION_DESCRIPTOR);
+ configurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) ExAllocatePool(NonPagedPool, siz);
+
+ if(configurationDescriptor)
+ {
+ UsbBuildGetDescriptorRequest(
+ urb,
+ (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+ USB_CONFIGURATION_DESCRIPTOR_TYPE,
+ 0,
+ 0,
+ configurationDescriptor,
+ NULL,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR),
+ NULL);
+
+ ntStatus = CallUSBD(DeviceObject, urb);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: ConfigureDevice: UsbBuildGetDescriptorRequest failed\n"));
+ goto ConfigureDevice_Exit;
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: ConfigureDevice: Failed to allocate mem for config Descriptor\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto ConfigureDevice_Exit;
+
+ }
+
+ siz = configurationDescriptor->wTotalLength;
+ ExFreePool(configurationDescriptor);
+
+ configurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) ExAllocatePool(NonPagedPool, siz);
+ if (configurationDescriptor)
+ {
+ UsbBuildGetDescriptorRequest(
+ urb,
+ (USHORT)sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+ USB_CONFIGURATION_DESCRIPTOR_TYPE,
+ 0,
+ 0,
+ configurationDescriptor,
+ NULL,
+ siz,
+ NULL);
+
+ ntStatus = CallUSBD(DeviceObject, urb);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1,("FBTUSB: ConfigureDevice: Failed to read configuration descriptor"));
+ goto ConfigureDevice_Exit;
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: ConfigureDevice: Failed to alloc mem for config Descriptor\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto ConfigureDevice_Exit;
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: ConfigureDevice: Failed to allocate memory for urb\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto ConfigureDevice_Exit;
+
+ }
+
+ if (configurationDescriptor)
+ {
+ // save a copy of configurationDescriptor in deviceExtension
+ // remember to free it later.
+ deviceExtension->UsbConfigurationDescriptor = configurationDescriptor;
+
+ if (configurationDescriptor->bmAttributes & REMOTE_WAKEUP_MASK)
+ {
+ // this configuration supports remote wakeup
+ deviceExtension->WaitWakeEnable = 1;
+
+ }
+
+ else
+ {
+ deviceExtension->WaitWakeEnable = 0;
+
+ }
+
+ ntStatus = SelectInterfaces(DeviceObject, configurationDescriptor);
+
+ }
+
+ else
+ {
+ deviceExtension->UsbConfigurationDescriptor = NULL;
+
+ }
+
+ConfigureDevice_Exit:
+ if (urb)
+ {
+ ExFreePool(urb);
+
+ }
+
+ return ntStatus;
+
+}
+
+NTSTATUS SelectInterfaces(IN PDEVICE_OBJECT DeviceObject, IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
+{
+ LONG numberOfInterfaces, interfaceNumber, interfaceindex;
+ ULONG i;
+ PURB urb;
+ PUCHAR pInf;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
+ PUSBD_INTERFACE_LIST_ENTRY interfaceList,
+ tmp;
+ PUSBD_INTERFACE_INFORMATION Interface;
+
+ urb = NULL;
+ Interface = NULL;
+ interfaceDescriptor = NULL;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ numberOfInterfaces = ConfigurationDescriptor->bNumInterfaces;
+ interfaceindex = interfaceNumber = 0;
+
+ // Parse the configuration descriptor for the interface;
+ tmp = interfaceList = (PUSBD_INTERFACE_LIST_ENTRY)
+ ExAllocatePool(NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (numberOfInterfaces + 1));
+
+ if (!tmp)
+ {
+
+ FreeBT_DbgPrint(1, ("FBTUSB: SelectInterfaces: Failed to allocate mem for interfaceList\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+
+ FreeBT_DbgPrint(3, ("FBTUSB: -------------\n"));
+ FreeBT_DbgPrint(3, ("FBTUSB: Number of interfaces %d\n", numberOfInterfaces));
+
+ while (interfaceNumber < numberOfInterfaces)
+ {
+ interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
+ ConfigurationDescriptor,
+ ConfigurationDescriptor,
+ interfaceindex,
+ 0, -1, -1, -1);
+
+ if (interfaceDescriptor)
+ {
+ interfaceList->InterfaceDescriptor = interfaceDescriptor;
+ interfaceList->Interface = NULL;
+ interfaceList++;
+ interfaceNumber++;
+
+ }
+
+ interfaceindex++;
+
+ }
+
+ interfaceList->InterfaceDescriptor = NULL;
+ interfaceList->Interface = NULL;
+ urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor, tmp);
+
+ if (urb)
+ {
+ Interface = &urb->UrbSelectConfiguration.Interface;
+ for (i=0; i<Interface->NumberOfPipes; i++)
+ {
+ // perform pipe initialization here
+ // set the transfer size and any pipe flags we use
+ // USBD sets the rest of the Interface struct members
+ Interface->Pipes[i].MaximumTransferSize = USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
+
+ }
+
+ ntStatus = CallUSBD(DeviceObject, urb);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // save a copy of interface information in the device extension.
+ deviceExtension->UsbInterface = (PUSBD_INTERFACE_INFORMATION) ExAllocatePool(NonPagedPool, Interface->Length);
+ if (deviceExtension->UsbInterface)
+ {
+ RtlCopyMemory(deviceExtension->UsbInterface, Interface, Interface->Length);
+
+ }
+
+ else
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ FreeBT_DbgPrint(1, ("FBTUSB: SelectInterfaces: Memory alloc for UsbInterface failed\n"));
+
+ }
+
+ // Dump the interface to the debugger
+ Interface = &urb->UrbSelectConfiguration.Interface;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: ---------\n"));
+ FreeBT_DbgPrint(3, ("FBTUSB: NumberOfPipes 0x%x\n", Interface->NumberOfPipes));
+ FreeBT_DbgPrint(3, ("FBTUSB: Length 0x%x\n", Interface->Length));
+ FreeBT_DbgPrint(3, ("FBTUSB: Alt Setting 0x%x\n", Interface->AlternateSetting));
+ FreeBT_DbgPrint(3, ("FBTUSB: Interface Number 0x%x\n", Interface->InterfaceNumber));
+ FreeBT_DbgPrint(3, ("FBTUSB: Class, subclass, protocol 0x%x 0x%x 0x%x\n",
+ Interface->Class,
+ Interface->SubClass,
+ Interface->Protocol));
+
+ if (Interface->Class==FREEBT_USB_STDCLASS && Interface->SubClass==FREEBT_USB_STDSUBCLASS &&
+ Interface->Protocol==FREEBT_USB_STDPROTOCOL)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: This is a standard USB Bluetooth device\n"));
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: WARNING: This device does not report itself as a standard USB Bluetooth device\n"));
+
+ }
+
+ // Initialize the PipeContext
+ // Dump the pipe info
+ deviceExtension->PipeContext = (PFREEBT_PIPE_CONTEXT) ExAllocatePool(
+ NonPagedPool,
+ Interface->NumberOfPipes *
+ sizeof(FREEBT_PIPE_CONTEXT));
+
+ if (!deviceExtension->PipeContext)
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ FreeBT_DbgPrint(1, ("FBTUSB: Memory alloc for UsbInterface failed\n"));
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: SelectInterfaces: Allocated PipeContext %p\n", deviceExtension->PipeContext));
+ for (i=0; i<Interface->NumberOfPipes; i++)
+ {
+ deviceExtension->PipeContext[i].PipeOpen = FALSE;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: ---------\n"));
+ FreeBT_DbgPrint(3, ("FBTUSB: PipeType 0x%x\n", Interface->Pipes[i].PipeType));
+ FreeBT_DbgPrint(3, ("FBTUSB: EndpointAddress 0x%x\n", Interface->Pipes[i].EndpointAddress));
+ FreeBT_DbgPrint(3, ("FBTUSB: MaxPacketSize 0x%x\n", Interface->Pipes[i].MaximumPacketSize));
+ FreeBT_DbgPrint(3, ("FBTUSB: Interval 0x%x\n", Interface->Pipes[i].Interval));
+ FreeBT_DbgPrint(3, ("FBTUSB: Handle 0x%x\n", Interface->Pipes[i].PipeHandle));
+ FreeBT_DbgPrint(3, ("FBTUSB: MaximumTransferSize 0x%x\n", Interface->Pipes[i].MaximumTransferSize));
+
+ // Log the pipes
+ // Note the HCI Command endpoint won't appear here, because the Default Control Pipe
+ // is used for this. The Default Control Pipe is always present at EndPointAddress 0x0
+ switch (Interface->Pipes[i].EndpointAddress)
+ {
+ case FREEBT_STDENDPOINT_HCIEVENT:
+ deviceExtension->PipeContext[i].PipeType=HciEventPipe;
+ deviceExtension->EventPipe=Interface->Pipes[i];
+ FreeBT_DbgPrint(3, ("FBTUSB: HCI Event Endpoint\n"));
+ break;
+
+ case FREEBT_STDENDPOINT_ACLIN:
+ deviceExtension->PipeContext[i].PipeType=AclDataIn;
+ deviceExtension->DataInPipe=Interface->Pipes[i];
+ FreeBT_DbgPrint(3, ("FBTUSB: ACL Data In Endpoint\n"));
+ break;
+
+ case FREEBT_STDENDPOINT_ACLOUT:
+ deviceExtension->PipeContext[i].PipeType=AclDataOut;
+ deviceExtension->DataOutPipe=Interface->Pipes[i];
+ FreeBT_DbgPrint(3, ("FBTUSB: ACL Data Out Endpoint\n"));
+ break;
+
+ case FREEBT_STDENDPOINT_AUDIOIN:
+ deviceExtension->PipeContext[i].PipeType=SCODataIn;
+ deviceExtension->AudioInPipe=Interface->Pipes[i];
+ FreeBT_DbgPrint(3, ("FBTUSB: ACL Data Out Endpoint\n"));
+ break;
+
+ case FREEBT_STDENDPOINT_AUDIOOUT:
+ deviceExtension->PipeContext[i].PipeType=SCODataOut;
+ deviceExtension->AudioOutPipe=Interface->Pipes[i];
+ FreeBT_DbgPrint(3, ("FBTUSB: ACL Data Out Endpoint\n"));
+ break;
+
+ }
+
+ }
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: ---------\n"));
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: SelectInterfaces: Failed to select an interface\n"));
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: SelectInterfaces: USBD_CreateConfigurationRequestEx failed\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ if (tmp)
+ {
+ ExFreePool(tmp);
+
+ }
+
+ if (urb)
+ {
+ ExFreePool(urb);
+
+ }
+
+ return ntStatus;
+}
+
+
+NTSTATUS DeconfigureDevice(IN PDEVICE_OBJECT DeviceObject)
+{
+ PURB urb;
+ ULONG siz;
+ NTSTATUS ntStatus;
+
+ siz = sizeof(struct _URB_SELECT_CONFIGURATION);
+ urb = (PURB) ExAllocatePool(NonPagedPool, siz);
+ if (urb)
+ {
+ UsbBuildSelectConfigurationRequest(urb, (USHORT)siz, NULL);
+ ntStatus = CallUSBD(DeviceObject, urb);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: DeconfigureDevice: Failed to deconfigure device\n"));
+
+ }
+
+ ExFreePool(urb);
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: DeconfigureDevice: Failed to allocate urb\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ return ntStatus;
+
+}
+
+NTSTATUS CallUSBD(IN PDEVICE_OBJECT DeviceObject, IN PURB Urb)
+{
+ PIRP irp;
+ KEVENT event;
+ NTSTATUS ntStatus;
+ IO_STATUS_BLOCK ioStatus;
+ PIO_STACK_LOCATION nextStack;
+ PDEVICE_EXTENSION deviceExtension;
+
+ irp = NULL;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+ irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
+ deviceExtension->TopOfStackDeviceObject,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ TRUE,
+ &event,
+ &ioStatus);
+
+ if (!irp)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: CallUSBD: IoBuildDeviceIoControlRequest failed\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ nextStack = IoGetNextIrpStackLocation(irp);
+ ASSERT(nextStack != NULL);
+ nextStack->Parameters.Others.Argument1 = Urb;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: CallUSBD::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
+ if (ntStatus == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ ntStatus = ioStatus.Status;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: CallUSBD::"));
+ FreeBT_IoDecrement(deviceExtension);
+ return ntStatus;
+
+}
+
+NTSTATUS HandleQueryStopDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ KIRQL oldIrql;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleQueryStopDevice: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ // If we can stop the device, we need to set the QueueState to
+ // HoldRequests so further requests will be queued.
+ KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
+
+ SET_NEW_PNP_STATE(deviceExtension, PendingStop);
+ deviceExtension->QueueState = HoldRequests;
+
+ KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
+
+ // wait for the existing ones to be finished.
+ // first, decrement this operation
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleQueryStopDevice::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ KeWaitForSingleObject(&deviceExtension->StopEvent, Executive, KernelMode, FALSE, NULL);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleQueryStopDevice: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+NTSTATUS HandleCancelStopDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ KIRQL oldIrql;
+ KEVENT event;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleCancelStopDevice: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ // Send this IRP down and wait for it to come back.
+ // Set the QueueState flag to AllowRequests,
+ // and process all the previously queued up IRPs.
+
+ // First check to see whether you have received cancel-stop
+ // without first receiving a query-stop. This could happen if someone
+ // above us fails a query-stop and passes down the subsequent
+ // cancel-stop.
+ if(PendingStop == deviceExtension->DeviceState)
+ {
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
+ (PVOID)&event,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if(ntStatus == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ ntStatus = Irp->IoStatus.Status;
+
+ }
+
+ if(NT_SUCCESS(ntStatus))
+ {
+ KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
+
+ RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
+ deviceExtension->QueueState = AllowRequests;
+ ASSERT(deviceExtension->DeviceState == Working);
+
+ KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
+
+ ProcessQueuedRequests(deviceExtension);
+
+ }
+
+ }
+
+ else
+ {
+ // spurious Irp
+ ntStatus = STATUS_SUCCESS;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleCancelStopDevice: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+NTSTATUS HandleStopDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ KIRQL oldIrql;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleStopDevice: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ if(WinXpOrBetter == deviceExtension->WdmVersion)
+ {
+ if(deviceExtension->SSEnable)
+ {
+ // Cancel the timer so that the DPCs are no longer fired.
+ // Thus, we are making judicious usage of our resources.
+ // we do not need DPCs because the device is stopping.
+ // The timers are re-initialized while handling the start
+ // device irp.
+ KeCancelTimer(&deviceExtension->Timer);
+
+ // after the device is stopped, it can be surprise removed.
+ // we set this to 0, so that we do not attempt to cancel
+ // the timer while handling surprise remove or remove irps.
+ // when we get the start device request, this flag will be
+ // reinitialized.
+ deviceExtension->SSEnable = 0;
+
+ // make sure that if a DPC was fired before we called cancel timer,
+ // then the DPC and work-time have run to their completion
+ KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent, Executive, KernelMode, FALSE, NULL);
+
+ // make sure that the selective suspend request has been completed.
+ KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, Executive, KernelMode, FALSE, NULL);
+
+ }
+
+ }
+
+ // after the stop Irp is sent to the lower driver object,
+ // the driver must not send any more Irps down that touch
+ // the device until another Start has occurred.
+ if (deviceExtension->WaitWakeEnable)
+ {
+ CancelWaitWake(deviceExtension);
+
+ }
+
+ KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
+
+ SET_NEW_PNP_STATE(deviceExtension, Stopped);
+
+ KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
+
+ // This is the right place to actually give up all the resources used
+ // This might include calls to IoDisconnectInterrupt, MmUnmapIoSpace,
+ // etc.
+ ReleaseMemory(DeviceObject);
+
+ ntStatus = DeconfigureDevice(DeviceObject);
+
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleStopDevice: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+NTSTATUS HandleQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ KIRQL oldIrql;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleQueryRemoveDevice: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ // If we can allow removal of the device, we should set the QueueState
+ // to HoldRequests so further requests will be queued. This is required
+ // so that we can process queued up requests in cancel-remove just in
+ // case somebody else in the stack fails the query-remove.
+ ntStatus = CanRemoveDevice(DeviceObject, Irp);
+
+ KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
+
+ deviceExtension->QueueState = HoldRequests;
+ SET_NEW_PNP_STATE(deviceExtension, PendingRemove);
+
+ KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleQueryRemoveDevice::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ // Wait for all the requests to be completed
+ KeWaitForSingleObject(&deviceExtension->StopEvent, Executive, KernelMode, FALSE, NULL);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleQueryRemoveDevice: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+NTSTATUS HandleCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ KIRQL oldIrql;
+ KEVENT event;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleCancelRemoveDevice: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ // We need to reset the QueueState flag to ProcessRequest,
+ // since the device resume its normal activities.
+
+ // First check to see whether you have received cancel-remove
+ // without first receiving a query-remove. This could happen if
+ // someone above us fails a query-remove and passes down the
+ // subsequent cancel-remove.
+ if(PendingRemove == deviceExtension->DeviceState)
+ {
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
+ (PVOID)&event,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if(ntStatus == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ ntStatus = Irp->IoStatus.Status;
+
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
+
+ deviceExtension->QueueState = AllowRequests;
+ RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
+
+ KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
+
+ // process the queued requests that arrive between
+ // QUERY_REMOVE and CANCEL_REMOVE
+ ProcessQueuedRequests(deviceExtension);
+
+ }
+
+ }
+
+ else
+ {
+ // spurious cancel-remove
+ ntStatus = STATUS_SUCCESS;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleCancelRemoveDevice: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+NTSTATUS HandleSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ KIRQL oldIrql;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleSurpriseRemoval: Entered\n"));
+
+ // initialize variables
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ // 1. fail pending requests
+ // 2. return device and memory resources
+ // 3. disable interfaces
+ if(deviceExtension->WaitWakeEnable)
+ {
+ CancelWaitWake(deviceExtension);
+
+ }
+
+
+ if (WinXpOrBetter == deviceExtension->WdmVersion)
+ {
+ if (deviceExtension->SSEnable)
+ {
+ // Cancel the timer so that the DPCs are no longer fired.
+ // we do not need DPCs because the device has been surprise
+ // removed
+ KeCancelTimer(&deviceExtension->Timer);
+
+ deviceExtension->SSEnable = 0;
+
+ // make sure that if a DPC was fired before we called cancel timer,
+ // then the DPC and work-time have run to their completion
+ KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent, Executive, KernelMode, FALSE, NULL);
+
+ // make sure that the selective suspend request has been completed.
+ KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, Executive, KernelMode, FALSE, NULL);
+
+ }
+
+ }
+
+ KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
+ deviceExtension->QueueState = FailRequests;
+ SET_NEW_PNP_STATE(deviceExtension, SurpriseRemoved);
+ KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
+
+ ProcessQueuedRequests(deviceExtension);
+
+ ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName, FALSE);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: HandleSurpriseRemoval: IoSetDeviceInterfaceState::disable:failed\n"));
+
+ }
+
+ FreeBT_AbortPipes(DeviceObject);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleSurpriseRemoval: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+NTSTATUS HandleRemoveDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ KIRQL oldIrql;
+ KEVENT event;
+ ULONG requestCount;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleRemoveDevice: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ // The Plug & Play system has dictated the removal of this device. We
+ // have no choice but to detach and delete the device object.
+ // (If we wanted to express an interest in preventing this removal,
+ // we should have failed the query remove IRP).
+ if(SurpriseRemoved != deviceExtension->DeviceState)
+ {
+
+ // we are here after QUERY_REMOVE
+ KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
+ deviceExtension->QueueState = FailRequests;
+ KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
+
+ if(deviceExtension->WaitWakeEnable)
+ {
+ CancelWaitWake(deviceExtension);
+
+ }
+
+ if(WinXpOrBetter == deviceExtension->WdmVersion)
+ {
+ if (deviceExtension->SSEnable)
+ {
+ // Cancel the timer so that the DPCs are no longer fired.
+ // we do not need DPCs because the device has been removed
+ KeCancelTimer(&deviceExtension->Timer);
+
+ deviceExtension->SSEnable = 0;
+
+ // make sure that if a DPC was fired before we called cancel timer,
+ // then the DPC and work-time have run to their completion
+ KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent, Executive, KernelMode, FALSE, NULL);
+
+ // make sure that the selective suspend request has been completed.
+ KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, Executive, KernelMode, FALSE, NULL);
+
+ }
+
+ }
+
+ ProcessQueuedRequests(deviceExtension);
+
+ ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName, FALSE);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: HandleRemoveDevice: IoSetDeviceInterfaceState::disable:failed\n"));
+
+ }
+
+ FreeBT_AbortPipes(DeviceObject);
+
+ }
+
+ KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
+ SET_NEW_PNP_STATE(deviceExtension, Removed);
+ KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
+#ifdef ENABLE_WMI
+ FreeBT_WmiDeRegistration(deviceExtension);
+#endif
+
+ // Need 2 decrements
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleRemoveDevice::"));
+ requestCount = FreeBT_IoDecrement(deviceExtension);
+
+ ASSERT(requestCount > 0);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleRemoveDevice::"));
+ requestCount = FreeBT_IoDecrement(deviceExtension);
+
+ KeWaitForSingleObject(&deviceExtension->RemoveEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ ReleaseMemory(DeviceObject);
+
+ // We need to send the remove down the stack before we detach,
+ // but we don't need to wait for the completion of this operation
+ // (and to register a completion routine).
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+
+ IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
+ IoDeleteDevice(DeviceObject);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleRemoveDevice: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+NTSTATUS HandleQueryCapabilities(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ ULONG i;
+ KEVENT event;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ PDEVICE_CAPABILITIES pdc;
+ PIO_STACK_LOCATION irpStack;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleQueryCapabilities: Entered\n"));
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ pdc = irpStack->Parameters.DeviceCapabilities.Capabilities;
+
+ if(pdc->Version < 1 || pdc->Size < sizeof(DEVICE_CAPABILITIES))
+ {
+
+ FreeBT_DbgPrint(1, ("FBTUSB: HandleQueryCapabilities::request failed\n"));
+ ntStatus = STATUS_UNSUCCESSFUL;
+ return ntStatus;
+
+ }
+
+ // Add in the SurpriseRemovalOK bit before passing it down.
+ pdc->SurpriseRemovalOK = TRUE;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
+ (PVOID)&event,
+ TRUE,
+ TRUE,
+ TRUE);
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if(ntStatus == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ ntStatus = Irp->IoStatus.Status;
+
+ }
+
+ // initialize PowerDownLevel to disabled
+ deviceExtension->PowerDownLevel = PowerDeviceUnspecified;
+ if(NT_SUCCESS(ntStatus))
+ {
+ deviceExtension->DeviceCapabilities = *pdc;
+ for(i = PowerSystemSleeping1; i <= PowerSystemSleeping3; i++)
+ {
+ if(deviceExtension->DeviceCapabilities.DeviceState[i] < PowerDeviceD3)
+ {
+ deviceExtension->PowerDownLevel = deviceExtension->DeviceCapabilities.DeviceState[i];
+
+ }
+
+ }
+
+ // since its safe to surprise-remove this device, we shall
+ // set the SurpriseRemoveOK flag to supress any dialog to
+ // user.
+ pdc->SurpriseRemovalOK = 1;
+
+ }
+
+ if(deviceExtension->PowerDownLevel == PowerDeviceUnspecified ||
+ deviceExtension->PowerDownLevel <= PowerDeviceD0)
+ {
+ deviceExtension->PowerDownLevel = PowerDeviceD2;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleQueryCapabilities: Leaving\n"));
+
+ return ntStatus;
+}
+
+
+VOID DpcRoutine(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
+/*++
+
+ DPC routine triggered by the timer to check the idle state
+ of the device and submit an idle request for the device.
+
+ --*/
+{
+ NTSTATUS ntStatus;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_WORKITEM item;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: DpcRoutine: Entered\n"));
+
+ deviceObject = (PDEVICE_OBJECT)DeferredContext;
+ deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
+
+ // Clear this event since a DPC has been fired!
+ KeClearEvent(&deviceExtension->NoDpcWorkItemPendingEvent);
+
+ if(CanDeviceSuspend(deviceExtension))
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: DpcRoutine: Device is Idle\n"));
+ item = IoAllocateWorkItem(deviceObject);
+
+ if (item)
+ {
+ IoQueueWorkItem(item, IdleRequestWorkerRoutine, DelayedWorkQueue, item);
+ ntStatus = STATUS_PENDING;
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: DpcRoutine: Cannot alloc memory for work item\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent, IO_NO_INCREMENT, FALSE);
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: DpcRoutine: Idle event not signaled\n"));
+ KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent, IO_NO_INCREMENT, FALSE);
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: DpcRoutine: Leaving\n"));
+}
+
+
+VOID IdleRequestWorkerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
+{
+ PIRP irp;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_WORKITEM workItem;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleRequestWorkerRoutine: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ workItem = (PIO_WORKITEM) Context;
+
+ if(CanDeviceSuspend(deviceExtension))
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleRequestWorkerRoutine: Device is idle\n"));
+ ntStatus = SubmitIdleRequestIrp(deviceExtension);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: IdleRequestWorkerRoutine: SubmitIdleRequestIrp failed\n"));
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleRequestWorkerRoutine: Device is not idle\n"));
+
+ }
+
+ IoFreeWorkItem(workItem);
+
+ KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent, IO_NO_INCREMENT, FALSE);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: IdleRequestsWorkerRoutine: Leaving\n"));
+
+}
+
+
+VOID ProcessQueuedRequests(IN OUT PDEVICE_EXTENSION DeviceExtension)
+/*++
+
+Routine Description:
+
+ Remove and process the entries in the queue. If this routine is called
+ when processing IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE
+ or IRP_MN_START_DEVICE, the requests are passed to the next lower driver.
+ If the routine is called when IRP_MN_REMOVE_DEVICE is received, the IRPs
+ are complete with STATUS_DELETE_PENDING
+
+Arguments:
+
+ DeviceExtension - pointer to device extension
+
+Return Value:
+
+ None
+
+--*/
+{
+ KIRQL oldIrql;
+ PIRP nextIrp,
+ cancelledIrp;
+ PVOID cancelRoutine;
+ LIST_ENTRY cancelledIrpList;
+ PLIST_ENTRY listEntry;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: ProcessQueuedRequests: Entered\n"));
+
+ cancelRoutine = NULL;
+ InitializeListHead(&cancelledIrpList);
+
+ // 1. dequeue the entries in the queue
+ // 2. reset the cancel routine
+ // 3. process them
+ // 3a. if the device is active, send them down
+ // 3b. else complete with STATUS_DELETE_PENDING
+ while(1)
+ {
+ KeAcquireSpinLock(&DeviceExtension->QueueLock, &oldIrql);
+ if(IsListEmpty(&DeviceExtension->NewRequestsQueue))
+ {
+ KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
+ break;
+
+ }
+
+ listEntry = RemoveHeadList(&DeviceExtension->NewRequestsQueue);
+ nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
+
+ cancelRoutine = IoSetCancelRoutine(nextIrp, NULL);
+
+ // check if its already cancelled
+ if (nextIrp->Cancel)
+ {
+ if(cancelRoutine)
+ {
+ // the cancel routine for this IRP hasnt been called yet
+ // so queue the IRP in the cancelledIrp list and complete
+ // after releasing the lock
+ InsertTailList(&cancelledIrpList, listEntry);
+
+ }
+
+ else
+ {
+ // the cancel routine has run
+ // it must be waiting to hold the queue lock
+ // so initialize the IRPs listEntry
+ InitializeListHead(listEntry);
+
+ }
+
+ KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
+
+ }
+
+ else
+ {
+ KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
+ if(FailRequests == DeviceExtension->QueueState)
+ {
+ nextIrp->IoStatus.Information = 0;
+ nextIrp->IoStatus.Status = STATUS_DELETE_PENDING;
+ IoCompleteRequest(nextIrp, IO_NO_INCREMENT);
+
+ }
+
+ else
+ {
+ PIO_STACK_LOCATION irpStack;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: ProcessQueuedRequests::"));
+ FreeBT_IoIncrement(DeviceExtension);
+
+ IoSkipCurrentIrpStackLocation(nextIrp);
+ IoCallDriver(DeviceExtension->TopOfStackDeviceObject, nextIrp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: ProcessQueuedRequests::"));
+ FreeBT_IoDecrement(DeviceExtension);
+
+ }
+
+ }
+
+ }
+
+ while(!IsListEmpty(&cancelledIrpList))
+ {
+ PLIST_ENTRY cancelEntry = RemoveHeadList(&cancelledIrpList);
+
+ cancelledIrp = CONTAINING_RECORD(cancelEntry, IRP, Tail.Overlay.ListEntry);
+ cancelledIrp->IoStatus.Status = STATUS_CANCELLED;
+ cancelledIrp->IoStatus.Information = 0;
+
+ IoCompleteRequest(cancelledIrp, IO_NO_INCREMENT);
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: ProcessQueuedRequests: Leaving\n"));
+
+ return;
+
+}
+
+NTSTATUS FreeBT_GetRegistryDword(IN PWCHAR RegPath, IN PWCHAR ValueName, IN OUT PULONG Value)
+{
+ ULONG defaultData;
+ WCHAR buffer[MAXIMUM_FILENAME_LENGTH];
+ NTSTATUS ntStatus;
+ UNICODE_STRING regPath;
+ RTL_QUERY_REGISTRY_TABLE paramTable[2];
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetRegistryDword: Entered\n"));
+
+ regPath.Length = 0;
+ regPath.MaximumLength = MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR);
+ regPath.Buffer = buffer;
+
+ RtlZeroMemory(regPath.Buffer, regPath.MaximumLength);
+ RtlMoveMemory(regPath.Buffer, RegPath, wcslen(RegPath) * sizeof(WCHAR));
+ RtlZeroMemory(paramTable, sizeof(paramTable));
+
+ paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[0].Name = ValueName;
+ paramTable[0].EntryContext = Value;
+ paramTable[0].DefaultType = REG_DWORD;
+ paramTable[0].DefaultData = &defaultData;
+ paramTable[0].DefaultLength = sizeof(ULONG);
+
+ ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE |
+ RTL_REGISTRY_OPTIONAL,
+ regPath.Buffer,
+ paramTable,
+ NULL,
+ NULL);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetRegistryDword: Success, Value = %X\n", *Value));
+ return STATUS_SUCCESS;
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_GetRegistryDword: Failed\n"));
+ *Value = 0;
+ return STATUS_UNSUCCESSFUL;
+
+ }
+}
+
+
+NTSTATUS FreeBT_DispatchClean(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ PDEVICE_EXTENSION deviceExtension;
+ KIRQL oldIrql;
+ LIST_ENTRY cleanupList;
+ PLIST_ENTRY thisEntry,
+ nextEntry,
+ listHead;
+ PIRP pendingIrp;
+ PIO_STACK_LOCATION pendingIrpStack,
+ irpStack;
+ NTSTATUS ntStatus;
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ InitializeListHead(&cleanupList);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchClean::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ KeAcquireSpinLock(&deviceExtension->QueueLock, &oldIrql);
+
+ listHead = &deviceExtension->NewRequestsQueue;
+ for(thisEntry = listHead->Flink, nextEntry = thisEntry->Flink;
+ thisEntry != listHead;
+ thisEntry = nextEntry, nextEntry = thisEntry->Flink)
+ {
+ pendingIrp = CONTAINING_RECORD(thisEntry, IRP, Tail.Overlay.ListEntry);
+ pendingIrpStack = IoGetCurrentIrpStackLocation(pendingIrp);
+ if (irpStack->FileObject == pendingIrpStack->FileObject)
+ {
+ RemoveEntryList(thisEntry);
+
+ if (NULL == IoSetCancelRoutine(pendingIrp, NULL))
+ {
+ InitializeListHead(thisEntry);
+
+ }
+
+ else
+ {
+ InsertTailList(&cleanupList, thisEntry);
+
+ }
+
+ }
+
+ }
+
+ KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql);
+
+ while(!IsListEmpty(&cleanupList))
+ {
+ thisEntry = RemoveHeadList(&cleanupList);
+ pendingIrp = CONTAINING_RECORD(thisEntry, IRP, Tail.Overlay.ListEntry);
+
+ pendingIrp->IoStatus.Information = 0;
+ pendingIrp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(pendingIrp, IO_NO_INCREMENT);
+
+ }
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchClean::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ return STATUS_SUCCESS;
+
+}
+
+
+BOOLEAN CanDeviceSuspend(IN PDEVICE_EXTENSION DeviceExtension)
+{
+ FreeBT_DbgPrint(3, ("FBTUSB: CanDeviceSuspend: Entered\n"));
+
+ if ((DeviceExtension->OpenHandleCount == 0) && (DeviceExtension->OutStandingIO == 1))
+ return TRUE;
+
+ return FALSE;
+
+}
+
+NTSTATUS FreeBT_AbortPipes(IN PDEVICE_OBJECT DeviceObject)
+{
+ PURB urb;
+ ULONG i;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ PFREEBT_PIPE_CONTEXT pipeContext;
+ PUSBD_PIPE_INFORMATION pipeInformation;
+ PUSBD_INTERFACE_INFORMATION interfaceInfo;
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ pipeContext = deviceExtension->PipeContext;
+ interfaceInfo = deviceExtension->UsbInterface;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AbortPipes: Entered\n"));
+
+ if(interfaceInfo == NULL || pipeContext == NULL)
+ return STATUS_SUCCESS;
+
+ for(i=0; i<interfaceInfo->NumberOfPipes; i++)
+ {
+ if(pipeContext[i].PipeOpen)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AbortPipes: Aborting open pipe %d\n", i));
+
+ urb = (PURB) ExAllocatePool(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
+ if (urb)
+ {
+ urb->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST);
+ urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
+ urb->UrbPipeRequest.PipeHandle = interfaceInfo->Pipes[i].PipeHandle;
+
+ ntStatus = CallUSBD(DeviceObject, urb);
+
+ ExFreePool(urb);
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_AbortPipes: Failed to alloc memory for urb\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ return ntStatus;
+
+ }
+
+ if(NT_SUCCESS(ntStatus))
+ pipeContext[i].PipeOpen = FALSE;
+
+
+ }
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AbortPipes: Leaving\n"));
+
+ return STATUS_SUCCESS;
+
+}
+
+// Completion routine for PNP IRPs
+NTSTATUS IrpCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
+{
+ PKEVENT event = (PKEVENT) Context;
+ KeSetEvent(event, 0, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+}
+
+
+LONG FreeBT_IoIncrement(IN OUT PDEVICE_EXTENSION DeviceExtension)
+{
+ LONG result = 0;
+ KIRQL oldIrql;
+
+ KeAcquireSpinLock(&DeviceExtension->IOCountLock, &oldIrql);
+ result = InterlockedIncrement((PLONG)(&DeviceExtension->OutStandingIO));
+
+ // When OutStandingIO bumps from 1 to 2, clear the StopEvent
+ if (result == 2)
+ KeClearEvent(&DeviceExtension->StopEvent);
+
+ KeReleaseSpinLock(&DeviceExtension->IOCountLock, oldIrql);
+
+ FreeBT_DbgPrint(3, ("FreeBT_IoIncrement::%d\n", result));
+
+ return result;
+
+}
+
+LONG FreeBT_IoDecrement(IN OUT PDEVICE_EXTENSION DeviceExtension)
+{
+ LONG result = 0;
+ KIRQL oldIrql;
+
+ KeAcquireSpinLock(&DeviceExtension->IOCountLock, &oldIrql);
+
+ result = InterlockedDecrement((PLONG)(&DeviceExtension->OutStandingIO));
+
+ if (result == 1)
+ KeSetEvent(&DeviceExtension->StopEvent, IO_NO_INCREMENT, FALSE);
+
+ if(result == 0)
+ {
+ ASSERT(Removed == DeviceExtension->DeviceState);
+ KeSetEvent(&DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE);
+
+ }
+
+ KeReleaseSpinLock(&DeviceExtension->IOCountLock, oldIrql);
+
+ FreeBT_DbgPrint(3, ("FreeBT_IoDecrement::%d\n", result));
+
+ return result;
+
+}
+
+NTSTATUS CanStopDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ // For the time being, just allow it to be stopped
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
+
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS CanRemoveDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+
+{
+ // For the time being, just allow it to be removed
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
+
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS ReleaseMemory(IN PDEVICE_OBJECT DeviceObject)
+{
+ // Disconnect from the interrupt and unmap any I/O ports
+ PDEVICE_EXTENSION deviceExtension;
+ UNICODE_STRING uniDeviceName;
+ NTSTATUS ntStatus;
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ if (deviceExtension->UsbConfigurationDescriptor)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: ReleaseMemory: Freeing UsbConfigurationDescriptor\n"));
+ ExFreePool(deviceExtension->UsbConfigurationDescriptor);
+ deviceExtension->UsbConfigurationDescriptor = NULL;
+
+ }
+
+ if(deviceExtension->UsbInterface)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: ReleaseMemory: Freeing UsbInterface\n"));
+ ExFreePool(deviceExtension->UsbInterface);
+ deviceExtension->UsbInterface = NULL;
+
+ }
+
+ if(deviceExtension->PipeContext)
+ {
+ RtlInitUnicodeString(&uniDeviceName, deviceExtension->wszDosDeviceName);
+ ntStatus = IoDeleteSymbolicLink(&uniDeviceName);
+ if (!NT_SUCCESS(ntStatus))
+ FreeBT_DbgPrint(3, ("FBTUSB: Failed to delete symbolic link %ws\n", deviceExtension->wszDosDeviceName));
+
+ FreeBT_DbgPrint(3, ("FBTUSB: ReleaseMemory: Freeing PipeContext %p\n", deviceExtension->PipeContext));
+ ExFreePool(deviceExtension->PipeContext);
+ deviceExtension->PipeContext = NULL;
+
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+PCHAR PnPMinorFunctionString (UCHAR MinorFunction)
+{
+ switch (MinorFunction)
+ {
+ case IRP_MN_START_DEVICE:
+ return "IRP_MN_START_DEVICE\n";
+
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ return "IRP_MN_QUERY_REMOVE_DEVICE\n";
+
+ case IRP_MN_REMOVE_DEVICE:
+ return "IRP_MN_REMOVE_DEVICE\n";
+
+ case IRP_MN_CANCEL_REMOVE_DEVICE:
+ return "IRP_MN_CANCEL_REMOVE_DEVICE\n";
+
+ case IRP_MN_STOP_DEVICE:
+ return "IRP_MN_STOP_DEVICE\n";
+
+ case IRP_MN_QUERY_STOP_DEVICE:
+ return "IRP_MN_QUERY_STOP_DEVICE\n";
+
+ case IRP_MN_CANCEL_STOP_DEVICE:
+ return "IRP_MN_CANCEL_STOP_DEVICE\n";
+
+ case IRP_MN_QUERY_DEVICE_RELATIONS:
+ return "IRP_MN_QUERY_DEVICE_RELATIONS\n";
+
+ case IRP_MN_QUERY_INTERFACE:
+ return "IRP_MN_QUERY_INTERFACE\n";
+
+ case IRP_MN_QUERY_CAPABILITIES:
+ return "IRP_MN_QUERY_CAPABILITIES\n";
+
+ case IRP_MN_QUERY_RESOURCES:
+ return "IRP_MN_QUERY_RESOURCES\n";
+
+ case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
+ return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n";
+
+ case IRP_MN_QUERY_DEVICE_TEXT:
+ return "IRP_MN_QUERY_DEVICE_TEXT\n";
+
+ case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
+ return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n";
+
+ case IRP_MN_READ_CONFIG:
+ return "IRP_MN_READ_CONFIG\n";
+
+ case IRP_MN_WRITE_CONFIG:
+ return "IRP_MN_WRITE_CONFIG\n";
+
+ case IRP_MN_EJECT:
+ return "IRP_MN_EJECT\n";
+
+ case IRP_MN_SET_LOCK:
+ return "IRP_MN_SET_LOCK\n";
+
+ case IRP_MN_QUERY_ID:
+ return "IRP_MN_QUERY_ID\n";
+
+ case IRP_MN_QUERY_PNP_DEVICE_STATE:
+ return "IRP_MN_QUERY_PNP_DEVICE_STATE\n";
+
+ case IRP_MN_QUERY_BUS_INFORMATION:
+ return "IRP_MN_QUERY_BUS_INFORMATION\n";
+
+ case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+ return "IRP_MN_DEVICE_USAGE_NOTIFICATION\n";
+
+ case IRP_MN_SURPRISE_REMOVAL:
+ return "IRP_MN_SURPRISE_REMOVAL\n";
+
+ default:
+ return "IRP_MN_?????\n";
+
+ }
+
+}
+
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#include "fbtusb.h"
+#include "fbtpwr.h"
+#include "fbtpnp.h"
+#include "fbtdev.h"
+#include "fbtrwr.h"
+#include "fbtwmi.h"
+
+#include "fbtusr.h"
+
+// Handle power events
+NTSTATUS FreeBT_DispatchPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION irpStack;
+ PUNICODE_STRING tagString;
+ PDEVICE_EXTENSION deviceExtension;
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ // We don't queue power Irps, we'll only check if the
+ // device was removed, otherwise we'll take appropriate
+ // action and send it to the next lower driver. In general
+ // drivers should not cause long delays while handling power
+ // IRPs. If a driver cannot handle a power IRP in a brief time,
+ // it should return STATUS_PENDING and queue all incoming
+ // IRPs until the IRP completes.
+ if (Removed == deviceExtension->DeviceState)
+ {
+
+ // Even if a driver fails the IRP, it must nevertheless call
+ // PoStartNextPowerIrp to inform the Power Manager that it
+ // is ready to handle another power IRP.
+ PoStartNextPowerIrp(Irp);
+ Irp->IoStatus.Status = ntStatus = STATUS_DELETE_PENDING;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+
+ }
+
+ if (NotStarted == deviceExtension->DeviceState)
+ {
+ // if the device is not started yet, pass it down
+ PoStartNextPowerIrp(Irp);
+ IoSkipCurrentIrpStackLocation(Irp);
+
+ return PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ switch(irpStack->MinorFunction)
+ {
+ case IRP_MN_SET_POWER:
+ // The Power Manager sends this IRP for one of the
+ // following reasons:
+
+ // 1) To notify drivers of a change to the system power state.
+ // 2) To change the power state of a device for which
+ // the Power Manager is performing idle detection.
+
+ // A driver sends IRP_MN_SET_POWER to change the power
+ // state of its device if it's a power policy owner for the
+ // device.
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_SET_POWER\n"));
+ IoMarkIrpPending(Irp);
+
+ switch(irpStack->Parameters.Power.Type)
+ {
+ case SystemPowerState:
+ HandleSystemSetPower(DeviceObject, Irp);
+ ntStatus = STATUS_PENDING;
+ break;
+
+ case DevicePowerState:
+ HandleDeviceSetPower(DeviceObject, Irp);
+ ntStatus = STATUS_PENDING;
+ break;
+
+ }
+
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ // The Power Manager sends a power IRP with the minor
+ // IRP code IRP_MN_QUERY_POWER to determine whether it
+ // can safely change to the specified system power state
+ // (S1-S5) and to allow drivers to prepare for such a change.
+ // If a driver can put its device in the requested state,
+ // it sets status to STATUS_SUCCESS and passes the IRP down.
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_QUERY_POWER\n"));
+ IoMarkIrpPending(Irp);
+
+ switch(irpStack->Parameters.Power.Type)
+ {
+ case SystemPowerState:
+ HandleSystemQueryPower(DeviceObject, Irp);
+ ntStatus = STATUS_PENDING;
+ break;
+
+ case DevicePowerState:
+ HandleDeviceQueryPower(DeviceObject, Irp);
+ ntStatus = STATUS_PENDING;
+ break;
+
+ }
+
+ break;
+
+ case IRP_MN_WAIT_WAKE:
+ // The minor power IRP code IRP_MN_WAIT_WAKE provides
+ // for waking a device or waking the system. Drivers
+ // of devices that can wake themselves or the system
+ // send IRP_MN_WAIT_WAKE. The system sends IRP_MN_WAIT_WAKE
+ // only to devices that always wake the system, such as
+ // the power-on switch.
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_WAIT_WAKE\n"));
+ IoMarkIrpPending(Irp);
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(
+ Irp,
+ (PIO_COMPLETION_ROUTINE)WaitWakeCompletionRoutine,
+ deviceExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ PoStartNextPowerIrp(Irp);
+ ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: Lower drivers failed the wait-wake Irp\n"));
+
+ }
+
+ ntStatus = STATUS_PENDING;
+
+ // push back the count HERE and NOT in completion routine
+ // a pending Wait Wake Irp should not impede stopping the device
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_WAIT_WAKE::"));
+ FreeBT_IoDecrement(deviceExtension);
+ break;
+
+ case IRP_MN_POWER_SEQUENCE:
+ // A driver sends this IRP as an optimization to determine
+ // whether its device actually entered a specific power state.
+ // This IRP is optional. Power Manager cannot send this IRP.
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_POWER_SEQUENCE\n"));
+
+ default:
+ PoStartNextPowerIrp(Irp);
+ IoSkipCurrentIrpStackLocation(Irp);
+ ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchPower: Lower drivers failed this Irp\n"));
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ break;
+
+ }
+
+ return ntStatus;
+
+}
+
+NTSTATUS HandleSystemQueryPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ SYSTEM_POWER_STATE systemState;
+ PIO_STACK_LOCATION irpStack;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower: Entered\n"));
+
+ // initialize variables
+ deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ systemState = irpStack->Parameters.Power.State.SystemState;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower: Query for system power state S%X\n"
+ "FBTUSB: HandleSystemQueryPower: Current system power state S%X\n",
+ systemState - 1,
+ deviceExtension->SysPower - 1));
+
+ // Fail a query for a power state incompatible with waking up the system
+ if ((deviceExtension->WaitWakeEnable) && (systemState > deviceExtension->DeviceCapabilities.SystemWake))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: HandleSystemQueryPower: Query for an incompatible system power state\n"));
+
+ PoStartNextPowerIrp(Irp);
+ Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ return ntStatus;
+
+ }
+
+ // if querying for a lower S-state, issue a wait-wake
+ if((systemState > deviceExtension->SysPower) && (deviceExtension->WaitWakeEnable))
+ {
+ IssueWaitWake(deviceExtension);
+
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(
+ Irp,
+ (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
+ deviceExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower: Leaving\n"));
+
+ return STATUS_PENDING;
+
+}
+
+NTSTATUS HandleSystemSetPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
+{
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ SYSTEM_POWER_STATE systemState;
+ PIO_STACK_LOCATION irpStack;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemSetPower: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ systemState = irpStack->Parameters.Power.State.SystemState;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemSetPower: Set request for system power state S%X\n"
+ "FBTUSB: HandleSystemSetPower: Current system power state S%X\n",
+ systemState - 1,
+ deviceExtension->SysPower - 1));
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(
+ Irp,
+ (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
+ deviceExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemSetPower: Leaving\n"));
+
+ return STATUS_PENDING;
+
+}
+
+NTSTATUS HandleDeviceQueryPower(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpStack;
+ DEVICE_POWER_STATE deviceState;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ deviceState = irpStack->Parameters.Power.State.DeviceState;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower: Query for device power state D%X\n"
+ "FBTUSB: HandleDeviceQueryPower: Current device power state D%X\n",
+ deviceState - 1,
+ deviceExtension->DevPower - 1));
+
+ if (deviceExtension->WaitWakeEnable && deviceState > deviceExtension->DeviceCapabilities.DeviceWake)
+ {
+ PoStartNextPowerIrp(Irp);
+ Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ return ntStatus;
+
+ }
+
+ if (deviceState < deviceExtension->DevPower)
+ {
+ ntStatus = STATUS_SUCCESS;
+
+ }
+
+ else
+ {
+ ntStatus = HoldIoRequests(DeviceObject, Irp);
+ if(STATUS_PENDING == ntStatus)
+ {
+ return ntStatus;
+
+ }
+
+ }
+
+ // on error complete the Irp.
+ // on success pass it to the lower layers
+ PoStartNextPowerIrp(Irp);
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ if(!NT_SUCCESS(ntStatus))
+ {
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ }
+
+ else
+ {
+ IoSkipCurrentIrpStackLocation(Irp);
+ ntStatus=PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+
+NTSTATUS SysPoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION irpStack;
+
+ ntStatus = Irp->IoStatus.Status;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: SysPoCompletionRoutine: Entered\n"));
+
+ // lower drivers failed this Irp
+ if(!NT_SUCCESS(ntStatus))
+ {
+ PoStartNextPowerIrp(Irp);
+ FreeBT_DbgPrint(3, ("FBTUSB: SysPoCompletionRoutine::"));
+ FreeBT_IoDecrement(DeviceExtension);
+
+ return STATUS_SUCCESS;
+
+ }
+
+ // ..otherwise update the cached system power state (IRP_MN_SET_POWER)
+ if(irpStack->MinorFunction == IRP_MN_SET_POWER)
+ {
+ DeviceExtension->SysPower = irpStack->Parameters.Power.State.SystemState;
+
+ }
+
+ // queue device irp and return STATUS_MORE_PROCESSING_REQUIRED
+ SendDeviceIrp(DeviceObject, Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: SysPoCompletionRoutine: Leaving\n"));
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+}
+
+VOID SendDeviceIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP SIrp )
+{
+ NTSTATUS ntStatus;
+ POWER_STATE powState;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpStack;
+ SYSTEM_POWER_STATE systemState;
+ DEVICE_POWER_STATE devState;
+ PPOWER_COMPLETION_CONTEXT powerContext;
+
+ irpStack = IoGetCurrentIrpStackLocation(SIrp);
+ systemState = irpStack->Parameters.Power.State.SystemState;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: SendDeviceIrp: Entered\n"));
+
+ // Read out the D-IRP out of the S->D mapping array captured in QueryCap's.
+ // we can choose deeper sleep states than our mapping but never choose
+ // lighter ones.
+ devState = deviceExtension->DeviceCapabilities.DeviceState[systemState];
+ powState.DeviceState = devState;
+
+ powerContext = (PPOWER_COMPLETION_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(POWER_COMPLETION_CONTEXT));
+ if (!powerContext)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: SendDeviceIrp: Failed to alloc memory for powerContext\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ else
+ {
+ powerContext->DeviceObject = DeviceObject;
+ powerContext->SIrp = SIrp;
+
+ // in win2k PoRequestPowerIrp can take fdo or pdo.
+ ntStatus = PoRequestPowerIrp(
+ deviceExtension->PhysicalDeviceObject,
+ irpStack->MinorFunction,
+ powState,
+ (PREQUEST_POWER_COMPLETE)DevPoCompletionRoutine,
+ powerContext,
+ NULL);
+
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ if (powerContext)
+ {
+ ExFreePool(powerContext);
+
+ }
+
+ PoStartNextPowerIrp(SIrp);
+ SIrp->IoStatus.Status = ntStatus;
+ SIrp->IoStatus.Information = 0;
+ IoCompleteRequest(SIrp, IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: SendDeviceIrp::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: SendDeviceIrp: Leaving\n"));
+
+}
+
+
+VOID DevPoCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus
+ )
+{
+ PIRP sIrp;
+ PDEVICE_EXTENSION deviceExtension;
+ PPOWER_COMPLETION_CONTEXT powerContext;
+
+ powerContext = (PPOWER_COMPLETION_CONTEXT) Context;
+ sIrp = powerContext->SIrp;
+ deviceExtension = (PDEVICE_EXTENSION) powerContext->DeviceObject->DeviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: DevPoCompletionRoutine: Entered\n"));
+
+ sIrp->IoStatus.Status = IoStatus->Status;
+ PoStartNextPowerIrp(sIrp);
+ sIrp->IoStatus.Information = 0;
+ IoCompleteRequest(sIrp, IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: DevPoCompletionRoutine::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ ExFreePool(powerContext);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: DevPoCompletionRoutine: Leaving\n"));
+
+}
+
+NTSTATUS HandleDeviceSetPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ KIRQL oldIrql;
+ NTSTATUS ntStatus;
+ POWER_STATE newState;
+ PIO_STACK_LOCATION irpStack;
+ PDEVICE_EXTENSION deviceExtension;
+ DEVICE_POWER_STATE newDevState,
+ oldDevState;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ oldDevState = deviceExtension->DevPower;
+ newState = irpStack->Parameters.Power.State;
+ newDevState = newState.DeviceState;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Set request for device power state D%X\n"
+ "FBTUSB: HandleDeviceSetPower: Current device power state D%X\n",
+ newDevState - 1,
+ deviceExtension->DevPower - 1));
+
+ if (newDevState < oldDevState)
+ {
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Adding power to the device\n"));
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(
+ Irp,
+ (PIO_COMPLETION_ROUTINE)FinishDevPoUpIrp,
+ deviceExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+
+ }
+
+ else
+ {
+ // newDevState >= oldDevState
+
+ // hold I/O if transition from D0 -> DX (X = 1, 2, 3)
+ // if transition from D1 or D2 to deeper sleep states,
+ // I/O queue is already on hold.
+ if(PowerDeviceD0 == oldDevState && newDevState > oldDevState)
+ {
+ // D0 -> DX transition
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Removing power from the device\n"));
+
+ ntStatus = HoldIoRequests(DeviceObject, Irp);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ PoStartNextPowerIrp(Irp);
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ return ntStatus;
+
+ }
+
+ else
+ {
+ goto HandleDeviceSetPower_Exit;
+
+ }
+
+ }
+
+ else if (PowerDeviceD0 == oldDevState && PowerDeviceD0 == newDevState)
+ {
+ // D0 -> D0
+ // unblock the queue which may have been blocked processing
+ // query irp
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: A SetD0 request\n"));
+
+ KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
+ deviceExtension->QueueState = AllowRequests;
+ KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
+
+ ProcessQueuedRequests(deviceExtension);
+
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(
+ Irp,
+ (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
+ deviceExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: HandleDeviceSetPower: Lower drivers failed a power Irp\n"));
+
+ }
+
+ }
+
+HandleDeviceSetPower_Exit:
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Leaving\n"));
+
+ return STATUS_PENDING;
+
+}
+
+NTSTATUS FinishDevPoUpIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS ntStatus;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoUpIrp: Entered\n"));
+
+ ntStatus = Irp->IoStatus.Status;
+ if(Irp->PendingReturned)
+ {
+ IoMarkIrpPending(Irp);
+
+ }
+
+ if(!NT_SUCCESS(ntStatus))
+ {
+ PoStartNextPowerIrp(Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoUpIrp::"));
+ FreeBT_IoDecrement(DeviceExtension);
+
+ return STATUS_SUCCESS;
+
+ }
+
+ SetDeviceFunctional(DeviceObject, Irp, DeviceExtension);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoUpIrp: Leaving\n"));
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+}
+
+NTSTATUS SetDeviceFunctional(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
+{
+ KIRQL oldIrql;
+ NTSTATUS ntStatus;
+ POWER_STATE newState;
+ PIO_STACK_LOCATION irpStack;
+ DEVICE_POWER_STATE newDevState, oldDevState;
+
+ ntStatus = Irp->IoStatus.Status;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ newState = irpStack->Parameters.Power.State;
+ newDevState = newState.DeviceState;
+ oldDevState = DeviceExtension->DevPower;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional: Entered\n"));
+
+ // update the cached state
+ DeviceExtension->DevPower = newDevState;
+
+ // restore appropriate amount of state to our h/w
+ // this driver does not implement partial context
+ // save/restore.
+ PoSetPowerState(DeviceObject, DevicePowerState, newState);
+ if(PowerDeviceD0 == newDevState)
+ {
+ KeAcquireSpinLock(&DeviceExtension->DevStateLock, &oldIrql);
+ DeviceExtension->QueueState = AllowRequests;
+ KeReleaseSpinLock(&DeviceExtension->DevStateLock, oldIrql);
+
+ ProcessQueuedRequests(DeviceExtension);
+
+ }
+
+ PoStartNextPowerIrp(Irp);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional::"));
+ FreeBT_IoDecrement(DeviceExtension);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional: Leaving\n"));
+
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS FinishDevPoDnIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS ntStatus;
+ POWER_STATE newState;
+ PIO_STACK_LOCATION irpStack;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp: Entered\n"));
+
+ ntStatus = Irp->IoStatus.Status;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ newState = irpStack->Parameters.Power.State;
+
+ if (NT_SUCCESS(ntStatus) && irpStack->MinorFunction == IRP_MN_SET_POWER)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: updating cache..\n"));
+ DeviceExtension->DevPower = newState.DeviceState;
+ PoSetPowerState(DeviceObject, DevicePowerState, newState);
+
+ }
+
+ PoStartNextPowerIrp(Irp);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp::"));
+ FreeBT_IoDecrement(DeviceExtension);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp: Leaving\n"));
+
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS HoldIoRequests(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+
+{
+ NTSTATUS ntStatus;
+ PIO_WORKITEM item;
+ PDEVICE_EXTENSION deviceExtension;
+ PWORKER_THREAD_CONTEXT context;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequests: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ deviceExtension->QueueState = HoldRequests;
+
+ context = (PWORKER_THREAD_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(WORKER_THREAD_CONTEXT));
+ if(context)
+ {
+ item = IoAllocateWorkItem(DeviceObject);
+
+ context->Irp = Irp;
+ context->DeviceObject = DeviceObject;
+ context->WorkItem = item;
+
+ if (item)
+ {
+ IoMarkIrpPending(Irp);
+ IoQueueWorkItem(item, HoldIoRequestsWorkerRoutine, DelayedWorkQueue, context);
+ ntStatus = STATUS_PENDING;
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequests: Failed to allocate memory for workitem\n"));
+ ExFreePool(context);
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: HoldIoRequests: Failed to alloc memory for worker thread context\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequests: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+VOID HoldIoRequestsWorkerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
+{
+ PIRP irp;
+ NTSTATUS ntStatus;
+ PDEVICE_EXTENSION deviceExtension;
+ PWORKER_THREAD_CONTEXT context;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ context = (PWORKER_THREAD_CONTEXT) Context;
+ irp = (PIRP) context->Irp;
+
+ // wait for I/O in progress to finish.
+ // the stop event is signalled when the counter drops to 1.
+ // invoke FreeBT_IoDecrement twice: once each for the S-Irp and D-Irp.
+ FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ KeWaitForSingleObject(&deviceExtension->StopEvent, Executive, KernelMode, FALSE, NULL);
+
+ // Increment twice to restore the count
+ FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ // now send the Irp down
+ IoCopyCurrentIrpStackLocationToNext(irp);
+ IoSetCompletionRoutine(
+ irp,
+ (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
+ deviceExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: HoldIoRequestsWorkerRoutine: Lower driver fail a power Irp\n"));
+
+ }
+
+ IoFreeWorkItem(context->WorkItem);
+ ExFreePool((PVOID)context);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine: Leaving\n"));
+
+}
+
+NTSTATUS QueueRequest(IN OUT PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp)
+{
+ KIRQL oldIrql;
+ NTSTATUS ntStatus;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: QueueRequests: Entered\n"));
+
+ ntStatus = STATUS_PENDING;
+
+ ASSERT(HoldRequests == DeviceExtension->QueueState);
+
+ KeAcquireSpinLock(&DeviceExtension->QueueLock, &oldIrql);
+
+ InsertTailList(&DeviceExtension->NewRequestsQueue, &Irp->Tail.Overlay.ListEntry);
+ IoMarkIrpPending(Irp);
+ IoSetCancelRoutine(Irp, CancelQueued);
+
+ KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: QueueRequests: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+VOID CancelQueued(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ PDEVICE_EXTENSION deviceExtension;
+ KIRQL oldIrql;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: CancelQueued: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ oldIrql = Irp->CancelIrql;
+
+ // Release the cancel spin lock
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ // Acquire the queue lock
+ KeAcquireSpinLockAtDpcLevel(&deviceExtension->QueueLock);
+
+ // Remove the cancelled Irp from queue and release the lock
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+
+ KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql);
+
+ // complete with STATUS_CANCELLED
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: CancelQueued: Leaving\n"));
+
+ return;
+
+}
+
+NTSTATUS IssueWaitWake(IN PDEVICE_EXTENSION DeviceExtension)
+{
+ POWER_STATE poState;
+ NTSTATUS ntStatus;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: IssueWaitWake: Entered\n"));
+
+ if(InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 1))
+ {
+ return STATUS_DEVICE_BUSY;
+
+ }
+
+ InterlockedExchange(&DeviceExtension->FlagWWCancel, 0);
+
+ // lowest state from which this Irp will wake the system
+ poState.SystemState = DeviceExtension->DeviceCapabilities.SystemWake;
+ ntStatus = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
+ IRP_MN_WAIT_WAKE,
+ poState,
+ (PREQUEST_POWER_COMPLETE) WaitWakeCallback,
+ DeviceExtension,
+ &DeviceExtension->WaitWakeIrp);
+
+ if(!NT_SUCCESS(ntStatus))
+ {
+ InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 0);
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: IssueWaitWake: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+VOID CancelWaitWake(IN PDEVICE_EXTENSION DeviceExtension)
+{
+ PIRP Irp;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: CancelWaitWake: Entered\n"));
+
+ Irp = (PIRP) InterlockedExchangePointer(&DeviceExtension->WaitWakeIrp, NULL);
+ if(Irp)
+ {
+ IoCancelIrp(Irp);
+ if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1))
+ {
+ PoStartNextPowerIrp(Irp);
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ }
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: CancelWaitWake: Leaving\n"));
+
+}
+
+NTSTATUS WaitWakeCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
+{
+ FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCompletionRoutine: Entered\n"));
+ if(Irp->PendingReturned)
+ {
+ IoMarkIrpPending(Irp);
+
+ }
+
+ // Nullify the WaitWakeIrp pointer-the Irp is released
+ // as part of the completion process. If it's already NULL,
+ // avoid race with the CancelWaitWake routine.
+ if(InterlockedExchangePointer(&DeviceExtension->WaitWakeIrp, NULL))
+ {
+ PoStartNextPowerIrp(Irp);
+
+ return STATUS_SUCCESS;
+
+ }
+
+ // CancelWaitWake has run.
+ // If FlagWWCancel != 0, complete the Irp.
+ // If FlagWWCancel == 0, CancelWaitWake completes it.
+ if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1))
+ {
+ PoStartNextPowerIrp(Irp);
+
+ return STATUS_CANCELLED;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCompletionRoutine: Leaving\n"));
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+}
+
+VOID WaitWakeCallback(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus)
+{
+ NTSTATUS ntStatus;
+ POWER_STATE powerState;
+ PDEVICE_EXTENSION deviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) Context;
+
+ InterlockedExchange(&deviceExtension->FlagWWOutstanding, 0);
+
+ if(!NT_SUCCESS(IoStatus->Status))
+ {
+ return;
+
+ }
+
+ // wake up the device
+ if(deviceExtension->DevPower == PowerDeviceD0)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Device already powered up...\n"));
+
+ return;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ powerState.DeviceState = PowerDeviceD0;
+ ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
+ IRP_MN_SET_POWER,
+ powerState,
+ (PREQUEST_POWER_COMPLETE) WWIrpCompletionFunc,
+ deviceExtension,
+ NULL);
+
+ if(deviceExtension->WaitWakeEnable)
+ {
+ IssueWaitWake(deviceExtension);
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Leaving\n"));
+
+ return;
+
+}
+
+
+PCHAR PowerMinorFunctionString (IN UCHAR MinorFunction)
+{
+ switch (MinorFunction)
+ {
+ case IRP_MN_SET_POWER:
+ return "IRP_MN_SET_POWER\n";
+
+ case IRP_MN_QUERY_POWER:
+ return "IRP_MN_QUERY_POWER\n";
+
+ case IRP_MN_POWER_SEQUENCE:
+ return "IRP_MN_POWER_SEQUENCE\n";
+
+ case IRP_MN_WAIT_WAKE:
+ return "IRP_MN_WAIT_WAKE\n";
+
+ default:
+ return "IRP_MN_?????\n";
+
+ }
+
+}
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#include "fbtusb.h"
+#include "fbtpnp.h"
+#include "fbtpwr.h"
+#include "fbtdev.h"
+#include "fbtrwr.h"
+#include "fbtwmi.h"
+
+#include "fbtusr.h"
+
+// Read/Write handler
+NTSTATUS FreeBT_DispatchRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ PMDL mdl;
+ PURB urb;
+ ULONG totalLength;
+ ULONG stageLength;
+ NTSTATUS ntStatus;
+ ULONG_PTR virtualAddress;
+ PFILE_OBJECT fileObject;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpStack;
+ PIO_STACK_LOCATION nextStack;
+ PFREEBT_RW_CONTEXT rwContext;
+ ULONG maxLength=0;
+
+ urb = NULL;
+ mdl = NULL;
+ rwContext = NULL;
+ totalLength = 0;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ fileObject = irpStack->FileObject;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Entered\n"));
+
+ if (deviceExtension->DeviceState != Working)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Invalid device state\n"));
+ ntStatus = STATUS_INVALID_DEVICE_STATE;
+ goto FreeBT_DispatchRead_Exit;
+
+ }
+
+ // Make sure that any selective suspend request has been completed.
+ if (deviceExtension->SSEnable)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Waiting on the IdleReqPendEvent\n"));
+ KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ }
+
+ rwContext = (PFREEBT_RW_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(FREEBT_RW_CONTEXT));
+ if (rwContext == NULL)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for rwContext\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto FreeBT_DispatchRead_Exit;
+
+ }
+
+ if (Irp->MdlAddress)
+ {
+ totalLength = MmGetMdlByteCount(Irp->MdlAddress);
+
+ }
+
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Transfer data length = %d\n", totalLength));
+ if (totalLength == 0)
+ {
+ ntStatus = STATUS_SUCCESS;
+ ExFreePool(rwContext);
+ goto FreeBT_DispatchRead_Exit;
+
+ }
+
+ virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
+ if (totalLength > deviceExtension->DataInPipe.MaximumPacketSize)
+ {
+ stageLength = deviceExtension->DataInPipe.MaximumPacketSize;
+
+ }
+
+ else
+ {
+ stageLength = totalLength;
+
+ }
+
+ mdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL);
+ if (mdl == NULL)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for mdl\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(rwContext);
+ goto FreeBT_DispatchRead_Exit;
+
+ }
+
+ // map the portion of user-buffer described by an mdl to another mdl
+ IoBuildPartialMdl(Irp->MdlAddress, mdl, (PVOID) virtualAddress, stageLength);
+ urb = (PURB) ExAllocatePool(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
+ if (urb == NULL)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for urb\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(rwContext);
+ IoFreeMdl(mdl);
+ goto FreeBT_DispatchRead_Exit;
+
+ }
+
+ UsbBuildInterruptOrBulkTransferRequest(
+ urb,
+ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+ deviceExtension->DataInPipe.PipeHandle,
+ NULL,
+ mdl,
+ stageLength,
+ USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN,
+ NULL);
+
+ // set FREEBT_RW_CONTEXT parameters.
+ rwContext->Urb = urb;
+ rwContext->Mdl = mdl;
+ rwContext->Length = totalLength - stageLength;
+ rwContext->Numxfer = 0;
+ rwContext->VirtualAddress = virtualAddress + stageLength;
+
+ // use the original read/write irp as an internal device control irp
+ nextStack = IoGetNextIrpStackLocation(Irp);
+ nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ nextStack->Parameters.Others.Argument1 = (PVOID) urb;
+ nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+ IoSetCompletionRoutine(Irp,
+ (PIO_COMPLETION_ROUTINE)FreeBT_ReadCompletion,
+ rwContext,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ // We return STATUS_PENDING; call IoMarkIrpPending.
+ IoMarkIrpPending(Irp);
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: IoCallDriver fails with status %X\n", ntStatus));
+
+ // if the device was yanked out, then the pipeInformation
+ // field is invalid.
+ // similarly if the request was cancelled, then we need not
+ // invoked reset pipe/device.
+ if((ntStatus != STATUS_CANCELLED) && (ntStatus != STATUS_DEVICE_NOT_CONNECTED))
+ {
+ ntStatus = FreeBT_ResetPipe(DeviceObject, deviceExtension->DataInPipe.PipeHandle);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: FreeBT_ResetPipe failed\n"));
+ ntStatus = FreeBT_ResetDevice(DeviceObject);
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n"));
+
+ }
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: URB sent to lower driver, IRP is pending\n"));
+
+ // we return STATUS_PENDING and not the status returned by the lower layer.
+ return STATUS_PENDING;
+
+FreeBT_DispatchRead_Exit:
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+NTSTATUS FreeBT_ReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
+{
+ ULONG stageLength;
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION nextStack;
+ PFREEBT_RW_CONTEXT rwContext;
+ PDEVICE_EXTENSION deviceExtension;
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ rwContext = (PFREEBT_RW_CONTEXT) Context;
+ ntStatus = Irp->IoStatus.Status;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: Entered\n"));
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ Irp->IoStatus.Information = rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
+
+ }
+
+ else
+ {
+ Irp->IoStatus.Information = 0;
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ReadCompletion: - failed with status = %X\n", ntStatus));
+
+ }
+
+ if (rwContext)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: ::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ ExFreePool(rwContext->Urb);
+ IoFreeMdl(rwContext->Mdl);
+ ExFreePool(rwContext);
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+// Read/Write handler
+NTSTATUS FreeBT_DispatchWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ PMDL mdl;
+ PURB urb;
+ ULONG totalLength;
+ ULONG stageLength;
+ NTSTATUS ntStatus;
+ ULONG_PTR virtualAddress;
+ PFILE_OBJECT fileObject;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpStack;
+ PIO_STACK_LOCATION nextStack;
+ PFREEBT_RW_CONTEXT rwContext;
+ ULONG maxLength=0;
+
+ urb = NULL;
+ mdl = NULL;
+ rwContext = NULL;
+ totalLength = 0;
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ fileObject = irpStack->FileObject;
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: Entered\n"));
+
+ if (deviceExtension->DeviceState != Working)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Invalid device state\n"));
+ ntStatus = STATUS_INVALID_DEVICE_STATE;
+ goto FreeBT_DispatchWrite_Exit;
+
+ }
+
+ // Make sure that any selective suspend request has been completed.
+ if (deviceExtension->SSEnable)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteDispatch: Waiting on the IdleReqPendEvent\n"));
+ KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ }
+
+ rwContext = (PFREEBT_RW_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(FREEBT_RW_CONTEXT));
+ if (rwContext == NULL)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: Failed to alloc mem for rwContext\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto FreeBT_DispatchWrite_Exit;
+
+ }
+
+ if (Irp->MdlAddress)
+ {
+ totalLength = MmGetMdlByteCount(Irp->MdlAddress);
+
+ }
+
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Transfer data length = %d\n", totalLength));
+ if (totalLength>FBT_HCI_DATA_MAX_SIZE)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Buffer exceeds maximum packet length (%d), failing IRP\n", FBT_HCI_DATA_MAX_SIZE));
+ ntStatus = STATUS_INVALID_BUFFER_SIZE;
+ ExFreePool(rwContext);
+ goto FreeBT_DispatchWrite_Exit;
+
+ }
+
+ if (totalLength<FBT_HCI_DATA_MIN_SIZE)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Zero length buffer, completing IRP\n"));
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ ExFreePool(rwContext);
+ goto FreeBT_DispatchWrite_Exit;
+
+ }
+
+ virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
+ if (totalLength > deviceExtension->DataOutPipe.MaximumPacketSize)
+ {
+ stageLength = deviceExtension->DataOutPipe.MaximumPacketSize;
+
+ }
+
+ else
+ {
+ stageLength = totalLength;
+
+ }
+
+ mdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL);
+ if (mdl == NULL)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Failed to alloc mem for mdl\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(rwContext);
+ goto FreeBT_DispatchWrite_Exit;
+
+ }
+
+ // map the portion of user-buffer described by an mdl to another mdl
+ IoBuildPartialMdl(Irp->MdlAddress, mdl, (PVOID) virtualAddress, stageLength);
+ urb = (PURB) ExAllocatePool(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
+ if (urb == NULL)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Failed to alloc mem for urb\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(rwContext);
+ IoFreeMdl(mdl);
+ goto FreeBT_DispatchWrite_Exit;
+
+ }
+
+ UsbBuildInterruptOrBulkTransferRequest(
+ urb,
+ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+ deviceExtension->DataOutPipe.PipeHandle,
+ NULL,
+ mdl,
+ stageLength,
+ USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_OUT,
+ NULL);
+
+ // set FREEBT_RW_CONTEXT parameters.
+ rwContext->Urb = urb;
+ rwContext->Mdl = mdl;
+ rwContext->Length = totalLength - stageLength;
+ rwContext->Numxfer = 0;
+ rwContext->VirtualAddress = virtualAddress + stageLength;
+
+ // use the original read/write irp as an internal device control irp
+ nextStack = IoGetNextIrpStackLocation(Irp);
+ nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ nextStack->Parameters.Others.Argument1 = (PVOID) urb;
+ nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+ IoSetCompletionRoutine(Irp,
+ (PIO_COMPLETION_ROUTINE)FreeBT_WriteCompletion,
+ rwContext,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ // We return STATUS_PENDING; call IoMarkIrpPending.
+ IoMarkIrpPending(Irp);
+
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: IoCallDriver fails with status %X\n", ntStatus));
+
+ // if the device was yanked out, then the pipeInformation
+ // field is invalid.
+ // similarly if the request was cancelled, then we need not
+ // invoked reset pipe/device.
+ if((ntStatus != STATUS_CANCELLED) && (ntStatus != STATUS_DEVICE_NOT_CONNECTED))
+ {
+ ntStatus = FreeBT_ResetPipe(DeviceObject, deviceExtension->DataOutPipe.PipeHandle);
+ if(!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ResetPipe failed\n"));
+ ntStatus = FreeBT_ResetDevice(DeviceObject);
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n"));
+
+ }
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: URB sent to lower driver, IRP is pending\n"));
+
+ // we return STATUS_PENDING and not the status returned by the lower layer.
+ return STATUS_PENDING;
+
+FreeBT_DispatchWrite_Exit:
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+NTSTATUS FreeBT_WriteCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
+{
+ ULONG stageLength;
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION nextStack;
+ PFREEBT_RW_CONTEXT rwContext;
+ PDEVICE_EXTENSION deviceExtension;
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ rwContext = (PFREEBT_RW_CONTEXT) Context;
+ ntStatus = Irp->IoStatus.Status;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Entered\n"));
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (rwContext)
+ {
+ rwContext->Numxfer += rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
+ if (rwContext->Length)
+ {
+ // More data to transfer
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Initiating next transfer\n"));
+ if (rwContext->Length > deviceExtension->DataOutPipe.MaximumPacketSize)
+ {
+ stageLength = deviceExtension->DataOutPipe.MaximumPacketSize;
+
+ }
+
+ else
+ {
+ stageLength = rwContext->Length;
+
+ }
+
+ IoBuildPartialMdl(Irp->MdlAddress, rwContext->Mdl, (PVOID) rwContext->VirtualAddress, stageLength);
+
+ // reinitialize the urb
+ rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength;
+ rwContext->VirtualAddress += stageLength;
+ rwContext->Length -= stageLength;
+
+ nextStack = IoGetNextIrpStackLocation(Irp);
+ nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ nextStack->Parameters.Others.Argument1 = rwContext->Urb;
+ nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+ IoSetCompletionRoutine(Irp,
+ FreeBT_ReadCompletion,
+ rwContext,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ }
+
+ else
+ {
+ // No more data to transfer
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeNT_WriteCompletion: Write completed, %d bytes written\n", Irp->IoStatus.Information));
+ Irp->IoStatus.Information = rwContext->Numxfer;
+
+ }
+
+ }
+
+ }
+
+ else
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeNT_WriteCompletion - failed with status = %X\n", ntStatus));
+
+ }
+
+ if (rwContext)
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: ::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ ExFreePool(rwContext->Urb);
+ IoFreeMdl(rwContext->Mdl);
+ ExFreePool(rwContext);
+
+ }
+
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Leaving\n"));
+
+ return ntStatus;
+
+}
+
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#include "stdio.h"
+#include "fbtusb.h"
+#include "fbtpnp.h"
+#include "fbtpwr.h"
+#include "fbtdev.h"
+#include "fbtwmi.h"
+#include "fbtrwr.h"
+
+#include "fbtusr.h"
+
+
+// Globals
+GLOBALS Globals;
+ULONG DebugLevel=255;
+
+// Forward declaration
+NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING UniRegistryPath );
+VOID NTAPI FreeBT_DriverUnload(IN PDRIVER_OBJECT DriverObject);
+NTSTATUS NTAPI FreeBT_AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject);
+
+#ifdef PAGE_CODE
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(PAGE, FreeBT_DriverUnload)
+#endif
+#endif
+
+NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING UniRegistryPath)
+{
+ NTSTATUS ntStatus;
+ PUNICODE_STRING registryPath;
+
+ registryPath = &Globals.FreeBT_RegistryPath;
+
+ registryPath->MaximumLength = UniRegistryPath->Length + sizeof(UNICODE_NULL);
+ registryPath->Length = UniRegistryPath->Length;
+ registryPath->Buffer = (PWSTR) ExAllocatePool(PagedPool, registryPath->MaximumLength);
+
+ if (!registryPath->Buffer)
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: Failed to allocate memory for registryPath\n"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto DriverEntry_Exit;
+
+ }
+
+
+ RtlZeroMemory (registryPath->Buffer, registryPath->MaximumLength);
+ RtlMoveMemory (registryPath->Buffer, UniRegistryPath->Buffer, UniRegistryPath->Length);
+
+ ntStatus = STATUS_SUCCESS;
+
+ // Initialize the driver object with this driver's entry points.
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FreeBT_DispatchDevCtrl;
+ DriverObject->MajorFunction[IRP_MJ_POWER] = FreeBT_DispatchPower;
+ DriverObject->MajorFunction[IRP_MJ_PNP] = FreeBT_DispatchPnP;
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = FreeBT_DispatchCreate;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = FreeBT_DispatchClose;
+ DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FreeBT_DispatchClean;
+ DriverObject->MajorFunction[IRP_MJ_READ] = FreeBT_DispatchRead;
+ DriverObject->MajorFunction[IRP_MJ_WRITE] = FreeBT_DispatchWrite;
+#ifdef ENABLE_WMI
+ DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = FreeBT_DispatchSysCtrl;
+#endif
+ DriverObject->DriverUnload = FreeBT_DriverUnload;
+ DriverObject->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE) FreeBT_AddDevice;
+
+DriverEntry_Exit:
+ return ntStatus;
+
+}
+
+VOID NTAPI FreeBT_DriverUnload(IN PDRIVER_OBJECT DriverObject)
+{
+ PUNICODE_STRING registryPath;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DriverUnload: Entered\n"));
+
+ registryPath = &Globals.FreeBT_RegistryPath;
+ if(registryPath->Buffer)
+ {
+ ExFreePool(registryPath->Buffer);
+ registryPath->Buffer = NULL;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DriverUnload: Leaving\n"));
+
+ return;
+
+}
+
+// AddDevice, called when an instance of our supported hardware is found
+// Returning anything other than NT_SUCCESS here causes the device to fail
+// to initialise
+NTSTATUS NTAPI FreeBT_AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject)
+{
+ NTSTATUS ntStatus;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE_EXTENSION deviceExtension;
+ POWER_STATE state;
+ KIRQL oldIrql;
+ UNICODE_STRING uniDeviceName;
+ WCHAR wszDeviceName[255]={0};
+ UNICODE_STRING uniDosDeviceName;
+ LONG instanceNumber=0;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AddDevice: Entered\n"));
+
+ deviceObject = NULL;
+
+ swprintf(wszDeviceName, L"\\Device\\FbtUsb%02d", instanceNumber);
+ RtlInitUnicodeString(&uniDeviceName, wszDeviceName);
+ ntStatus=STATUS_OBJECT_NAME_COLLISION;
+ while (instanceNumber<99 && !NT_SUCCESS(ntStatus))
+ {
+ swprintf(wszDeviceName, L"\\Device\\FbtUsb%02d", instanceNumber);
+ uniDeviceName.Length = wcslen(wszDeviceName) * sizeof(WCHAR);
+ FreeBT_DbgPrint(1, ("FBTUSB: Attempting to create device %ws\n", wszDeviceName));
+ ntStatus = IoCreateDevice(
+ DriverObject, // our driver object
+ sizeof(DEVICE_EXTENSION), // extension size for us
+ &uniDeviceName, // name for this device
+ FILE_DEVICE_UNKNOWN,
+ 0, // device characteristics
+ FALSE, // Not exclusive
+ &deviceObject); // Our device object
+
+ if (!NT_SUCCESS(ntStatus))
+ instanceNumber++;
+
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: Failed to create device object\n"));
+ return ntStatus;
+
+ }
+
+ FreeBT_DbgPrint(1, ("FBTUSB: Created device %ws\n", wszDeviceName));
+
+ deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
+ deviceExtension->FunctionalDeviceObject = deviceObject;
+ deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ swprintf(deviceExtension->wszDosDeviceName, L"\\DosDevices\\FbtUsb%02d", instanceNumber);
+ RtlInitUnicodeString(&uniDosDeviceName, deviceExtension->wszDosDeviceName);
+ ntStatus=IoCreateSymbolicLink(&uniDosDeviceName, &uniDeviceName);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: Failed to create symbolic link %ws to %ws, status=0x%08x\n", deviceExtension->wszDosDeviceName, wszDeviceName, ntStatus));
+ IoDeleteDevice(deviceObject);
+ return ntStatus;
+
+ }
+
+ FreeBT_DbgPrint(1, ("FBTUSB: Created symbolic link %ws\n", deviceExtension->wszDosDeviceName));
+
+ KeInitializeSpinLock(&deviceExtension->DevStateLock);
+
+ INITIALIZE_PNP_STATE(deviceExtension);
+
+ deviceExtension->OpenHandleCount = 0;
+
+ // Initialize the selective suspend variables
+ KeInitializeSpinLock(&deviceExtension->IdleReqStateLock);
+ deviceExtension->IdleReqPend = 0;
+ deviceExtension->PendingIdleIrp = NULL;
+
+ // Hold requests until the device is started
+ deviceExtension->QueueState = HoldRequests;
+
+ // Initialize the queue and the queue spin lock
+ InitializeListHead(&deviceExtension->NewRequestsQueue);
+ KeInitializeSpinLock(&deviceExtension->QueueLock);
+
+ // Initialize the remove event to not-signaled.
+ KeInitializeEvent(&deviceExtension->RemoveEvent, SynchronizationEvent, FALSE);
+
+ // Initialize the stop event to signaled.
+ // This event is signaled when the OutstandingIO becomes 1
+ KeInitializeEvent(&deviceExtension->StopEvent, SynchronizationEvent, TRUE);
+
+ // OutstandingIo count biased to 1.
+ // Transition to 0 during remove device means IO is finished.
+ // Transition to 1 means the device can be stopped
+ deviceExtension->OutStandingIO = 1;
+ KeInitializeSpinLock(&deviceExtension->IOCountLock);
+
+#ifdef ENABLE_WMI
+ // Delegating to WMILIB
+ ntStatus = FreeBT_WmiRegistration(deviceExtension);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WmiRegistration failed with %X\n", ntStatus));
+ IoDeleteDevice(deviceObject);
+ IoDeleteSymbolicLink(&uniDosDeviceName);
+ return ntStatus;
+
+ }
+#endif
+
+ // Set the flags as underlying PDO
+ if (PhysicalDeviceObject->Flags & DO_POWER_PAGABLE)
+ {
+ deviceObject->Flags |= DO_POWER_PAGABLE;
+
+ }
+
+ // Typically, the function driver for a device is its
+ // power policy owner, although for some devices another
+ // driver or system component may assume this role.
+ // Set the initial power state of the device, if known, by calling
+ // PoSetPowerState.
+ deviceExtension->DevPower = PowerDeviceD0;
+ deviceExtension->SysPower = PowerSystemWorking;
+
+ state.DeviceState = PowerDeviceD0;
+ PoSetPowerState(deviceObject, DevicePowerState, state);
+
+ // attach our driver to device stack
+ // The return value of IoAttachDeviceToDeviceStack is the top of the
+ // attachment chain. This is where all the IRPs should be routed.
+ deviceExtension->TopOfStackDeviceObject = IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
+ if (NULL == deviceExtension->TopOfStackDeviceObject)
+ {
+#ifdef ENABLE_WMI
+ FreeBT_WmiDeRegistration(deviceExtension);
+#endif
+ IoDeleteDevice(deviceObject);
+ IoDeleteSymbolicLink(&uniDosDeviceName);
+ return STATUS_NO_SUCH_DEVICE;
+
+ }
+
+ // Register device interfaces
+ ntStatus = IoRegisterDeviceInterface(deviceExtension->PhysicalDeviceObject,
+ &GUID_CLASS_FREEBT_USB,
+ NULL,
+ &deviceExtension->InterfaceName);
+ if (!NT_SUCCESS(ntStatus))
+ {
+#ifdef ENABLE_WMI
+ FreeBT_WmiDeRegistration(deviceExtension);
+#endif
+ IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
+ IoDeleteDevice(deviceObject);
+ IoDeleteSymbolicLink(&uniDosDeviceName);
+ return ntStatus;
+
+ }
+
+ if (IoIsWdmVersionAvailable(1, 0x20))
+ {
+ deviceExtension->WdmVersion = WinXpOrBetter;
+
+ }
+
+ else if (IoIsWdmVersionAvailable(1, 0x10))
+ {
+ deviceExtension->WdmVersion = Win2kOrBetter;
+
+ }
+
+ else if (IoIsWdmVersionAvailable(1, 0x5))
+ {
+ deviceExtension->WdmVersion = WinMeOrBetter;
+
+ }
+
+ else if (IoIsWdmVersionAvailable(1, 0x0))
+ {
+ deviceExtension->WdmVersion = Win98OrBetter;
+
+ }
+
+ deviceExtension->SSRegistryEnable = 0;
+ deviceExtension->SSEnable = 0;
+
+ // WinXP only: check the registry flag indicating whether
+ // the device should selectively suspend when idle
+ if (WinXpOrBetter == deviceExtension->WdmVersion)
+ {
+ FreeBT_GetRegistryDword(FREEBT_REGISTRY_PARAMETERS_PATH,
+ L"BulkUsbEnable",
+ (PULONG)(&deviceExtension->SSRegistryEnable));
+ if (deviceExtension->SSRegistryEnable)
+ {
+ // initialize DPC
+ KeInitializeDpc(&deviceExtension->DeferredProcCall, DpcRoutine, deviceObject);
+
+ // initialize the timer.
+ // the DPC and the timer in conjunction,
+ // monitor the state of the device to
+ // selectively suspend the device.
+ KeInitializeTimerEx(&deviceExtension->Timer, NotificationTimer);
+
+ // Initialize the NoDpcWorkItemPendingEvent to signaled state.
+ // This event is cleared when a Dpc is fired and signaled
+ // on completion of the work-item.
+ KeInitializeEvent(&deviceExtension->NoDpcWorkItemPendingEvent, NotificationEvent, TRUE);
+
+ // Initialize the NoIdleReqPendEvent to ensure that the idle request
+ // is indeed complete before we unload the drivers.
+ KeInitializeEvent(&deviceExtension->NoIdleReqPendEvent, NotificationEvent, TRUE);
+
+ }
+
+ }
+
+ // Initialize the NoIdleReqPendEvent to ensure that the idle request
+ // is indeed complete before we unload the drivers.
+ KeInitializeEvent(&deviceExtension->DelayEvent, NotificationEvent, FALSE);
+
+ // Clear the DO_DEVICE_INITIALIZING flag.
+ // Note: Do not clear this flag until the driver has set the
+ // device power state and the power DO flags.
+ deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+ InterlockedIncrement(&instanceNumber);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_AddDevice: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<module name="fbtusb" type="kernelmodedriver" installbase="system32/drivers" installname="fbtusb.sys" allowwarnings="true">
+ <include base="fbtusb">include</include>
+ <library>ntoskrnl</library>
+ <library>hal</library>
+ <library>usbd</library>
+ <file>fbtdev.c</file>
+ <file>fbtpnp.c</file>
+ <file>fbtpwr.c</file>
+ <file>fbtrwr.c</file>
+ <file>fbtusb.c</file>
+ <!--file>fbtwmi.c</file-->
+ <file>fbtusb.rc</file>
+</module>
--- /dev/null
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "Generic USB Bluetooth Driver\0"
+#define REACTOS_STR_INTERNAL_NAME "fbtusb\0"
+#define REACTOS_STR_ORIGINAL_FILENAME "fbtusb.sys\0"
+#include <reactos/version.rc>
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#include "fbtusb.h"
+#include "fbtpwr.h"
+#include "fbtpnp.h"
+#include "fbtdev.h"
+#include "fbtrwr.h"
+#include "fbtwmi.h"
+
+#include "fbtusr.h"
+
+#define MOFRESOURCENAME L"MofResourceName"
+
+#define WMI_FREEBT_DRIVER_INFORMATION 0
+
+DEFINE_GUID (FREEBT_WMI_STD_DATA_GUID, 0x871B1A60, 0xD3EA, 0x4f2f, 0x81, 0x7b, 0x46, 0x5e, 0x44, 0x86, 0x7b, 0xf5);
+
+WMIGUIDREGINFO FreeBTWmiGuidList[1] =
+{
+ {
+ &FREEBT_WMI_STD_DATA_GUID, 1, 0 // driver information
+
+ }
+
+};
+
+NTSTATUS FreeBT_WmiRegistration(IN OUT PDEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS ntStatus;
+
+ PAGED_CODE();
+
+ DeviceExtension->WmiLibInfo.GuidCount = sizeof (FreeBTWmiGuidList) / sizeof (WMIGUIDREGINFO);
+ DeviceExtension->WmiLibInfo.GuidList = FreeBTWmiGuidList;
+ DeviceExtension->WmiLibInfo.QueryWmiRegInfo = FreeBT_QueryWmiRegInfo;
+ DeviceExtension->WmiLibInfo.QueryWmiDataBlock = FreeBT_QueryWmiDataBlock;
+ DeviceExtension->WmiLibInfo.SetWmiDataBlock = FreeBT_SetWmiDataBlock;
+ DeviceExtension->WmiLibInfo.SetWmiDataItem = FreeBT_SetWmiDataItem;
+ DeviceExtension->WmiLibInfo.ExecuteWmiMethod = NULL;
+ DeviceExtension->WmiLibInfo.WmiFunctionControl = NULL;
+
+ // Register with WMI
+ ntStatus = IoWMIRegistrationControl(DeviceExtension->FunctionalDeviceObject, WMIREG_ACTION_REGISTER);
+
+ return ntStatus;
+
+}
+
+NTSTATUS FreeBT_WmiDeRegistration(IN OUT PDEVICE_EXTENSION DeviceExtension)
+{
+ PAGED_CODE();
+ return IoWMIRegistrationControl(DeviceExtension->FunctionalDeviceObject, WMIREG_ACTION_DEREGISTER);
+
+}
+
+NTSTATUS FreeBT_DispatchSysCtrl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ PDEVICE_EXTENSION deviceExtension;
+ SYSCTL_IRP_DISPOSITION disposition;
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION irpStack;
+
+ PAGED_CODE();
+
+ irpStack = IoGetCurrentIrpStackLocation (Irp);
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ FreeBT_DbgPrint(3, ("FBTUSB: "));
+ FreeBT_DbgPrint(3, (WMIMinorFunctionString(irpStack->MinorFunction)));
+ if (Removed == deviceExtension->DeviceState)
+ {
+ ntStatus = STATUS_DELETE_PENDING;
+
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchSysCtrl::"));
+ FreeBT_IoIncrement(deviceExtension);
+
+ ntStatus = WmiSystemControl(&deviceExtension->WmiLibInfo,
+ DeviceObject,
+ Irp,
+ &disposition);
+
+ switch(disposition)
+ {
+ case IrpProcessed:
+ {
+ // This irp has been processed and may be completed or pending.
+ break;
+
+ }
+
+ case IrpNotCompleted:
+ {
+ // This irp has not been completed, but has been fully processed.
+ // we will complete it now
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ break;
+
+ }
+
+ case IrpForward:
+ case IrpNotWmi:
+ {
+ // This irp is either not a WMI irp or is a WMI irp targeted
+ // at a device lower in the stack.
+ IoSkipCurrentIrpStackLocation (Irp);
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ break;
+ }
+
+ default:
+ {
+ // We really should never get here, but if we do just forward....
+ ASSERT(FALSE);
+ IoSkipCurrentIrpStackLocation (Irp);
+ ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
+ break;
+
+ }
+
+ }
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchSysCtrl::"));
+ FreeBT_IoDecrement(deviceExtension);
+
+ return ntStatus;
+
+}
+
+NTSTATUS FreeBT_QueryWmiRegInfo(
+ IN PDEVICE_OBJECT DeviceObject,
+ OUT ULONG *RegFlags,
+ OUT PUNICODE_STRING InstanceName,
+ OUT PUNICODE_STRING *RegistryPath,
+ OUT PUNICODE_STRING MofResourceName,
+ OUT PDEVICE_OBJECT *Pdo
+ )
+/*++
+
+Routine Description:
+
+ This routine is a callback into the driver to retrieve the list of
+ guids or data blocks that the driver wants to register with WMI. This
+ routine may not pend or block. Driver should NOT call
+ WmiCompleteRequest.
+
+Arguments:
+
+ DeviceObject is the device whose data block is being queried
+
+ *RegFlags returns with a set of flags that describe the guids being
+ registered for this device. If the device wants enable and disable
+ collection callbacks before receiving queries for the registered
+ guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
+ returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
+ the instance name is determined from the PDO associated with the
+ device object. Note that the PDO must have an associated devnode. If
+ WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
+ name for the device.
+
+ InstanceName returns with the instance name for the guids if
+ WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
+ caller will call ExFreePool with the buffer returned.
+
+ *RegistryPath returns with the registry path of the driver
+
+ *MofResourceName returns with the name of the MOF resource attached to
+ the binary file. If the driver does not have a mof resource attached
+ then this can be returned as NULL.
+
+ *Pdo returns with the device object for the PDO associated with this
+ device if the WMIREG_FLAG_INSTANCE_PDO flag is returned in
+ *RegFlags.
+
+Return Value:
+
+ status
+
+--*/
+{
+ PDEVICE_EXTENSION deviceExtension;
+
+ PAGED_CODE();
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_QueryWmiRegInfo: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+ *RegFlags = WMIREG_FLAG_INSTANCE_PDO;
+ *RegistryPath = &Globals.FreeBT_RegistryPath;
+ *Pdo = deviceExtension->PhysicalDeviceObject;
+ RtlInitUnicodeString(MofResourceName, MOFRESOURCENAME);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_QueryWmiRegInfo: Leaving\n"));
+
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS FreeBT_QueryWmiDataBlock(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN ULONG GuidIndex,
+ IN ULONG InstanceIndex,
+ IN ULONG InstanceCount,
+ IN OUT PULONG InstanceLengthArray,
+ IN ULONG OutBufferSize,
+ OUT PUCHAR Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine is a callback into the driver to query for the contents of
+ a data block. When the driver has finished filling the data block it
+ must call WmiCompleteRequest to complete the irp. The driver can
+ return STATUS_PENDING if the irp cannot be completed immediately.
+
+Arguments:
+
+ DeviceObject is the device whose data block is being queried
+
+ Irp is the Irp that makes this request
+
+ GuidIndex is the index into the list of guids provided when the
+ device registered
+
+ InstanceIndex is the index that denotes which instance of the data block
+ is being queried.
+
+ InstanceCount is the number of instances expected to be returned for
+ the data block.
+
+ InstanceLengthArray is a pointer to an array of ULONG that returns the
+ lengths of each instance of the data block. If this is NULL then
+ there was not enough space in the output buffer to fulfill the request
+ so the irp should be completed with the buffer needed.
+
+ OutBufferSize has the maximum size available to write the data
+ block.
+
+ Buffer on return is filled with the returned data block
+
+
+Return Value:
+
+ status
+
+--*/
+{
+ PDEVICE_EXTENSION deviceExtension;
+ NTSTATUS ntStatus;
+ ULONG size;
+ WCHAR modelName[] = L"Aishverya\0\0";
+ USHORT modelNameLen;
+
+ PAGED_CODE();
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_QueryWmiDataBlock: Entered\n"));
+
+ size = 0;
+ modelNameLen = (wcslen(modelName) + 1) * sizeof(WCHAR);
+
+ // Only ever registers 1 instance per guid
+ ASSERT((InstanceIndex == 0) && (InstanceCount == 1));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ switch (GuidIndex)
+ {
+ case WMI_FREEBT_DRIVER_INFORMATION:
+ size = sizeof(ULONG) + modelNameLen + sizeof(USHORT);
+ if (OutBufferSize < size )
+ {
+ FreeBT_DbgPrint(3, ("FBTUSB: OutBuffer too small\n"));
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ break;
+
+ }
+
+ * (PULONG) Buffer = DebugLevel;
+ Buffer += sizeof(ULONG);
+
+ // put length of string ahead of string
+ *((PUSHORT)Buffer) = modelNameLen;
+ Buffer = (PUCHAR)Buffer + sizeof(USHORT);
+ RtlCopyBytes((PVOID)Buffer, (PVOID)modelName, modelNameLen);
+ *InstanceLengthArray = size ;
+
+ ntStatus = STATUS_SUCCESS;
+ break;
+
+ default:
+ ntStatus = STATUS_WMI_GUID_NOT_FOUND;
+
+ }
+
+ ntStatus = WmiCompleteRequest(DeviceObject,
+ Irp,
+ ntStatus,
+ size,
+ IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_QueryWmiDataBlock: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+
+NTSTATUS FreeBT_SetWmiDataItem(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN ULONG GuidIndex,
+ IN ULONG InstanceIndex,
+ IN ULONG DataItemId,
+ IN ULONG BufferSize,
+ IN PUCHAR Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine is a callback into the driver to set for the contents of
+ a data block. When the driver has finished filling the data block it
+ must call WmiCompleteRequest to complete the irp. The driver can
+ return STATUS_PENDING if the irp cannot be completed immediately.
+
+Arguments:
+
+ DeviceObject is the device whose data block is being queried
+
+ Irp is the Irp that makes this request
+
+ GuidIndex is the index into the list of guids provided when the
+ device registered
+
+ InstanceIndex is the index that denotes which instance of the data block
+ is being queried.
+
+ DataItemId has the id of the data item being set
+
+ BufferSize has the size of the data item passed
+
+ Buffer has the new values for the data item
+
+
+Return Value:
+
+ status
+
+--*/
+{
+ PDEVICE_EXTENSION deviceExtension;
+ NTSTATUS ntStatus;
+ ULONG info;
+
+ PAGED_CODE();
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SetWmiDataItem: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ info = 0;
+
+ switch(GuidIndex)
+ {
+ case WMI_FREEBT_DRIVER_INFORMATION:
+ if(DataItemId == 1)
+ {
+ if(BufferSize == sizeof(ULONG))
+ {
+ DebugLevel = *((PULONG)Buffer);
+ ntStatus = STATUS_SUCCESS;
+ info = sizeof(ULONG);
+
+ }
+
+ else
+ {
+ ntStatus = STATUS_INFO_LENGTH_MISMATCH;
+
+ }
+
+ }
+
+ else
+ {
+ ntStatus = STATUS_WMI_READ_ONLY;
+
+ }
+
+ break;
+
+ default:
+ ntStatus = STATUS_WMI_GUID_NOT_FOUND;
+
+ }
+
+ ntStatus = WmiCompleteRequest(DeviceObject,
+ Irp,
+ ntStatus,
+ info,
+ IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SetWmiDataItem: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+NTSTATUS FreeBT_SetWmiDataBlock(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN ULONG GuidIndex,
+ IN ULONG InstanceIndex,
+ IN ULONG BufferSize,
+ IN PUCHAR Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine is a callback into the driver to set the contents of
+ a data block. When the driver has finished filling the data block it
+ must call WmiCompleteRequest to complete the irp. The driver can
+ return STATUS_PENDING if the irp cannot be completed immediately.
+
+Arguments:
+
+ DeviceObject is the device whose data block is being queried
+
+ Irp is the Irp that makes this request
+
+ GuidIndex is the index into the list of guids provided when the
+ device registered
+
+ InstanceIndex is the index that denotes which instance of the data block
+ is being queried.
+
+ BufferSize has the size of the data block passed
+
+ Buffer has the new values for the data block
+
+--*/
+{
+ PDEVICE_EXTENSION deviceExtension;
+ NTSTATUS ntStatus;
+ ULONG info;
+
+ PAGED_CODE();
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SetWmiDataBlock: Entered\n"));
+
+ deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ info = 0;
+
+ switch(GuidIndex)
+ {
+ case WMI_FREEBT_DRIVER_INFORMATION:
+ if(BufferSize == sizeof(ULONG))
+ {
+ DebugLevel = *(PULONG) Buffer;
+ ntStatus = STATUS_SUCCESS;
+ info = sizeof(ULONG);
+
+ }
+
+ else
+ {
+ ntStatus = STATUS_INFO_LENGTH_MISMATCH;
+
+ }
+
+ break;
+
+ default:
+ ntStatus = STATUS_WMI_GUID_NOT_FOUND;
+
+ }
+
+ ntStatus = WmiCompleteRequest(DeviceObject,
+ Irp,
+ ntStatus,
+ info,
+ IO_NO_INCREMENT);
+
+ FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_SetWmiDataBlock: Leaving\n"));
+
+ return ntStatus;
+
+}
+
+PCHAR WMIMinorFunctionString(UCHAR MinorFunction)
+{
+ switch (MinorFunction)
+ {
+ case IRP_MN_CHANGE_SINGLE_INSTANCE:
+ return "IRP_MN_CHANGE_SINGLE_INSTANCE\n";
+
+ case IRP_MN_CHANGE_SINGLE_ITEM:
+ return "IRP_MN_CHANGE_SINGLE_ITEM\n";
+
+ case IRP_MN_DISABLE_COLLECTION:
+ return "IRP_MN_DISABLE_COLLECTION\n";
+
+ case IRP_MN_DISABLE_EVENTS:
+ return "IRP_MN_DISABLE_EVENTS\n";
+
+ case IRP_MN_ENABLE_COLLECTION:
+ return "IRP_MN_ENABLE_COLLECTION\n";
+
+ case IRP_MN_ENABLE_EVENTS:
+ return "IRP_MN_ENABLE_EVENTS\n";
+
+ case IRP_MN_EXECUTE_METHOD:
+ return "IRP_MN_EXECUTE_METHOD\n";
+
+ case IRP_MN_QUERY_ALL_DATA:
+ return "IRP_MN_QUERY_ALL_DATA\n";
+
+ case IRP_MN_QUERY_SINGLE_INSTANCE:
+ return "IRP_MN_QUERY_SINGLE_INSTANCE\n";
+
+ case IRP_MN_REGINFO:
+ return "IRP_MN_REGINFO\n";
+
+ default:
+ return "IRP_MN_?????\n";
+
+ }
+
+}
--- /dev/null
+#ifndef _FBT_HCI_CMD_STRUCTS_H
+#define _FBT_HCI_CMD_STRUCTS_H
+
+// Pack structures to single unsigned char boundries
+#pragma pack(push, 1)
+
+// Command Header
+typedef struct
+{
+ unsigned short OpCode;
+ unsigned char ParameterLength;
+
+} FBT_HCI_CMD_HEADER, *PFBT_HCI_CMD_HEADER;
+
+// Link control commands
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char LAP[FBT_HCI_LAP_SIZE];
+ unsigned char InquiryLength;
+ unsigned char NumResponses;
+
+} FBT_HCI_INQUIRY, *PFBT_HCI_INQUIRY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_INQUIRY_CANCEL, *PFBT_HCI_INQUIRY_CANCEL;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short MaxPeriodLength;
+ unsigned short MinPeriodLength;
+ unsigned char LAP[FBT_HCI_LAP_SIZE];
+ unsigned char InquiryLength;
+ unsigned char NumResponses;
+
+} FBT_HCI_PERIODIC_INQUIRY_MODE, *PFBT_HCI_PERIODIC_INQUIRY_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_EXIT_PERIODIC_INQUIRY_MODE, *PFBT_HCI_EXIT_PERIODIC_INQUIRY_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned short PacketType;
+ unsigned char PageScanRepetitionMode;
+ unsigned char PageScanMode;
+ unsigned short ClockOffset;
+ unsigned char AllowRoleSwitch;
+
+} FBT_HCI_CREATE_CONNECTION, *PFBT_HCI_CREATE_CONNECTION;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned char Reason;
+
+} FBT_HCI_DISCONNECT, *PFBT_HCI_DISCONNECT;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned short PacketType;
+
+} FBT_HCI_ADD_SCO_CONNECTION, *PFBT_HCI_ADD_SCO_CONNECTION;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char Role;
+
+} FBT_HCI_ACCEPT_CONNECTION_REQUEST, *PFBT_HCI_ACCEPT_CONNECTION_REQUEST;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char Reason;
+
+} FBT_HCI_REJECT_CONNECTION_REQUEST, *PFBT_HCI_REJECT_CONNECTION_REQUEST;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char LinkKey[FBT_HCI_LINK_KEY_SIZE];
+
+} FBT_HCI_LINK_KEY_REQUEST_REPLY, *PFBT_HCI_LINK_KEY_REQUEST_REPLY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+
+} FBT_HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY, *PFBT_HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char PINCodeLength;
+ unsigned char PINCode[FBT_HCI_PIN_CODE_SIZE];
+
+} FBT_HCI_PIN_CODE_REQUEST_REPLY, *PFBT_HCI_PIN_CODE_REQUEST_REPLY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+
+} FBT_HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY, *PFBT_HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned short PacketType;
+
+} FBT_HCI_CHANGE_CONNECTION_PACKET_TYPE, *PFBT_HCI_CHANGE_CONNECTION_PACKET_TYPE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_AUTHENTICATION_REQUESTED, *PFBT_HCI_AUTHENTICATION_REQUESTED;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned char EncryptionEnable;
+
+} FBT_HCI_SET_CONNECTION_ENCRYPTION, *PFBT_HCI_SET_CONNECTION_ENCRYPTION;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_CHANGE_CONNECTION_LINK_KEY, *PFBT_HCI_CHANGE_CONNECTION_LINK_KEY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char KeyFlag;
+
+} FBT_HCI_MASTER_LINK_KEY, *PFBT_HCI_MASTER_LINK_KEY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char PageScanRepetitionMode;
+ unsigned char PageScanMode;
+ unsigned short ClockOffset;
+
+} FBT_HCI_REMOTE_NAME_REQUEST, *PFBT_HCI_REMOTE_NAME_REQUEST;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_READ_REMOTE_SUPPORTED_FEATURES, *PFBT_HCI_READ_REMOTE_SUPPORTED_FEATURES;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_READ_REMOTE_VERSION_INFORMATION, *PFBT_HCI_READ_REMOTE_VERSION_INFORMATION;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_READ_CLOCK_OFFSET, *PFBT_HCI_READ_CLOCK_OFFSET;
+
+
+// Link policy commands
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned short HoldModeMaxInterval;
+ unsigned short HoldModeMinInterval;
+
+} FBT_HCI_HOLD_MODE, *PFBT_HCI_HOLD_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned short SniffMaxInterval;
+ unsigned short SniffMinInterval;
+ unsigned short SniffAttempt;
+ unsigned short SniffTimeout;
+
+} FBT_HCI_SNIFF_MODE, *PFBT_HCI_SNIFF_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_EXIT_SNIFF_MODE, *PFBT_HCI_EXIT_SNIFF_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned short BeaconMaxInterval;
+ unsigned short BeaconMinInterval;
+
+} FBT_HCI_PARK_MODE, *PFBT_HCI_PARK_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_EXIT_PARK_MODE, *PFBT_HCI_EXIT_PARK_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned char Flags;
+ unsigned char ServiceType;
+ unsigned long TokenRate;
+ unsigned long PeakBandwidth;
+ unsigned long Latency;
+ unsigned long DelayVariation;
+
+} FBT_HCI_QOS_SETUP, *PFBT_HCI_QOS_SETUP;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_ROLE_DISCOVERY, *PFBT_HCI_ROLE_DISCOVERY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char Role;
+
+} FBT_HCI_SWITCH_ROLE, *PFBT_HCI_SWITCH_ROLE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_READ_LINK_POLICY_SETTINGS, *PFBT_HCI_READ_LINK_POLICY_SETTINGS;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned short LinkPolicySettings;
+
+} FBT_HCI_WRITE_LINK_POLICY_SETTINGS, *PFBT_HCI_WRITE_LINK_POLICY_SETTINGS;
+
+
+// Host Controller and Baseband commands
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char EventMask[8];
+
+} FBT_HCI_SET_EVENT_MASK, *PFBT_HCI_SET_EVENT_MASK;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_RESET, *PFBT_HCI_RESET;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char FilterType;
+ unsigned char FilterConditionType;
+ unsigned char Condition[7];
+
+} FBT_HCI_SET_EVENT_FILTER, *PFBT_HCI_SET_EVENT_FILTER;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_FLUSH, *PFBT_HCI_FLUSH;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_PIN_TYPE, *PFBT_HCI_READ_PIN_TYPE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char PinType;
+
+} FBT_HCI_WRITE_PIN_TYPE, *PFBT_HCI_WRITE_PIN_TYPE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_CREATE_NEW_UNIT_KEY, *PFBT_HCI_CREATE_NEW_UNIT_KEY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char ReadAllFlag;
+
+} FBT_HCI_READ_STORED_LINK_KEY, *PFBT_HCI_READ_STORED_LINK_KEY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char NumKeysToWrite;
+ unsigned char BD_ADDR[FBT_HCI_VARIABLE_SIZE][FBT_HCI_BDADDR_SIZE];
+ unsigned char LinkKey[FBT_HCI_VARIABLE_SIZE][FBT_HCI_LINK_KEY_SIZE];
+
+} FBT_HCI_WRITE_STORED_LINK_KEY, *PFBT_HCI_WRITE_STORED_LINK_KEY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char DeleteAllFlag;
+
+} FBT_HCI_DELETE_STORED_LINK_KEY, *PFBT_HCI_DELETE_STORED_LINK_KEY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char Name[FBT_HCI_NAME_SIZE];
+
+} FBT_HCI_CHANGE_LOCAL_NAME, *PFBT_HCI_CHANGE_LOCAL_NAME;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_LOCAL_NAME, *PFBT_HCI_READ_LOCAL_NAME;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_CONNECTION_ACCEPT_TIMEOUT, *PFBT_HCI_READ_CONNECTION_ACCEPT_TIMEOUT;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnAcceptTimeout;
+
+} FBT_HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT, *PFBT_HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_PAGE_TIMEOUT, *PFBT_HCI_READ_PAGE_TIMEOUT;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short PageTimeout;
+
+} FBT_HCI_WRITE_PAGE_TIMEOUT, *PFBT_HCI_WRITE_PAGE_TIMEOUT;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_SCAN_ENABLE, *PFBT_HCI_READ_SCAN_ENABLE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char ScanEnable;
+
+} FBT_HCI_WRITE_SCAN_ENABLE, *PFBT_HCI_WRITE_SCAN_ENABLE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_PAGE_SCAN_ACTIVITY, *PFBT_HCI_READ_PAGE_SCAN_ACTIVITY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short PageScanInterval;
+ unsigned short PageScanWindow;
+
+} FBT_HCI_WRITE_PAGE_SCAN_ACTIVITY, *PFBT_HCI_WRITE_PAGE_SCAN_ACTIVITY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_INQUIRY_SCAN_ACTIVITY, *PFBT_HCI_READ_INQUIRY_SCAN_ACTIVITY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short InquiryScanInterval;
+ unsigned short InquiryScanWindow;
+
+} FBT_HCI_WRITE_INQUIRY_SCAN_ACTIVITY, *PFBT_HCI_WRITE_INQUIRY_SCAN_ACTIVITY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_AUTHENTICATION_ENABLE, *PFBT_HCI_READ_AUTHENTICATION_ENABLE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char AuthenticationEnable;
+
+} FBT_HCI_WRITE_AUTHENTICATION_ENABLE, *PFBT_HCI_WRITE_AUTHENTICATION_ENABLE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_ENCRYPTION_MODE, *PFBT_HCI_READ_ENCRYPTION_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char EncryptionMode;
+
+} FBT_HCI_WRITE_ENCRYPTION_MODE, *PFBT_HCI_WRITE_ENCRYPTION_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_CLASS_OF_DEVICE, *PFBT_HCI_READ_CLASS_OF_DEVICE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char ClassOfDevice[FBT_HCI_DEVICE_CLASS_SIZE];
+
+} FBT_HCI_WRITE_CLASS_OF_DEVICE, *PFBT_HCI_WRITE_CLASS_OF_DEVICE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_VOICE_SETTING, *PFBT_HCI_READ_VOICE_SETTING;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short VoiceSetting;
+
+} FBT_HCI_WRITE_VOICE_SETTING, *PFBT_HCI_WRITE_VOICE_SETTING;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_READ_AUTOMATIC_FLUSH_TIMEOUT, *PFBT_HCI_READ_AUTOMATIC_FLUSH_TIMEOUT;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned short FlushTimeout;
+
+} FBT_HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT, *PFBT_HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_NUM_BROADCAST_RETRANSMISSIONS, *PFBT_HCI_READ_NUM_BROADCAST_RETRANSMISSIONS;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char NumBroadcastRetran;
+
+} FBT_HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS, *PFBT_HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_HOLD_MODE_ACTIVITY, *PFBT_HCI_READ_HOLD_MODE_ACTIVITY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char HoldModeActivity;
+
+} FBT_HCI_WRITE_HOLD_MODE_ACTIVITY, *PFBT_HCI_WRITE_HOLD_MODE_ACTIVITY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned char Type;
+
+} FBT_HCI_READ_TRANSMIT_POWER_LEVEL, *PFBT_HCI_READ_TRANSMIT_POWER_LEVEL;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_SCO_FLOW_CONTROL_ENABLE, *PFBT_HCI_READ_SCO_FLOW_CONTROL_ENABLE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char ScoFlowControlEnable;
+
+} FBT_HCI_WRITE_SCO_FLOW_CONTROL_ENABLE, *PFBT_HCI_WRITE_SCO_FLOW_CONTROL_ENABLE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char FlowControlEnable;
+
+} FBT_HCI_SET_HOST_CONTROLLER_TO_HOST_FLOW_CONTROL, *PFBT_HCI_SET_HOST_CONTROLLER_TO_HOST_FLOW_CONTROL;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short AclDataPacketLength;
+ unsigned char ScoDataPacketLength;
+ unsigned short TotalNumAclDataPackets;
+ unsigned short TotalNumScoDataPackets;
+
+} FBT_HCI_HOST_BUFFER_SIZE, *PFBT_HCI_HOST_BUFFER_SIZE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char NumberOfHandles;
+ unsigned short ConnectionHandle[FBT_HCI_VARIABLE_SIZE];
+ unsigned short HostNumOfCompletedPackets[FBT_HCI_VARIABLE_SIZE];
+
+} FBT_HCI_HOST_NUMBER_OF_COMPLETED_PACKETS, *PFBT_HCI_HOST_NUMBER_OF_COMPLETED_PACKETS;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_READ_LINK_SUPERVISION_TIMEOUT, *PFBT_HCI_READ_LINK_SUPERVISION_TIMEOUT;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+ unsigned short LinkSupervisionTimeout;
+
+} FBT_HCI_WRITE_LINK_SUPERVISION_TIMEOUT, *PFBT_HCI_WRITE_LINK_SUPERVISION_TIMEOUT;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_NUMBER_OF_SUPPORTED_IAC, *PFBT_HCI_READ_NUMBER_OF_SUPPORTED_IAC;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_CURRENT_IAC_LAP, *PFBT_HCI_READ_CURRENT_IAC_LAP;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char NumCurrentIac;
+ unsigned char IacLap[FBT_HCI_VARIABLE_SIZE][FBT_HCI_LAP_SIZE];
+
+} FBT_HCI_WRITE_CURRENT_IAC_LAP, *PFBT_HCI_WRITE_CURRENT_IAC_LAP;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_PAGE_SCAN_PERIOD_MODE, *PFBT_HCI_READ_PAGE_SCAN_PERIOD_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char PageScanPeriodMode;
+
+} FBT_HCI_WRITE_PAGE_SCAN_PERIOD_MODE, *PFBT_HCI_WRITE_PAGE_SCAN_PERIOD_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_PAGE_SCAN_MODE, *PFBT_HCI_READ_PAGE_SCAN_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char PageScanMode;
+
+} FBT_HCI_WRITE_PAGE_SCAN_MODE, *PFBT_HCI_WRITE_PAGE_SCAN_MODE;
+
+
+// Informational parameters
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_LOCAL_VERSION_INFORMATION, *PFBT_HCI_READ_LOCAL_VERSION_INFORMATION;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_LOCAL_SUPPORTED_FEATURES, *PFBT_HCI_READ_LOCAL_SUPPORTED_FEATURES;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_BUFFER_SIZE, *PFBT_HCI_READ_BUFFER_SIZE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_COUNTRY_CODE, *PFBT_HCI_READ_COUNTRY_CODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_BD_ADDR, *PFBT_HCI_READ_BD_ADDR;
+
+
+// Status parameter commands
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_READ_FAILED_CONTACT_COUNTER, *PFBT_HCI_READ_FAILED_CONTACT_COUNTER;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_RESET_FAILED_CONTACT_COUNTER, *PFBT_HCI_RESET_FAILED_CONTACT_COUNTER;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_GET_LINK_QUALITY, *PFBT_HCI_GET_LINK_QUALITY;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_READ_RSSI, *PFBT_HCI_READ_RSSI;
+
+
+// Testing commands
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_READ_LOOPBACK_MODE, *PFBT_HCI_READ_LOOPBACK_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+ unsigned char LoopbackMode;
+
+} FBT_HCI_WRITE_LOOPBACK_MODE, *PFBT_HCI_WRITE_LOOPBACK_MODE;
+
+typedef struct
+{
+ FBT_HCI_CMD_HEADER CommandHeader;
+
+} FBT_HCI_ENABLE_DEVICE_UNDER_TEST_MODE, *PFBT_HCI_ENABLE_DEVICE_UNDER_TEST_MODE;
+
+#pragma pack(pop)
+
+#endif // _FBT_HCI_CMD_STRUCTS_H
\ No newline at end of file
--- /dev/null
+#ifndef _FBT_HCI_COMMANDS_H
+#define _FBT_HCI_COMMANDS_H
+
+#include "fbtHciOpcodes.h"
+#include "fbtHciSizes.h"
+
+#include "fbtHciCmdStructs.h"
+#include "fbtHciParms.h"
+
+// Utility macro to build a command CMD from ints constituent OCF/OGF
+#define FBT_HCI_CMD(nOCF, nOGF) ((unsigned short) nOCF + (unsigned short)(nOGF << 10))
+
+// HCI Command CMDs
+// Link control CMDs
+#define FBT_HCI_CMD_INQUIRY FBT_HCI_CMD(FBT_HCI_OCF_INQUIRY, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_INQUIRY_CANCEL FBT_HCI_CMD(FBT_HCI_OCF_INQUIRY_CANCEL, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_PERIODIC_INQUIRY_MODE FBT_HCI_CMD(FBT_HCI_OCF_PERIODIC_INQUIRY_MODE, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_EXIT_PERIODIC_INQUIRY_MODE FBT_HCI_CMD(FBT_HCI_OCF_EXIT_PERIODIC_INQUIRY_MODE, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_CREATE_CONNECTION FBT_HCI_CMD(FBT_HCI_OCF_CREATE_CONNECTION, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_DISCONNECT FBT_HCI_CMD(FBT_HCI_OCF_DISCONNECT, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_ADD_SCO_CONNECTION FBT_HCI_CMD(FBT_HCI_OCF_ADD_SCO_CONNECTION, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_ACCEPT_CONNECTION_REQUEST FBT_HCI_CMD(FBT_HCI_OCF_ACCEPT_CONNECTION_REQUEST, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_REJECT_CONNECTION_REQUEST FBT_HCI_CMD(FBT_HCI_OCF_REJECT_CONNECTION_REQUEST, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_LINK_KEY_REQUEST_REPLY FBT_HCI_CMD(FBT_HCI_OCF_LINK_KEY_REQUEST_REPLY, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_LINK_KEY_REQUEST_NEGATIVE_REPLY FBT_HCI_CMD(FBT_HCI_OCF_LINK_KEY_REQUEST_NEGATIVE_REPLY, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_PIN_CODE_REQUEST_REPLY FBT_HCI_CMD(FBT_HCI_OCF_PIN_CODE_REQUEST_REPLY, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_PIN_CODE_REQUEST_NEGATIVE_REPLY FBT_HCI_CMD(FBT_HCI_OCF_PIN_CODE_REQUEST_NEGATIVE_REPLY, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_CHANGE_CONNECTION_PACKET_TYPE FBT_HCI_CMD(FBT_HCI_OCF_CHANGE_CONNECTION_PACKET_TYPE, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_AUTHENTICATION_REQUESTED FBT_HCI_CMD(FBT_HCI_OCF_AUTHENTICATION_REQUESTED, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_SET_CONNECTION_ENCRYPTION FBT_HCI_CMD(FBT_HCI_OCF_SET_CONNECTION_ENCRYPTION, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_CHANGE_CONNECTION_LINK_KEY FBT_HCI_CMD(FBT_HCI_OCF_CHANGE_CONNECTION_LINK_KEY, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_MASTER_LINK_KEY FBT_HCI_CMD(FBT_HCI_OCF_MASTER_LINK_KEY, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_REMOTE_NAME_REQUEST FBT_HCI_CMD(FBT_HCI_OCF_REMOTE_NAME_REQUEST, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_READ_REMOTE_SUPPORTED_FEATURES FBT_HCI_CMD(FBT_HCI_OCF_READ_REMOTE_SUPPORTED_FEATURES, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_READ_REMOTE_VERSION_INFORMATION FBT_HCI_CMD(FBT_HCI_OCF_READ_REMOTE_VERSION_INFORMATION, FBT_HCI_OGF_LINK_CONTROL)
+#define FBT_HCI_CMD_READ_CLOCK_OFFSET FBT_HCI_CMD(FBT_HCI_OCF_READ_CLOCK_OFFSET, FBT_HCI_OGF_LINK_CONTROL)
+
+// Link policy CMDs
+#define FBT_HCI_CMD_HOLD_MODE FBT_HCI_CMD(FBT_HCI_OCF_HOLD_MODE, FBT_HCI_OGF_LINK_POLICY)
+#define FBT_HCI_CMD_SNIFF_MODE FBT_HCI_CMD(FBT_HCI_OCF_SNIFF_MODE, FBT_HCI_OGF_LINK_POLICY)
+#define FBT_HCI_CMD_EXIT_SNIFF_MODE FBT_HCI_CMD(FBT_HCI_OCF_EXIT_SNIFF_MODE, FBT_HCI_OGF_LINK_POLICY)
+#define FBT_HCI_CMD_PARK_MODE FBT_HCI_CMD(FBT_HCI_OCF_PARK_MODE, FBT_HCI_OGF_LINK_POLICY)
+#define FBT_HCI_CMD_EXIT_PARK_MODE FBT_HCI_CMD(FBT_HCI_OCF_EXIT_PARK_MODE, FBT_HCI_OGF_LINK_POLICY)
+#define FBT_HCI_CMD_QOS_SETUP FBT_HCI_CMD(FBT_HCI_OCF_QOS_SETUP, FBT_HCI_OGF_LINK_POLICY)
+#define FBT_HCI_CMD_ROLE_DISCOVERY FBT_HCI_CMD(FBT_HCI_OCF_ROLE_DISCOVERY, FBT_HCI_OGF_LINK_POLICY)
+#define FBT_HCI_CMD_SWITCH_ROLE FBT_HCI_CMD(FBT_HCI_OCF_SWITCH_ROLE, FBT_HCI_OGF_LINK_POLICY)
+#define FBT_HCI_CMD_READ_LINK_POLICY_SETTINGS FBT_HCI_CMD(FBT_HCI_OCF_READ_LINK_POLICY_SETTINGS, FBT_HCI_OGF_LINK_POLICY)
+#define FBT_HCI_CMD_WRITE_LINK_POLICY_SETTINGS FBT_HCI_CMD(FBT_HCI_OCF_WRITE_LINK_POLICY_SETTINGS, FBT_HCI_OGF_LINK_POLICY)
+
+// Host controller & baseband command CMDs
+#define FBT_HCI_CMD_SET_EVENT_MASK FBT_HCI_CMD(FBT_HCI_OCF_SET_EVENT_MASK, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_RESET FBT_HCI_CMD(FBT_HCI_OCF_RESET, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_SET_EVENT_FILTER FBT_HCI_CMD(FBT_HCI_OCF_SET_EVENT_FILTER, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_FLUSH FBT_HCI_CMD(FBT_HCI_OCF_FLUSH, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_PIN_TYPE FBT_HCI_CMD(FBT_HCI_OCF_READ_PIN_TYPE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_PIN_TYPE FBT_HCI_CMD(FBT_HCI_OCF_WRITE_PIN_TYPE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_CREATE_NEW_UNIT_KEY FBT_HCI_CMD(FBT_HCI_OCF_CREATE_NEW_UNIT_KEY, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_STORED_LINK_KEY FBT_HCI_CMD(FBT_HCI_OCF_READ_STORED_LINK_KEY, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_STORED_LINK_KEY FBT_HCI_CMD(FBT_HCI_OCF_WRITE_STORED_LINK_KEY, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_DELETE_STORED_LINK_KEY FBT_HCI_CMD(FBT_HCI_OCF_DELETE_STORED_LINK_KEY, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_CHANGE_LOCAL_NAME FBT_HCI_CMD(FBT_HCI_OCF_CHANGE_LOCAL_NAME, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_LOCAL_NAME FBT_HCI_CMD(FBT_HCI_OCF_READ_LOCAL_NAME, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_CONNECTION_ACCEPT_TIMEOUT FBT_HCI_CMD(FBT_HCI_OCF_READ_CONNECTION_ACCEPT_TIMEOUT, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_CONNECTION_ACCEPT_TIMEOUT FBT_HCI_CMD(FBT_HCI_OCF_WRITE_CONNECTION_ACCEPT_TIMEOUT, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_PAGE_TIMEOUT FBT_HCI_CMD(FBT_HCI_OCF_READ_PAGE_TIMEOUT, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_PAGE_TIMEOUT FBT_HCI_CMD(FBT_HCI_OCF_WRITE_PAGE_TIMEOUT, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_SCAN_ENABLE FBT_HCI_CMD(FBT_HCI_OCF_READ_SCAN_ENABLE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_SCAN_ENABLE FBT_HCI_CMD(FBT_HCI_OCF_WRITE_SCAN_ENABLE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_PAGE_SCAN_ACTIVITY FBT_HCI_CMD(FBT_HCI_OCF_READ_PAGE_SCAN_ACTIVITY, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY FBT_HCI_CMD(FBT_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY FBT_HCI_CMD(FBT_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY FBT_HCI_CMD(FBT_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_AUTHENTICATION_ENABLE FBT_HCI_CMD(FBT_HCI_OCF_READ_AUTHENTICATION_ENABLE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_AUTHENTICATION_ENABLE FBT_HCI_CMD(FBT_HCI_OCF_WRITE_AUTHENTICATION_ENABLE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_ENCRYPTION_MODE FBT_HCI_CMD(FBT_HCI_OCF_READ_ENCRYPTION_MODE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_ENCRYPTION_MODE FBT_HCI_CMD(FBT_HCI_OCF_WRITE_ENCRYPTION_MODE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_CLASS_OF_DEVICE FBT_HCI_CMD(FBT_HCI_OCF_READ_CLASS_OF_DEVICE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_CLASS_OF_DEVICE FBT_HCI_CMD(FBT_HCI_OCF_WRITE_CLASS_OF_DEVICE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_VOICE_SETTING FBT_HCI_CMD(FBT_HCI_OCF_READ_VOICE_SETTING, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_VOICE_SETTING FBT_HCI_CMD(FBT_HCI_OCF_WRITE_VOICE_SETTING, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_AUTOMATIC_FLUSH_TIMEOUT FBT_HCI_CMD(FBT_HCI_OCF_READ_AUTOMATIC_FLUSH_TIMEOUT, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_AUTOMATIC_FLUSH_TIMEOUT FBT_HCI_CMD(FBT_HCI_OCF_WRITE_AUTOMATIC_FLUSH_TIMEOUT, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_NUM_BROADCAST_RETRANSMISSIONS FBT_HCI_CMD(FBT_HCI_OCF_READ_NUM_BROADCAST_RETRANSMISSIONS, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_NUM_BROADCAST_RETRANSMISSIONS FBT_HCI_CMD(FBT_HCI_OCF_WRITE_NUM_BROADCAST_RETRANSMISSIONS, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_HOLD_MODE_ACTIVITY FBT_HCI_CMD(FBT_HCI_OCF_READ_HOLD_MODE_ACTIVITY, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_HOLD_MODE_ACTIVITY FBT_HCI_CMD(FBT_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_TRANSMIT_POWER_LEVEL FBT_HCI_CMD(FBT_HCI_OCF_READ_TRANSMIT_POWER_LEVEL, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_SCO_FLOW_CONTROL_ENABLE FBT_HCI_CMD(FBT_HCI_OCF_READ_SCO_FLOW_CONTROL_ENABLE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_SCO_FLOW_CONTROL_ENABLE FBT_HCI_CMD(FBT_HCI_OCF_WRITE_SCO_FLOW_CONTROL_ENABLE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_SET_HOST_CONTROLLER_TO_HOST_FLOW_CONTROL FBT_HCI_CMD(FBT_HCI_OCF_SET_HOST_CONTROLLER_TO_HOST_FLOW_CONTROL, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_HOST_BUFFER_SIZE FBT_HCI_CMD(FBT_HCI_OCF_HOST_BUFFER_SIZE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_HOST_NUMBER_OF_COMPLETED_PACKETS FBT_HCI_CMD(FBT_HCI_OCF_HOST_NUMBER_OF_COMPLETED_PACKETS, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT FBT_HCI_CMD(FBT_HCI_OCF_READ_LINK_SUPERVISION_TIMEOUT, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT FBT_HCI_CMD(FBT_HCI_OCF_WRITE_LINK_SUPERVISION_TIMEOUT, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_NUMBER_OF_SUPPORTED_IAC FBT_HCI_CMD(FBT_HCI_OCF_READ_NUMBER_OF_SUPPORTED_IAC, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_CURRENT_IAC_LAP FBT_HCI_CMD(FBT_HCI_OCF_READ_CURRENT_IAC_LAP, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_CURRENT_IAC_LAP FBT_HCI_CMD(FBT_HCI_OCF_WRITE_CURRENT_IAC_LAP, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_PAGE_SCAN_PERIOD_MODE FBT_HCI_CMD(FBT_HCI_OCF_READ_PAGE_SCAN_PERIOD_MODE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_PAGE_SCAN_PERIOD_MODE FBT_HCI_CMD(FBT_HCI_OCF_WRITE_PAGE_SCAN_PERIOD_MODE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_READ_PAGE_SCAN_MODE FBT_HCI_CMD(FBT_HCI_OCF_READ_PAGE_SCAN_MODE, FBT_HCI_OGF_CONTROL_BASEBAND)
+#define FBT_HCI_CMD_WRITE_PAGE_SCAN_MODE FBT_HCI_CMD(FBT_HCI_OCF_WRITE_PAGE_SCAN_MODE, FBT_HCI_OGF_CONTROL_BASEBAND)
+
+// Informational parameters CMDs
+#define FBT_HCI_CMD_READ_LOCAL_VERSION_INFORMATION FBT_HCI_CMD(FBT_HCI_OCF_READ_LOCAL_VERSION_INFORMATION, FBT_HCI_OGF_INFORMATIONAL_PARAMETERS)
+#define FBT_HCI_CMD_LOCAL_SUPPPROTED_FEATURES FBT_HCI_CMD(FBT_HCI_OCF_LOCAL_SUPPPROTED_FEATURES, FBT_HCI_OGF_INFORMATIONAL_PARAMETERS)
+#define FBT_HCI_CMD_READ_BUFFER_SIZE FBT_HCI_CMD(FBT_HCI_OCF_READ_BUFFER_SIZE, FBT_HCI_OGF_INFORMATIONAL_PARAMETERS)
+#define FBT_HCI_CMD_READ_COUNTRY_CODE FBT_HCI_CMD(FBT_HCI_OCF_READ_COUNTRY_CODE, FBT_HCI_OGF_INFORMATIONAL_PARAMETERS)
+#define FBT_HCI_CMD_READ_BD_ADDR FBT_HCI_CMD(FBT_HCI_OCF_READ_BD_ADDR, FBT_HCI_OGF_INFORMATIONAL_PARAMETERS)
+
+// Status parameters CMDs
+#define FBT_HCI_CMD_READ_FAILED_CONTACT_COUNTER FBT_HCI_CMD(FBT_HCI_OCF_READ_FAILED_CONTACT_COUNTER, FBT_HCI_OGF_STATUS_PARAMETERS)
+#define FBT_HCI_CMD_RESET_FAILED_CONTACT_COUNTER FBT_HCI_CMD(FBT_HCI_OCF_RESET_FAILED_CONTACT_COUNTER, FBT_HCI_OGF_STATUS_PARAMETERS)
+#define FBT_HCI_CMD_GET_LINK_QUALITY FBT_HCI_CMD(FBT_HCI_OCF_GET_LINK_QUALITY, FBT_HCI_OGF_STATUS_PARAMETERS)
+#define FBT_HCI_CMD_READ_RSSI FBT_HCI_CMD(FBT_HCI_OCF_READ_RSSI, FBT_HCI_OGF_STATUS_PARAMETERS)
+
+// Testing CMDs
+#define FBT_HCI_CMD_READ_LOOPBACK_MODE FBT_HCI_CMD(FBT_HCI_OCF_READ_LOOPBACK_MODE, FBT_HCI_OGF_TESTING)
+#define FBT_HCI_CMD_WRITE_LOOPBACK_MODE FBT_HCI_CMD(FBT_HCI_OCF_WRITE_LOOPBACK_MODE, FBT_HCI_OGF_TESTING)
+#define FBT_HCI_CMD_ENABLE_DEVICE_UNDER_TEST_MODE FBT_HCI_CMD(FBT_HCI_OCF_ENABLE_DEVICE_UNDER_TEST_MODE, FBT_HCI_OGF_TESTING)
+
+// Packet Boundry Flags (ORed into the upper 8 bits of the connection handle)
+#define FBT_HCI_PACKET_BOUNDRY_FIRST 0x20
+#define FBT_HCI_PACKET_BOUNDRY_NEXT 0x10
+
+// HCI header types
+#define FBT_HCI_SYNC_HCI_COMMAND_PACKET 0x01
+#define FBT_HCI_SYNC_ACL_DATA_PACKET 0x02
+#define FBT_HCI_SYNC_SCO_DATA_PACKET 0x03
+#define FBT_HCI_SYNC_HCI_EVENT_PACKET 0x04
+
+// Packet types for use in CreateConnection
+#define FBT_HCI_PACKET_TYPE_DM1 0x0008 // 1 time slot, 1-18 bytes of data, FEC encoded
+#define FBT_HCI_PACKET_TYPE_DH1 0x0010 // 1 time slot, 1-28 bytes of data, not FEC encoded
+
+#define FBT_HCI_PACKET_TYPE_DM3 0x0400 // 3 time slots, 2-123 bytes of data, FEC encoded
+#define FBT_HCI_PACKET_TYPE_DH3 0x0800 // 3 time slots, 2-185 bytes of data, not FEC encoded
+
+#define FBT_HCI_PACKET_TYPE_DM5 0x4000 // 5 time slots, 2-226 bytes of data, FEC encoded
+#define FBT_HCI_PACKET_TYPE_DH5 0x8000 // 3 time slots, 2-341 bytes of data, not FEC encoded
+
+// LAP codes for use in Inquiry
+#define FBT_HCI_LAP_GIAC 0x9E8B33
+#define FBT_HCI_LAP_LIAC 0x9E8B00
+
+// Link Types
+#define FBT_HCI_LINK_TYPE_SCO 0x00
+#define FBT_HCI_LINK_TYPE_ACL 0x01
+
+// Maximum number of each type of handle
+#define FBT_HCI_MAX_ALLOWED_ACL_HANDLES 32
+#define FBT_HCI_MAX_ALLOWED_SCO_HANDLES 4
+
+#endif // _FBT_HCI_COMMANDS_H
\ No newline at end of file
--- /dev/null
+#ifndef _FBT_HCI_DEFS_H
+#define _FBT_HCI_DEFS_H
+
+#include "fbtHciCmds.h"
+#include "fbtHciEvents.h"
+#include "fbtHciErrors.h"
+
+#endif // _FBT_HCI_DEFS_H
\ No newline at end of file
--- /dev/null
+#ifndef _FBT_HCI_ERROR_H
+#define _FBT_HCI_ERROR_H
+
+#define FBT_HCI_ERROR_SUCCESS 0x00
+#define FBT_HCI_UNKNOWN_HCI_COMMAND 0x01
+#define FBT_HCI_UNKNOWN_CONNECTION_IDENTIFIER 0x02
+#define FBT_HCI_HARDWARE_FAILURE 0x03
+#define FBT_HCI_PAGE_TIMEOUT 0x04
+#define FBT_HCI_AUTHENTICATION_FAILURE 0x05
+#define FBT_HCI_PIN_MISSING 0x06
+#define FBT_HCI_MEMORY_CAPACITY_EXCEEDED 0x07
+#define FBT_HCI_CONNECTION_TIMEOUT 0x08
+#define FBT_HCI_CONNECTION_LIMIT EXCEEDED 0x09
+#define FBT_HCI_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE EXCEEDED 0x0a
+#define FBT_HCI_ACL_CONNECTION_ALREADY_EXISTS 0x0b
+#define FBT_HCI_COMMAND_DISALLOWED 0x0c
+#define FBT_HCI_CONNECTION_REJECTED_DUE_TO_LIMITED RESOURCES 0x0d
+#define FBT_HCI_CONNECTION_REJECTED_DUE_TO_SECURITY REASONS 0x0e
+#define FBT_HCI_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE BD_ADDR 0x0f
+#define FBT_HCI_CONNECTION_ACCEPT_TIMEOUT_EXCEEDED 0x10
+#define FBT_HCI_UNSUPPORTED_FEATURE_OR_PARAMETER VALUE 0x11
+#define FBT_HCI_INVALID_HCI_COMMAND_PARAMETERS 0x12
+#define FBT_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13
+#define FBT_HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES 0x14
+#define FBT_HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_POWER OFF 0x15
+#define FBT_HCI_CONNECTION_TERMINATED_BY_LOCAL_HOST 0x16
+#define FBT_HCI_REPEATED_ATTEMPTS 0x17
+#define FBT_HCI_PAIRING_NOT ALLOWED 0x18
+#define FBT_HCI_UNKNOWN_LMP_PDU 0x19
+#define FBT_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1a
+#define FBT_HCI_SCO_OFFSET_REJECTED 0x1b
+#define FBT_HCI_SCO_INTERVAL_REJECTED 0x1c
+#define FBT_HCI_SCO_AIR_MODE_REJECTED 0x1d
+#define FBT_HCI_INVALID_LMP_PARAMETERS 0x1e
+#define FBT_HCI_UNSPECIFIED_ERROR 0x1f
+#define FBT_HCI_UNSUPPORTED_LMP_PARAMETER_VALUE 0x20
+#define FBT_HCI_ROLE_CHANGE_NOT_ALLOWED 0x21
+#define FBT_HCI_LMP_RESPONSE_TIMEOUT 0x22
+#define FBT_HCI_LMP_ERROR_TRANSACTION_COLLISION 0x23
+#define FBT_HCI_LMP_PDU_NOT_ALLOWED 0x24
+#define FBT_HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE 0x25
+#define FBT_HCI_LINK_KEY_CAN_NOT_BE_CHANGED 0x26
+#define FBT_HCI_REQUESTED_QOS_NOT_SUPPORTED 0x27
+#define FBT_HCI_INSTANT_PASSED 0x28
+#define FBT_HCI_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED 0x29
+#define FBT_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2a
+#define FBT_HCI_QOS_UNACCEPTABLE PARAMETER 0x2c
+#define FBT_HCI_QOS_REJECTED 0x2d
+#define FBT_HCI_CHANNEL_CLASSIFICATION_NOT_SUPPORTED 0x2e
+#define FBT_HCI_INSUFFICIENT_SECURITY 0x2f
+#define FBT_HCI_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30
+#define FBT_HCI_ROLE_SWITCH_PENDING 0x32
+#define FBT_HCI_RESERVED_SLOT_VIOLATION 0x34
+#define FBT_HCI_ROLE_SWITCH_FAILED 0x35
+
+#define FBT_HCI_SUCCESS(x) (x==FBT_HCI_ERROR_SUCCESS)
+
+#endif // _FBT_HCI_ERROR_H
\ No newline at end of file
--- /dev/null
+#ifndef _FBT_HCI_EVENT_STRUCTS_H
+#define _FBT_HCI_EVENT_STRUCTS_H
+
+// Pack structures to single unsigned char boundries
+#pragma pack(push, 1)
+
+typedef struct
+{
+ unsigned char EventCode;
+ unsigned char ParameterLength;
+
+} FBT_HCI_EVENT_HEADER, *PFBT_HCI_EVENT_HEADER;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned char NumResponses;
+
+} FBT_HCI_INQUIRY_COMPLETE, *PFBT_HCI_INQUIRY_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char NumResponses;
+ unsigned char BD_ADDR[FBT_HCI_VARIABLE_SIZE][FBT_HCI_BDADDR_SIZE];
+ unsigned char PageScanRepetitionMode[FBT_HCI_VARIABLE_SIZE];
+ unsigned char PageScanPeriodMode[FBT_HCI_VARIABLE_SIZE];
+ unsigned char PageScanMode[FBT_HCI_VARIABLE_SIZE];
+ unsigned char ClassOfDevice[FBT_HCI_VARIABLE_SIZE][FBT_HCI_DEVICE_CLASS_SIZE];
+ unsigned short ClockOffset[FBT_HCI_VARIABLE_SIZE];
+
+} FBT_HCI_INQUIRY_RESULT, *PFBT_HCI_INQUIRY_RESULT;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char LinkType;
+ unsigned char EncryptionMode;
+
+} FBT_HCI_CONNECTION_COMPLETE, *PFBT_HCI_CONNECTION_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned long ClassOfDevice[FBT_HCI_DEVICE_CLASS_SIZE];
+ unsigned char LinkType;
+
+} FBT_HCI_CONNECTION_REQUEST, *PFBT_HCI_CONNECTION_REQUEST;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+ unsigned char Reason;
+
+} FBT_HCI_DISCONNECTION_COMPLETE, *PFBT_HCI_DISCONNECTION_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_AUTHENTICATION_COMPLETE, *PFBT_HCI_AUTHENTICATION_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char RemoteName[FBT_HCI_NAME_SIZE];
+
+} FBT_HCI_REMOTE_NAME_REQUEST_COMPLETE, *PFBT_HCI_REMOTE_NAME_REQUEST_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+ unsigned char EncryptionEnable;
+
+} FBT_HCI_ENCRYPTION_CHANGE, *PFBT_HCI_ENCRYPTION_CHANGE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_CHANGE_CONNECTION_LINK_KEY_COMPLETE, *PFBT_HCI_CHANGE_CONNECTION_LINK_KEY_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+ unsigned char KeyFlag;
+
+} FBT_HCI_MASTER_LINK_KEY_COMPLETE, *PFBT_HCI_MASTER_LINK_KEY_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+ unsigned char LmpFeatures[8];
+
+} FBT_HCI_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE, *PFBT_HCI_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+ unsigned char LmpVersion;
+ unsigned short ManufacturerName;
+ unsigned short LmpSubversion;
+
+} FBT_HCI_READ_REMOTE_VERSION_INFORMATION_COMPLETE, *PFBT_HCI_READ_REMOTE_VERSION_INFORMATION_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+ unsigned char Flags;
+ unsigned char ServiceType;
+ unsigned long TokenRate;
+ unsigned long PeakBandwidth;
+ unsigned long Latency;
+ unsigned long DelayVariation;
+
+} FBT_HCI_QOS_SETUP_COMPLETE, *PFBT_HCI_QOS_SETUP_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char NumHCICommandPackets;
+ unsigned short OpCode;
+ unsigned char Parameters[FBT_HCI_VARIABLE_SIZE];
+
+} FBT_HCI_COMMAND_COMPLETE, *PFBT_HCI_COMMAND_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned char NumHCICommandPackets;
+ unsigned short OpCode;
+
+} FBT_HCI_COMMAND_STATUS, *PFBT_HCI_COMMAND_STATUS;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char HardwareCode;
+
+} FBT_HCI_HARDWARE_ERROR, *PFBT_HCI_HARDWARE_ERROR;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_FLUSH_OCCURRED, *PFBT_HCI_FLUSH_OCCURRED;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char NewRole;
+
+} FBT_HCI_ROLE_CHANGE, *PFBT_HCI_ROLE_CHANGE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char NumberOfHandles;
+ unsigned short ConnectionHandle[FBT_HCI_VARIABLE_SIZE];
+ unsigned short NumberOfCompletedPackets[FBT_HCI_VARIABLE_SIZE];
+
+} FBT_HCI_NUMBER_OF_COMPLETED_PACKETS, *PFBT_HCI_NUMBER_OF_COMPLETED_PACKETS;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+ unsigned char CurrentMode;
+ unsigned short Interval;
+
+} FBT_HCI_MODE_CHANGE, *PFBT_HCI_MODE_CHANGE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char NumKeys;
+ unsigned char BD_ADDR[FBT_HCI_VARIABLE_SIZE][FBT_HCI_BDADDR_SIZE];
+ unsigned char LinkKey[FBT_HCI_VARIABLE_SIZE][FBT_HCI_LINK_KEY_SIZE];
+
+} FBT_HCI_RETURN_LINK_KEYS, *PFBT_HCI_RETURN_LINK_KEYS;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+
+} FBT_HCI_PIN_CODE_REQUEST, *PFBT_HCI_PIN_CODE_REQUEST;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+
+} FBT_HCI_LINK_KEY_REQUEST, *PFBT_HCI_LINK_KEY_REQUEST;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char LinkKey[FBT_HCI_LINK_KEY_SIZE];
+
+} FBT_HCI_LINK_KEY_NOTIFICATION, *PFBT_HCI_LINK_KEY_NOTIFICATION;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char HCICommandPacket[FBT_HCI_CMD_MAX_SIZE];
+
+} FBT_HCI_LOOPBACK_COMMAND, *PFBT_HCI_LOOPBACK_COMMAND;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char LinkType;
+
+} FBT_HCI_DATA_BUFFER_OVERFLOW, *PFBT_HCI_DATA_BUFFER_OVERFLOW;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned short ConnectionHandle;
+ unsigned char LmpMaxSlots;
+
+} FBT_HCI_MAX_SLOTS_CHANGE, *PFBT_HCI_MAX_SLOTS_CHANGE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+ unsigned short ClockOffset;
+
+} FBT_HCI_READ_CLOCK_OFFSET_COMPLETE, *PFBT_HCI_READ_CLOCK_OFFSET_COMPLETE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char Status;
+ unsigned short ConnectionHandle;
+ unsigned short PacketType;
+
+} FBT_HCI_CONNECTION_PACKET_TYPE_CHANGED, *PFBT_HCI_CONNECTION_PACKET_TYPE_CHANGED;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned short ConnectionHandle;
+
+} FBT_HCI_QOS_VIOLATION, *PFBT_HCI_QOS_VIOLATION;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char PageScanMode;
+
+} FBT_HCI_PAGE_SCAN_MODE_CHANGE, *PFBT_HCI_PAGE_SCAN_MODE_CHANGE;
+
+typedef struct
+{
+ FBT_HCI_EVENT_HEADER EventHeader;
+ unsigned char BD_ADDR[FBT_HCI_BDADDR_SIZE];
+ unsigned char PageScanRepetitionMode;
+
+} FBT_HCI_PAGE_SCAN_REPETITION_MODE_CHANGE, *PFBT_HCI_PAGE_SCAN_REPETITION_MODE_CHANGE;
+
+typedef struct
+{
+ unsigned char Status;
+ unsigned char HCIVersion;
+ unsigned short HCIRevision;
+ unsigned char LMPVersion;
+ unsigned short Manufacturer;
+ unsigned short LMPSubVersion;
+
+} FBT_HCI_READ_LOCAL_VERSION_INFORMATION_COMPLETE;
+
+// Data Packet Structure
+typedef struct
+{
+ unsigned short ConnectionHandle: 12;
+ unsigned short PacketBoundary: 2;
+ unsigned short Broadcast: 2;
+ unsigned short DataLength;
+ unsigned char Data[1];
+
+} FBT_HCI_DATA_PACKET, *PFBT_HCI_DATA_PACKET;
+
+#pragma pack(pop)
+
+#endif // _FBT_HCI_EVENT_STRUCTS_H
\ No newline at end of file
--- /dev/null
+#ifndef _FBT_HCI_EVENTS_H
+#define _FBT_HCI_EVENTS_H
+
+#include "fbtHciEventStructs.h"
+
+#define FBT_HCI_EVENT_INVALID 0x00
+#define FBT_HCI_EVENT_INQUIRY_COMPLETE 0x01
+#define FBT_HCI_EVENT_INQUIRY_RESULT 0x02
+#define FBT_HCI_EVENT_CONNECTION_COMPLETE 0x03
+#define FBT_HCI_EVENT_CONNECTION_REQUEST 0x04
+#define FBT_HCI_EVENT_DISCONNECTION_COMPLETE 0x05
+#define FBT_HCI_EVENT_AUTHENTICATION_COMPLETE 0x06
+#define FBT_HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE 0x07
+#define FBT_HCI_EVENT_ENCRYPTION_CHANGE_EVENT 0x08
+#define FBT_HCI_EVENT_CHANGE_CONNECTION_LINK_KEY_COMPLETE 0x09
+#define FBT_HCI_EVENT_MASTER_LINK_KEY_COMPLETE 0x0a
+#define FBT_HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES 0x0b
+#define FBT_HCI_EVENT_READ_REMOTE_VERSION_INFORMATION 0x0c
+#define FBT_HCI_EVENT_QOS_SETUP_COMPLETE 0x0d
+#define FBT_HCI_EVENT_COMMAND_COMPLETE 0x0e
+#define FBT_HCI_EVENT_COMMAND_STATUS 0x0f
+#define FBT_HCI_EVENT_HARDWARE_ERROR 0x10
+#define FBT_HCI_EVENT_FLUSH_OCCURRED 0x11
+#define FBT_HCI_EVENT_ROLE_CHANGE 0x12
+#define FBT_HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS 0x13
+#define FBT_HCI_EVENT_MODE_CHANGE 0x14
+#define FBT_HCI_EVENT_RETURN_LINK_KEYS 0x15
+#define FBT_HCI_EVENT_PIN_CODE_REQUEST 0x16
+#define FBT_HCI_EVENT_LINK_KEY_REQUEST 0x17
+#define FBT_HCI_EVENT_LINK_KEY_NOTIFICATION 0x18
+#define FBT_HCI_EVENT_LOOPBACK_COMMAND 0x19
+#define FBT_HCI_EVENT_DATA_BUFFER_OVERFLOW_EVENT 0x1a
+#define FBT_HCI_EVENT_MAX_SLOTS_CHANGE 0x1b
+#define FBT_HCI_EVENT_READ_CLOCK_OFFSET 0x1c
+#define FBT_HCI_EVENT_CONNECTION_PACKET_TYPE_CHANGED 0x1d
+#define FBT_HCI_EVENT_QOS_VIOLATION 0x1e
+#define FBT_HCI_EVENT_PAGE_SCAN_MODE_CHANGE 0x1f
+#define FBT_HCI_EVENT_PAGE_SCAN_REPETITION_MODE_CHANGE 0x20
+#define FBT_HCI_EVENT_FLOW_SPECIFICATION_COMPLETE 0x21
+#define FBT_HCI_EVENT_INQUIRY_RESULT_WITH_RSSI 0x22
+#define FBT_HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES_COMPLETE 0x23
+#define FBT_HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE 0x24
+#define FBT_HCI_EVENT_SYNCHRONOUS_CONNECTION_CHANGED 0x25
+
+#endif // _FBT_HCI_EVENTS_H
\ No newline at end of file
--- /dev/null
+#ifndef _LOCAL_HCI_H_
+#define _LOCAL_HCI_H_
+
+#include "fbtHci.h"
+
+#define MAX_QUEUED_COMMANDS 100
+
+typedef struct _QueuedCommand
+{
+ USHORT nCommand;
+ BYTE *pResultBuffer;
+ DWORD dwBufferSize;
+ HANDLE hEvent;
+
+} QueuedCommand, *PQueuedCommand;
+
+// Local HCI command abstraction
+// 1. Send Command
+// 2. Wait for Command status / Command complete
+class CHciLocal : public CHci
+{
+public:
+ CHciLocal(void);
+ virtual ~CHciLocal(void);
+
+ virtual int QueueCommand(USHORT nCommand, BYTE *pResultBuffer=NULL, DWORD dwBufferSize=0);
+ virtual int QueueCommandStatus(USHORT nCommand);
+ virtual void DeQueueCommand(int nSlot);
+ virtual DWORD ClearQueue(void);
+ virtual PQueuedCommand GetQueuedCommand(int nSlot);
+
+ virtual DWORD WaitForCommandComplete(int nSlot);
+ virtual DWORD WaitForCommandStatus(int nSlot, BYTE &nStatus);
+
+ virtual DWORD SendReset(void);
+ virtual DWORD SendWriteClassOfDevice(BYTE ClassOfDevice[FBT_HCI_DEVICE_CLASS_SIZE]);
+ virtual DWORD SendSetEventFilter(
+ BYTE nFilterType,
+ BYTE nFilterConditionType,
+ BYTE nCondition[FBT_HCI_MAX_CONDITION_SIZE],
+ BYTE nConditionBytes);
+
+ virtual DWORD SendInquiry(ULONG nLAP, BYTE nInquiryLength, BYTE nNumResponses);
+ virtual DWORD SendInquiryCancel(void);
+ virtual DWORD SendCreateConnection(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE],
+ USHORT nPacketType,
+ BYTE nPageScanRepetitionMode,
+ BYTE nPageScanMode,
+ USHORT nClockOffset,
+ BYTE nAllowRoleSwitch);
+
+ virtual DWORD SendDisconnect(USHORT nConnectionHandle, BYTE nReason);
+ virtual DWORD SendSwitchRole(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE nRole);
+ virtual DWORD SendRemoteNameRequest(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE nPageScanRepetitionMode, BYTE nPageScanMode, USHORT nClockOffset);
+ virtual DWORD SendReadLocalVersionInformation(FBT_HCI_READ_LOCAL_VERSION_INFORMATION_COMPLETE &CommandComplete);
+
+ virtual DWORD OnEvent(PFBT_HCI_EVENT_HEADER pEvent, DWORD dwLength);
+
+ virtual DWORD CommandCompleteHandler(USHORT nCommand, BYTE *pParameters, DWORD dwParameterLength);
+ virtual DWORD CommandStatusHandler(BYTE nStatus, USHORT nCommand);
+
+protected:
+ virtual int FindCommandSlot(USHORT nCommand);
+
+ QueuedCommand m_QueuedCommands[MAX_QUEUED_COMMANDS];
+ CRITICAL_SECTION m_QueueCriticalSection;
+
+};
+
+
+#endif // _LOCAL_HCI_H_
--- /dev/null
+#ifndef _FBT_HCI_OPCODES_H
+#define _FBT_HCI_OPCODES_H
+
+// Opcode Group Field (OGF) codes
+#define FBT_HCI_OGF_LINK_CONTROL 0x01 // Link control group
+#define FBT_HCI_OGF_LINK_POLICY 0x02 // Link polic group
+#define FBT_HCI_OGF_CONTROL_BASEBAND 0x03 // Host Controller & Baseband group
+#define FBT_HCI_OGF_INFORMATIONAL_PARAMETERS 0x04 // Information parameters group
+#define FBT_HCI_OGF_STATUS_PARAMETERS 0x05 // Status parameters group
+#define FBT_HCI_OGF_TESTING 0x06 // Test group
+
+// Opcode Command Field (OCF) codes
+// Link control commands
+#define FBT_HCI_OCF_INQUIRY 0x0001
+#define FBT_HCI_OCF_INQUIRY_CANCEL 0x0002
+#define FBT_HCI_OCF_PERIODIC_INQUIRY_MODE 0x0003
+#define FBT_HCI_OCF_EXIT_PERIODIC_INQUIRY_MODE 0x0004
+#define FBT_HCI_OCF_CREATE_CONNECTION 0x0005
+#define FBT_HCI_OCF_DISCONNECT 0x0006
+#define FBT_HCI_OCF_ADD_SCO_CONNECTION 0x0007
+
+#define FBT_HCI_OCF_ACCEPT_CONNECTION_REQUEST 0x0009
+#define FBT_HCI_OCF_REJECT_CONNECTION_REQUEST 0x000A
+#define FBT_HCI_OCF_LINK_KEY_REQUEST_REPLY 0x000B
+#define FBT_HCI_OCF_LINK_KEY_REQUEST_NEGATIVE_REPLY 0x000C
+#define FBT_HCI_OCF_PIN_CODE_REQUEST_REPLY 0x000D
+#define FBT_HCI_OCF_PIN_CODE_REQUEST_NEGATIVE_REPLY 0x000E
+#define FBT_HCI_OCF_CHANGE_CONNECTION_PACKET_TYPE 0x000F
+
+#define FBT_HCI_OCF_AUTHENTICATION_REQUESTED 0x0011
+#define FBT_HCI_OCF_SET_CONNECTION_ENCRYPTION 0x0013
+#define FBT_HCI_OCF_CHANGE_CONNECTION_LINK_KEY 0x0015
+#define FBT_HCI_OCF_MASTER_LINK_KEY 0x0017
+#define FBT_HCI_OCF_REMOTE_NAME_REQUEST 0x0019
+#define FBT_HCI_OCF_READ_REMOTE_SUPPORTED_FEATURES 0x001B
+#define FBT_HCI_OCF_READ_REMOTE_VERSION_INFORMATION 0x001D
+#define FBT_HCI_OCF_READ_CLOCK_OFFSET 0x001F
+
+// Link policy commands
+#define FBT_HCI_OCF_HOLD_MODE 0x0001
+#define FBT_HCI_OCF_SNIFF_MODE 0x0003
+#define FBT_HCI_OCF_EXIT_SNIFF_MODE 0x0004
+#define FBT_HCI_OCF_PARK_MODE 0x0005
+#define FBT_HCI_OCF_EXIT_PARK_MODE 0x0006
+#define FBT_HCI_OCF_QOS_SETUP 0x0007
+#define FBT_HCI_OCF_ROLE_DISCOVERY 0x0009
+#define FBT_HCI_OCF_SWITCH_ROLE 0x000B
+#define FBT_HCI_OCF_READ_LINK_POLICY_SETTINGS 0x000C
+#define FBT_HCI_OCF_WRITE_LINK_POLICY_SETTINGS 0x000D
+
+// Host controller & baseband commands
+#define FBT_HCI_OCF_SET_EVENT_MASK 0x0001
+#define FBT_HCI_OCF_RESET 0x0003
+#define FBT_HCI_OCF_SET_EVENT_FILTER 0x0005
+#define FBT_HCI_OCF_FLUSH 0x0008
+#define FBT_HCI_OCF_READ_PIN_TYPE 0x0009
+#define FBT_HCI_OCF_WRITE_PIN_TYPE 0x000A
+#define FBT_HCI_OCF_CREATE_NEW_UNIT_KEY 0x000B
+#define FBT_HCI_OCF_READ_STORED_LINK_KEY 0x000D
+#define FBT_HCI_OCF_WRITE_STORED_LINK_KEY 0x0011
+#define FBT_HCI_OCF_DELETE_STORED_LINK_KEY 0x0012
+#define FBT_HCI_OCF_CHANGE_LOCAL_NAME 0x0013
+#define FBT_HCI_OCF_READ_LOCAL_NAME 0x0014
+#define FBT_HCI_OCF_READ_CONNECTION_ACCEPT_TIMEOUT 0x0015
+#define FBT_HCI_OCF_WRITE_CONNECTION_ACCEPT_TIMEOUT 0x0016
+#define FBT_HCI_OCF_READ_PAGE_TIMEOUT 0x0017
+#define FBT_HCI_OCF_WRITE_PAGE_TIMEOUT 0x0018
+#define FBT_HCI_OCF_READ_SCAN_ENABLE 0x0019
+#define FBT_HCI_OCF_WRITE_SCAN_ENABLE 0x001A
+#define FBT_HCI_OCF_READ_PAGE_SCAN_ACTIVITY 0x001B
+#define FBT_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY 0x001C
+#define FBT_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY 0x001D
+#define FBT_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY 0x001E
+#define FBT_HCI_OCF_READ_AUTHENTICATION_ENABLE 0x001F
+#define FBT_HCI_OCF_WRITE_AUTHENTICATION_ENABLE 0x0020
+#define FBT_HCI_OCF_READ_ENCRYPTION_MODE 0x0021
+#define FBT_HCI_OCF_WRITE_ENCRYPTION_MODE 0x0022
+#define FBT_HCI_OCF_READ_CLASS_OF_DEVICE 0x0023
+#define FBT_HCI_OCF_WRITE_CLASS_OF_DEVICE 0x0024
+#define FBT_HCI_OCF_READ_VOICE_SETTING 0x0025
+#define FBT_HCI_OCF_WRITE_VOICE_SETTING 0x0026
+#define FBT_HCI_OCF_READ_AUTOMATIC_FLUSH_TIMEOUT 0x0027
+#define FBT_HCI_OCF_WRITE_AUTOMATIC_FLUSH_TIMEOUT 0x0028
+#define FBT_HCI_OCF_READ_NUM_BROADCAST_RETRANSMISSIONS 0x0029
+#define FBT_HCI_OCF_WRITE_NUM_BROADCAST_RETRANSMISSIONS 0x002A
+#define FBT_HCI_OCF_READ_HOLD_MODE_ACTIVITY 0x002B
+#define FBT_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY 0x002C
+#define FBT_HCI_OCF_READ_TRANSMIT_POWER_LEVEL 0x002D
+#define FBT_HCI_OCF_READ_SCO_FLOW_CONTROL_ENABLE 0x002E
+#define FBT_HCI_OCF_WRITE_SCO_FLOW_CONTROL_ENABLE 0x002F
+#define FBT_HCI_OCF_SET_HOST_CONTROLLER_TO_HOST_FLOW_CONTROL 0x0031
+#define FBT_HCI_OCF_HOST_BUFFER_SIZE 0x0033
+#define FBT_HCI_OCF_HOST_NUMBER_OF_COMPLETED_PACKETS 0x0035
+#define FBT_HCI_OCF_READ_LINK_SUPERVISION_TIMEOUT 0x0036
+#define FBT_HCI_OCF_WRITE_LINK_SUPERVISION_TIMEOUT 0x0037
+#define FBT_HCI_OCF_READ_NUMBER_OF_SUPPORTED_IAC 0x0038
+#define FBT_HCI_OCF_READ_CURRENT_IAC_LAP 0x0039
+#define FBT_HCI_OCF_WRITE_CURRENT_IAC_LAP 0x003A
+#define FBT_HCI_OCF_READ_PAGE_SCAN_PERIOD_MODE 0x003B
+#define FBT_HCI_OCF_WRITE_PAGE_SCAN_PERIOD_MODE 0x003C
+#define FBT_HCI_OCF_READ_PAGE_SCAN_MODE 0x003D
+#define FBT_HCI_OCF_WRITE_PAGE_SCAN_MODE 0x003E
+
+// Informational parameter commands
+#define FBT_HCI_OCF_READ_LOCAL_VERSION_INFORMATION 0x0001
+#define FBT_HCI_OCF_LOCAL_SUPPPROTED_FEATURES 0x0003
+#define FBT_HCI_OCF_READ_BUFFER_SIZE 0x0005
+#define FBT_HCI_OCF_READ_COUNTRY_CODE 0x0007
+#define FBT_HCI_OCF_READ_BD_ADDR 0x0009
+
+// Status parameters commands
+#define FBT_HCI_OCF_READ_FAILED_CONTACT_COUNTER 0x0001
+#define FBT_HCI_OCF_RESET_FAILED_CONTACT_COUNTER 0x0002
+#define FBT_HCI_OCF_GET_LINK_QUALITY 0x0003
+#define FBT_HCI_OCF_READ_RSSI 0x0005
+
+// Test commands
+#define FBT_HCI_OCF_READ_LOOPBACK_MODE 0x0001
+#define FBT_HCI_OCF_WRITE_LOOPBACK_MODE 0x0002
+#define FBT_HCI_OCF_ENABLE_DEVICE_UNDER_TEST_MODE 0x0003
+
+#define FBT_HCI_OGF_FROM_COMMAND(cmd) (cmd>>10)
+#define FBT_HCI_OCF_FROM_COMMAND(cmd) (cmd&0x3FF)
+
+#endif // _FBT_HCI_OPCODES_H
\ No newline at end of file
--- /dev/null
+#ifndef _FBT_HCI_PARAMETERS_H
+#define _FBT_HCI_PARAMETERS_H
+
+// HCI header types
+#define FBT_HCI_SYNC_HCI_COMMAND_PACKET 0x01
+#define FBT_HCI_SYNC_ACL_DATA_PACKET 0x02
+#define FBT_HCI_SYNC_SCO_DATA_PACKET 0x03
+#define FBT_HCI_SYNC_HCI_EVENT_PACKET 0x04
+
+// Packet types for use in CreateConnection
+#define FBT_HCI_PACKET_TYPE_DM1 0x0008 // 1 time slot, 1-18 bytes of data, FEC encoded
+#define FBT_HCI_PACKET_TYPE_DH1 0x0010 // 1 time slot, 1-28 bytes of data, not FEC encoded
+
+#define FBT_HCI_PACKET_TYPE_DM3 0x0400 // 3 time slots, 2-123 bytes of data, FEC encoded
+#define FBT_HCI_PACKET_TYPE_DH3 0x0800 // 3 time slots, 2-185 bytes of data, not FEC encoded
+
+#define FBT_HCI_PACKET_TYPE_DM5 0x4000 // 5 time slots, 2-226 bytes of data, FEC encoded
+#define FBT_HCI_PACKET_TYPE_DH5 0x8000 // 3 time slots, 2-341 bytes of data, not FEC encoded
+
+#define FBT_HCI_PACKET_TYPE_ALL (FBT_HCI_PACKET_TYPE_DM1|FBT_HCI_PACKET_TYPE_DH1|FBT_HCI_PACKET_TYPE_DM3|FBT_HCI_PACKET_TYPE_DH3|FBT_HCI_PACKET_TYPE_DM5|FBT_HCI_PACKET_TYPE_DH5)
+
+// LAP codes for use in Inquiry
+#define FBT_HCI_LAP_GIAC 0x9E8B33
+#define FBT_HCI_LAP_LIAC 0x9E8B00
+
+// Link Types
+#define FBT_HCI_LINK_TYPE_SCO 0x00
+#define FBT_HCI_LINK_TYPE_ACL 0x01
+
+// Roles
+#define FBT_HCI_ROLE_MASTER 0x00
+#define FBT_HCI_ROLE_SLAVE 0x01
+
+// Event Filters
+#define FBT_HCI_FILTER_NONE 0x00
+#define FBT_HCI_FILTER_INQUIRY_RESULT 0x01
+#define FBT_HCI_FILTER_CONNECTION_SETUP 0x02
+
+#define FBT_HCI_FILTER_ALL 0x00
+#define FBT_HCI_FILTER_CLASS_OF_DEVICE 0x01
+#define FBT_HCI_FILTER_BDADDR 0x02
+
+// Data packet parameters
+#define FBT_HCI_PACKET_BOUNDARY_FRAGMENT 0x01
+#define FBT_HCI_PACKET_BOUNDARY_START 0x02
+
+#define FBT_HCI_BROADCAST_POINT_TO_POINT 0x00
+#define FBT_HCI_BROADCAST_ACTIVE_SLAVE 0x01
+#define FBT_HCI_BROADCAST_PARKED_SLAVE 0x02
+
+#endif // _FBT_HCI_PARAMETERS_H
\ No newline at end of file
--- /dev/null
+#ifndef _ROUND_TRIP_HCI_H_
+#define _ROUND_TRIP_HCI_H_
+
+#include "fbtHciLocal.h"
+
+// Complete round trip HCI abstraction
+// 1. Send Command
+// 2. Wait for Command status / Command complete
+// 3. Wait fo event
+class CHciRoundTrip : public CHciLocal
+{
+public:
+
+ CHciRoundTrip();
+ virtual ~CHciRoundTrip();
+
+ virtual DWORD QueueEvent(BYTE EventCode, LPVOID pParameters, DWORD dwParameterLength);
+ virtual DWORD WaitForEvent();
+
+ virtual DWORD OnEvent(PFBT_HCI_EVENT_HEADER pEvent, DWORD Length);
+
+ virtual DWORD ReadBDADDR(BYTE *BDADDR);
+ virtual DWORD ReadClassOfDevice(BYTE *ClassOfDevice);
+ virtual DWORD ReadLocalName(BYTE *Name);
+ virtual DWORD CreateConnection(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE],
+ USHORT PacketType,
+ BYTE PageScanRepetitionMode,
+ BYTE PageScanMode,
+ USHORT ClockOffset,
+ BYTE AllowRoleSwitch,
+ USHORT &ConnectionHandle);
+
+ virtual DWORD Disconnect(USHORT ConnectionHandler, BYTE Reason);
+ virtual DWORD SwitchRole(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE Role);
+ virtual DWORD RemoteNameRequest(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE],
+ BYTE PageScanRepetitionMode,
+ BYTE PageScanMode,
+ USHORT ClockOffset,
+ BYTE Name[FBT_HCI_NAME_SIZE]);
+
+protected:
+ BYTE m_PendingEvent;
+ LPVOID m_pEventParameters;
+ DWORD m_dwEventParameterLength;
+
+ HANDLE m_hEventSignal;
+
+};
+
+
+#endif // _ROUND_TRIP_HCI_H_
--- /dev/null
+#ifndef _FBT_HCI_SIZES_H
+#define _FBT_HCI_SIZES_H
+
+// Sizes
+#define FBT_HCI_CMD_MIN_SIZE 3
+#define FBT_HCI_CMD_MAX_SIZE 258
+
+#define FBT_HCI_EVENT_MAX_SIZE 257
+
+#define FBT_HCI_DATA_MIN_SIZE 5
+#define FBT_HCI_DATA_MAX_SIZE 343
+
+#define FBT_HCI_BDADDR_SIZE 6
+#define FBT_HCI_NAME_SIZE 248
+
+#define FBT_HCI_DEVICE_CLASS_SIZE 3
+
+#define FBT_HCI_LAP_SIZE 3
+#define FBT_HCI_MAX_CONDITION_SIZE 7
+
+#define FBT_HCI_LINK_KEY_SIZE 16
+#define FBT_HCI_PIN_CODE_SIZE 16
+
+#define FBT_HCI_VARIABLE_SIZE 1
+
+
+#endif // _FBT_HCI_SIZES_H
\ No newline at end of file
--- /dev/null
+#ifndef __SEEXCEPTION_H__
+#define __SEEXCEPTION_H__
+
+#include <windows.h>
+
+class fbtSeException
+{
+ public:
+ fbtSeException(unsigned int nSeCode, _EXCEPTION_POINTERS* pExcPointers);
+ fbtSeException(fbtSeException & CseExc);
+
+ unsigned int GetSeCode(void);
+
+ private:
+ unsigned int m_nSeCode;
+ _EXCEPTION_POINTERS* m_pExcPointers;
+
+};
+
+void fbtXcptEnableSEHandling();
+
+#endif //__SEEXCEPTION_H__
\ No newline at end of file
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#ifndef _FREEBT_DEV_H
+#define _FREEBT_DEV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NTSTATUS FreeBT_DispatchCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS FreeBT_DispatchClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS FreeBT_DispatchDevCtrl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS FreeBT_ResetPipe(IN PDEVICE_OBJECT DeviceObject, IN USBD_PIPE_HANDLE PipeInfo);
+NTSTATUS FreeBT_ResetDevice(IN PDEVICE_OBJECT DeviceObject);
+NTSTATUS FreeBT_GetPortStatus(IN PDEVICE_OBJECT DeviceObject, IN PULONG PortStatus);
+NTSTATUS FreeBT_ResetParentPort(IN IN PDEVICE_OBJECT DeviceObject);
+
+NTSTATUS SubmitIdleRequestIrp(IN PDEVICE_EXTENSION DeviceExtension);
+VOID IdleNotificationCallback(IN PDEVICE_EXTENSION DeviceExtension);
+NTSTATUS IdleNotificationRequestComplete(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PDEVICE_EXTENSION DeviceExtension);
+
+VOID CancelSelectSuspend(IN PDEVICE_EXTENSION DeviceExtension);
+VOID PoIrpCompletionFunc(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus);
+
+VOID PoIrpAsyncCompletionFunc(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus);
+
+VOID WWIrpCompletionFunc(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
--- /dev/null
+#ifndef _HCI_H_
+#define _HCI_H_
+
+#include <windows.h>
+
+#include "fbthw.h"
+#include "fbtHciDefs.h"
+
+// Number of overlapped requests to have pending in the driver
+#define HCI_NUMBER_OF_OVERLAPPED_LISTENS MAXIMUM_WAIT_OBJECTS-1
+
+// HCI Abstraction layer
+class CHci;
+typedef struct
+{
+ PFBT_HCI_EVENT_HEADER pEvent;
+ DWORD dwLength;
+ CHci *pThis;
+
+} HCI_EVENT, *PHCI_EVENT;
+
+class CHci : public CBTHW
+{
+public:
+ CHci(void);
+ virtual ~CHci(void);
+
+ virtual DWORD StartEventListener(void);
+ virtual DWORD StopEventListener(void);
+ virtual DWORD OnEvent(PFBT_HCI_EVENT_HEADER pEvent, DWORD Length);
+
+ static LPCTSTR GetEventText(BYTE Event);
+ static LPCTSTR GetStatusText(BYTE Status);
+ static LPCTSTR GetManufacturerName(USHORT Company);
+
+ virtual DWORD OnCommandComplete(BYTE NumHCICommandPackets, USHORT CommandOpcode, BYTE *Parameters, DWORD ParameterLength);
+ virtual DWORD OnCommandStatus(BYTE Status, BYTE NumHCICommandPackets, USHORT CommandOpcode);
+
+ virtual DWORD OnConnectionRequest(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], ULONG ClassOfDevice[FBT_HCI_DEVICE_CLASS_SIZE], BYTE LinkType);
+ virtual DWORD OnConnectionComplete(BYTE Status, USHORT ConnectionHandle, BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE LinkType, BYTE EncryptionMode);
+ virtual DWORD OnDisconnectionComplete(BYTE Status, USHORT ConnectionHandle, BYTE Reason);
+
+ virtual DWORD OnInquiryComplete(BYTE Status, BYTE NumResponses);
+ virtual DWORD OnInquiryResult(BYTE NumResponses, BYTE BD_ADDR[FBT_HCI_VARIABLE_SIZE][FBT_HCI_BDADDR_SIZE], BYTE PageScanRepetitionMode[FBT_HCI_VARIABLE_SIZE], BYTE PageScanPeriodMode[FBT_HCI_VARIABLE_SIZE], BYTE PageScanMode[FBT_HCI_VARIABLE_SIZE], BYTE ClassOfDevice[FBT_HCI_VARIABLE_SIZE][FBT_HCI_DEVICE_CLASS_SIZE], USHORT ClockOffset[FBT_HCI_VARIABLE_SIZE]);
+
+ virtual DWORD OnRemoteNameRequestComplete(BYTE Status, BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE RemoteName[FBT_HCI_NAME_SIZE]);
+
+ virtual DWORD OnRoleChange(BYTE Status, BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE Role);
+
+ virtual DWORD OnPINCodeRequest(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE]);
+
+ virtual DWORD OnLinkKeyNotification(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE LinkKey[FBT_HCI_LINK_KEY_SIZE]);
+ virtual DWORD OnLinkKeyRequest(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE]);
+
+ virtual DWORD OnAuthenticationComplete(BYTE Status, USHORT ConnectionHandle);
+
+ virtual DWORD OnReadLocalNameComplete(BYTE Status, BYTE Name[FBT_HCI_NAME_SIZE]);
+
+ virtual DWORD OnUnknown(PFBT_HCI_EVENT_HEADER pEvent, DWORD Length);
+
+ virtual DWORD SendReset(void);
+
+ virtual DWORD SendInquiry(ULONG LAP, BYTE InquiryLength, BYTE NumResponses);
+ virtual DWORD SendInquiryCancel(void);
+
+ virtual DWORD SendReadBDADDR(void);
+
+ virtual DWORD SendWriteScanEnable(BYTE ScanEnable);
+
+ virtual DWORD SendWriteAuthenticationEnable(BYTE ScanEnable);
+
+ virtual DWORD SendSetEventFilter(BYTE FilterType,
+ BYTE FilterConditionType,
+ BYTE Condition[FBT_HCI_MAX_CONDITION_SIZE],
+ BYTE ConditionBytes);
+
+ virtual DWORD SendReadClassOfDevice(void);
+
+ virtual DWORD SendWriteClassOfDevice(BYTE ClassOfDevice[FBT_HCI_DEVICE_CLASS_SIZE]);
+
+ virtual DWORD SendCreateConnection(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE],
+ USHORT PacketType,
+ BYTE PageScanRepetitionMode,
+ BYTE PageScanMode,
+ USHORT ClockOffset,
+ BYTE AllowRoleSwitch);
+
+ virtual DWORD SendAcceptConnectionRequest(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE RoleSwitch);
+
+ virtual DWORD SendDisconnect(USHORT ConnectionHandle, BYTE Reason);
+
+ virtual DWORD SendWriteLinkSupervisionTimeout(USHORT ConnectionHandle, USHORT LinkSupervisionTimeout);
+
+ virtual DWORD SendWritePageTimeout(USHORT PageTimeout);
+
+ virtual DWORD SendRemoteNameRequest(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE PageScanRepetitionMode, BYTE PageScanMode, USHORT ClockOffset);
+
+ virtual DWORD SendReadLocalName(void);
+
+ virtual DWORD SendChangeLocalName(BYTE Name[FBT_HCI_NAME_SIZE]);
+
+ virtual DWORD SendSwitchRole(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE Role);
+
+ virtual DWORD SendPINCodeRequestReply(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE PINCodeLength, BYTE PINCode[FBT_HCI_PIN_CODE_SIZE]);
+ virtual DWORD SendPINCodeRequestNegativeReply(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE]);
+
+ virtual DWORD SendLinkKeyRequestReply(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE LinkKey[FBT_HCI_LINK_KEY_SIZE]);
+ virtual DWORD SendLinkKeyRequestNegativeReply(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE]);
+
+ virtual DWORD SendReadLocalVersionInformation(void);
+
+ DWORD CompareBDADDRs(BYTE BD_ADDR1[FBT_HCI_BDADDR_SIZE], BYTE BD_ADDR2[FBT_HCI_BDADDR_SIZE]);
+
+protected:
+ friend static DWORD CALLBACK Listener(LPVOID pContext);
+ friend static DWORD EventHandler(PFBT_HCI_EVENT_HEADER pEvent, DWORD Length);
+
+ virtual DWORD SendHciCommand(PFBT_HCI_CMD_HEADER lpCommand, DWORD dwBufferSize);
+
+ DWORD SendListenForEvent(OVERLAPPED *pOverlapped, BYTE *pEventBuffer);
+
+ HANDLE m_hStopListeningEvent;
+ HANDLE m_hListenerReadyEvent;
+ HANDLE m_hListenerThread;
+
+ DWORD m_dwListenerThreadId;
+
+ OVERLAPPED m_Overlappeds[HCI_NUMBER_OF_OVERLAPPED_LISTENS];
+ BYTE m_pEventBuffers[HCI_NUMBER_OF_OVERLAPPED_LISTENS][FBT_HCI_EVENT_MAX_SIZE];
+
+};
+
+
+#endif // _HCI_H_
--- /dev/null
+#ifndef _FBT_HW_H_
+#define _FBT_HW_H_
+
+#include <winioctl.h>
+
+// HW Driver Abstraction layer
+class CBTHW
+{
+public:
+ // The driver is opened for OVERLAPPED I/O
+ CBTHW();
+ virtual ~CBTHW();
+
+ // Set the driver instances symbolic name
+ void SetDeviceName(LPCTSTR szDeviceName);
+ DWORD GetDeviceName(LPTSTR szBuffer, DWORD dwBufferSize);
+
+ // Open a handle to the driver instance
+ virtual DWORD Attach(LPCSTR szDeviceName);
+ virtual DWORD Detach();
+ HANDLE GetDriverHandle();
+ BOOL IsAttached() {return GetDriverHandle()!=INVALID_HANDLE_VALUE;}
+
+ // Send a command to the driver
+ DWORD SendCommand(DWORD dwCommand, LPVOID lpInBuffer=NULL, DWORD dwInBufferSize=0, LPVOID lpOutBuffer=NULL, DWORD dwOutBufferSize=0, OVERLAPPED *pOverlapped=NULL);
+ DWORD SendData(LPVOID lpBuffer, DWORD dwBufferSize, DWORD *dwBytesSent, OVERLAPPED *pOverlapped);
+ DWORD GetData(LPVOID lpBuffer, DWORD dwBufferSize, DWORD *dwBytesRead, OVERLAPPED *pOverlapped);
+
+protected:
+ HANDLE m_hDriver;
+ TCHAR m_szDeviceName[1024];
+
+};
+
+
+#endif // _FBT_HW_H_
--- /dev/null
+#ifndef _FBT_DEBUG
+#define _FBT_DEBUG
+
+#define fbtLog_None 0
+#define fbtLog_Failure 1
+#define fbtLog_Warning 2
+#define fbtLog_Notice 3
+#define fbtLog_Enter 4
+#define fbtLog_Exit 4
+#define fbtLog_Verbose 5
+#define fbtLog_Exception 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void fbtLog(unsigned int nLevel, const char *szText, ...);
+BOOL fbtLogSetFile(char *szDebugFile);
+void fbtLogSetLevel(unsigned int nLevel);
+unsigned int fbtLogGetLevel(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#ifndef _FREEBT_PNP_H
+#define _FREEBT_PNP_H
+
+#define REMOTE_WAKEUP_MASK 0x20
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NTSTATUS FreeBT_DispatchPnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleStartDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleQueryStopDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleRemoveDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleCancelStopDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleStopDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleQueryCapabilities(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS ReadandSelectDescriptors(IN PDEVICE_OBJECT DeviceObject);
+NTSTATUS ConfigureDevice(IN PDEVICE_OBJECT DeviceObject);
+NTSTATUS SelectInterfaces(IN PDEVICE_OBJECT DeviceObject, IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor);
+NTSTATUS DeconfigureDevice(IN PDEVICE_OBJECT DeviceObject);
+NTSTATUS CallUSBD(IN PDEVICE_OBJECT DeviceObject, IN PURB Urb);
+VOID ProcessQueuedRequests(IN OUT PDEVICE_EXTENSION DeviceExtension);
+NTSTATUS FreeBT_GetRegistryDword(IN PWCHAR RegPath, IN PWCHAR ValueName, IN OUT PULONG Value);
+NTSTATUS FreeBT_DispatchClean(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+VOID DpcRoutine(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2);
+
+VOID IdleRequestWorkerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context);
+NTSTATUS FreeBT_AbortPipes(IN PDEVICE_OBJECT DeviceObject);
+NTSTATUS IrpCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);
+NTSTATUS CanStopDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS CanRemoveDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS ReleaseMemory(IN PDEVICE_OBJECT DeviceObject);
+LONG FreeBT_IoIncrement(IN OUT PDEVICE_EXTENSION DeviceExtension);
+LONG FreeBT_IoDecrement(IN OUT PDEVICE_EXTENSION DeviceExtension);
+BOOLEAN CanDeviceSuspend(IN PDEVICE_EXTENSION DeviceExtension);
+PCHAR PnPMinorFunctionString (IN UCHAR MinorFunction);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#ifndef _FREEBT_POWER_H
+#define _FREEBT_POWER_H
+
+typedef struct _POWER_COMPLETION_CONTEXT
+{
+ PDEVICE_OBJECT DeviceObject;
+ PIRP SIrp;
+
+} POWER_COMPLETION_CONTEXT, *PPOWER_COMPLETION_CONTEXT;
+
+typedef struct _WORKER_THREAD_CONTEXT
+{
+ PDEVICE_OBJECT DeviceObject;
+ PIRP Irp;
+ PIO_WORKITEM WorkItem;
+
+} WORKER_THREAD_CONTEXT, *PWORKER_THREAD_CONTEXT;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NTSTATUS FreeBT_DispatchPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleSystemQueryPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleSystemSetPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS HandleDeviceQueryPower(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS SysPoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension);
+VOID SendDeviceIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+VOID DevPoCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus
+ );
+
+NTSTATUS HandleDeviceSetPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS FinishDevPoUpIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension);
+NTSTATUS SetDeviceFunctional(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension);
+NTSTATUS FinishDevPoDnIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension);
+NTSTATUS HoldIoRequests(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+VOID HoldIoRequestsWorkerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context);
+NTSTATUS QueueRequest(IN OUT PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp);
+VOID CancelQueued(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS WaitWakeCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension);
+NTSTATUS IssueWaitWake(IN PDEVICE_EXTENSION DeviceExtension);
+VOID CancelWaitWake(IN PDEVICE_EXTENSION DeviceExtension);
+VOID WaitWakeCallback(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus
+ );
+
+PCHAR PowerMinorFunctionString(IN UCHAR MinorFunction);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
--- /dev/null
+#ifndef REG_H
+#define REG_H
+
+class CReg
+{
+ public:
+ // Constructor
+ CReg(LPCSTR lpszSubKey, HKEY hRootKey=HKEY_CURRENT_USER, REGSAM regSam=KEY_ALL_ACCESS, BOOL bCreate=TRUE);
+
+ // Destructor
+ ~CReg();
+
+ // Get the specified registry value
+ BOOL GetValue(LPCSTR lpszValueName, LPVOID lpvData, DWORD *dwBuffSize=NULL, DWORD *dwDataType=NULL);
+ BOOL GetValue(LPCSTR lpszValueName, LPSTR lpszValue, DWORD dwBalueSize);
+// BOOL GetValue(LPCSTR lpszValueName, CString &szData, DWORD *dwDataType=NULL);
+ BOOL GetValue(LPCSTR lpszValueName, DWORD &dwData);
+ BOOL GetValue(LPCSTR lpszValueName, BOOL &bData);
+
+ // Set the specified registry value
+ BOOL SetValue(LPCSTR lpszValueName, const LPVOID lpvData, DWORD dwDataSize, DWORD dwDataType=REG_SZ);
+ BOOL SetValue(LPCSTR lpszValueName, LPCSTR lpszValue, DWORD dwDataSize=0, DWORD dwDataType=REG_SZ);
+ BOOL SetValue(LPCSTR lpszValueName, LPSTR lpszValue, DWORD dwValueSize);
+// BOOL SetValue(LPCSTR lpszValueName, CString &szData, DWORD dwDataSize=0, DWORD dwDataType=REG_SZ);
+ BOOL SetValue(LPCSTR lpszValueName, DWORD dwData);
+ BOOL SetValue(LPCSTR lpszValueName, BOOL bData);
+
+ // Delete a value in the key
+ BOOL DeleteValue(LPCSTR lpszValueName);
+
+ // Delete all the values in the key
+ BOOL DeleteValues();
+
+ // Delete a sub key
+ BOOL DeleteKey(LPCSTR lpszKeyName);
+
+ // Retrieve the names of the values in the key
+// BOOL EnumerateValues(CStringArray &nszValueNames);
+
+ BOOL IsValid() {return m_hKey!=NULL;}
+
+ protected:
+ // Create a new registry key
+ LONG Create(LPCSTR lpszSubKey, HKEY hRootKey, HKEY *hKey=NULL, REGSAM regSam=NULL);
+
+ // Open the specified registry key (creates if non-existant)
+ LONG Open(LPCSTR lpszSubKey, HKEY hRootKey, HKEY *hKey=NULL, REGSAM regSam=NULL, BOOL bCreate=TRUE);
+
+ BOOL DeleteKey(HKEY hRootKey, HKEY hKey, LPCSTR szKey, LPCSTR szSubKey);
+
+// CString m_szKey; // Name of key this object wraps
+ char m_szKey[1024]; // Name of key this object wraps
+ HKEY m_hRootKey; // Root key of the wrapped key
+ HKEY m_hKey; // Key generated by Open/Create
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#ifndef _FREEBT_RWR_H
+#define _FREEBT_RWR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _FREEBT_RW_CONTEXT
+{
+ PURB Urb;
+ PMDL Mdl;
+ ULONG Length; // remaining to xfer
+ ULONG Numxfer; // cumulate xfer
+ ULONG_PTR VirtualAddress; // va for next segment of xfer.
+
+} FREEBT_RW_CONTEXT, * PFREEBT_RW_CONTEXT;
+
+NTSTATUS FreeBT_DispatchRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS FreeBT_ReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);
+NTSTATUS FreeBT_DispatchWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS FreeBT_WriteCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#ifndef _FREEBT_H
+#define _FREEBT_H
+
+#include <initguid.h>
+#include <wdm.h>
+#include <wmilib.h>
+#include <wmistr.h>
+#include <windef.h>
+#include "usbdi.h"
+#include "usbdlib.h"
+
+// Pull in all the command, event and structure definitions
+#include "fbtHciDefs.h"
+
+// Standard USB Wireless/Bluetooth class, etc
+#define FREEBT_USB_STDCLASS 0xE0 // Wireless Controller
+#define FREEBT_USB_STDSUBCLASS 0x01 // RF Controller
+#define FREEBT_USB_STDPROTOCOL 0x01 // Bluetooth Programming
+
+// Recommended Bluetooth Endpoints
+#define FREEBT_STDENDPOINT_HCICMD 0x00 // HCI Command
+#define FREEBT_STDENDPOINT_HCIEVENT 0x81 // HCI Event
+#define FREEBT_STDENDPOINT_ACLIN 0x82 // HCI Data In
+#define FREEBT_STDENDPOINT_ACLOUT 0x02 // HCI Data Out
+#define FREEBT_STDENDPOINT_AUDIOIN 0x83 // SCO In
+#define FREEBT_STDENDPOINT_AUDIOOUT 0x03 // SCO Out
+
+
+#define OBTTAG (ULONG) 'OBTU'
+
+#undef ExAllocatePool
+#define ExAllocatePool(type, size) ExAllocatePoolWithTag(type, size, OBTTAG);
+
+#if DBG
+
+#define FreeBT_DbgPrint(level, _x_) \
+ if((level) <= DebugLevel) { \
+ DbgPrint _x_; \
+ }
+
+#else
+
+#define FreeBT_DbgPrint(level, _x_)
+
+#endif
+
+typedef struct _GLOBALS
+{
+ UNICODE_STRING FreeBT_RegistryPath;
+
+} GLOBALS;
+
+#define IDLE_INTERVAL 5000
+
+typedef enum _PIPETYPE
+{
+ HciCommandPipe,
+ HciEventPipe,
+ AclDataIn,
+ AclDataOut,
+ SCODataIn,
+ SCODataOut
+
+} FREEBT_PIPETYPE;
+
+typedef enum _DEVSTATE
+{
+ NotStarted, // not started
+ Stopped, // device stopped
+ Working, // started and working
+ PendingStop, // stop pending
+ PendingRemove, // remove pending
+ SurpriseRemoved, // removed by surprise
+ Removed // removed
+
+} DEVSTATE;
+
+typedef enum _QUEUE_STATE
+{
+ HoldRequests, // device is not started yet
+ AllowRequests, // device is ready to process
+ FailRequests // fail both existing and queued up requests
+
+} QUEUE_STATE;
+
+typedef enum _WDM_VERSION
+{
+ WinXpOrBetter,
+ Win2kOrBetter,
+ WinMeOrBetter,
+ Win98OrBetter
+
+} WDM_VERSION;
+
+#define INITIALIZE_PNP_STATE(_Data_) \
+ (_Data_)->DeviceState = NotStarted;\
+ (_Data_)->PrevDevState = NotStarted;
+
+#define SET_NEW_PNP_STATE(_Data_, _state_) \
+ (_Data_)->PrevDevState = (_Data_)->DeviceState;\
+ (_Data_)->DeviceState = (_state_);
+
+#define RESTORE_PREVIOUS_PNP_STATE(_Data_) \
+ (_Data_)->DeviceState = (_Data_)->PrevDevState;
+
+
+// registry path used for parameters
+// global to all instances of the driver
+#define FREEBT_REGISTRY_PARAMETERS_PATH L"\\REGISTRY\\Machine\\System\\CurrentControlSet\\SERVICES\\BULKUSB\\Parameters"
+
+typedef struct _FREEBT_PIPE_CONTEXT
+{
+ BOOLEAN PipeOpen;
+ FREEBT_PIPETYPE PipeType;
+
+} FREEBT_PIPE_CONTEXT, *PFREEBT_PIPE_CONTEXT;
+
+// A structure representing the instance information associated with
+// this particular device.
+typedef struct _DEVICE_EXTENSION
+{
+ // Functional Device Object
+ PDEVICE_OBJECT FunctionalDeviceObject;
+
+ // Device object we call when submitting Urbs
+ PDEVICE_OBJECT TopOfStackDeviceObject;
+
+ // The bus driver object
+ PDEVICE_OBJECT PhysicalDeviceObject;
+
+ // Name buffer for our named Functional device object link
+ // The name is generated based on the driver's class GUID
+ UNICODE_STRING InterfaceName;
+
+ // Bus drivers set the appropriate values in this structure in response
+ // to an IRP_MN_QUERY_CAPABILITIES IRP. Function and filter drivers might
+ // alter the capabilities set by the bus driver.
+ DEVICE_CAPABILITIES DeviceCapabilities;
+
+ // Configuration Descriptor
+ PUSB_CONFIGURATION_DESCRIPTOR UsbConfigurationDescriptor;
+
+ // Interface Information structure
+ PUSBD_INTERFACE_INFORMATION UsbInterface;
+
+ // Pipe context for the driver
+ PFREEBT_PIPE_CONTEXT PipeContext;
+
+ // current state of device
+ DEVSTATE DeviceState;
+
+ // state prior to removal query
+ DEVSTATE PrevDevState;
+
+ // obtain and hold this lock while changing the device state,
+ // the queue state and while processing the queue.
+ KSPIN_LOCK DevStateLock;
+
+ // current system power state
+ SYSTEM_POWER_STATE SysPower;
+
+ // current device power state
+ DEVICE_POWER_STATE DevPower;
+
+ // Pending I/O queue state
+ QUEUE_STATE QueueState;
+
+ // Pending I/O queue
+ LIST_ENTRY NewRequestsQueue;
+
+ // I/O Queue Lock
+ KSPIN_LOCK QueueLock;
+
+ KEVENT RemoveEvent;
+
+ KEVENT StopEvent;
+
+ ULONG OutStandingIO;
+
+ KSPIN_LOCK IOCountLock;
+
+ // Selective Suspend variables
+ LONG SSEnable;
+ LONG SSRegistryEnable;
+ PUSB_IDLE_CALLBACK_INFO IdleCallbackInfo;
+ PIRP PendingIdleIrp;
+ LONG IdleReqPend;
+ LONG FreeIdleIrpCount;
+ KSPIN_LOCK IdleReqStateLock;
+ KEVENT NoIdleReqPendEvent;
+
+ // Default power state to power down to on self-susped
+ ULONG PowerDownLevel;
+
+ // remote wakeup variables
+ PIRP WaitWakeIrp;
+ LONG FlagWWCancel;
+ LONG FlagWWOutstanding;
+ LONG WaitWakeEnable;
+
+ // Open handle count
+ LONG OpenHandleCount;
+
+ // Selective suspend model uses timers, dpcs and work item.
+ KTIMER Timer;
+
+ KDPC DeferredProcCall;
+
+ // This event is cleared when a DPC/Work Item is queued.
+ // and signaled when the work-item completes.
+ // This is essential to prevent the driver from unloading
+ // while we have DPC or work-item queued up.
+ KEVENT NoDpcWorkItemPendingEvent;
+
+ // WMI information
+ WMILIB_CONTEXT WmiLibInfo;
+
+ // WDM version
+ WDM_VERSION WdmVersion;
+
+ // Pipe type
+ FREEBT_PIPETYPE PipeType;
+
+ // User accessible object name
+ WCHAR wszDosDeviceName[50];
+
+ // A never triggered event used for delaying execution
+ KEVENT DelayEvent;
+
+ // Significant pipes
+ USBD_PIPE_INFORMATION EventPipe;
+ USBD_PIPE_INFORMATION DataInPipe;
+ USBD_PIPE_INFORMATION DataOutPipe;
+ USBD_PIPE_INFORMATION AudioInPipe;
+ USBD_PIPE_INFORMATION AudioOutPipe;
+
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+
+typedef struct _IRP_COMPLETION_CONTEXT
+{
+ PDEVICE_EXTENSION DeviceExtension;
+ PKEVENT Event;
+
+} IRP_COMPLETION_CONTEXT, *PIRP_COMPLETION_CONTEXT;
+
+extern GLOBALS Globals;
+extern ULONG DebugLevel;
+
+#endif
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#ifndef _FREEBT_USER_H
+#define _FREEBT_USER_H
+
+#include <initguid.h>
+//#include <winioctl.h>
+
+// {7591F7C7-E760-434a-92D3-C1869930423C}
+DEFINE_GUID(GUID_CLASS_FREEBT_USB,
+0x7591f7c7, 0xe760, 0x434a, 0x92, 0xd3, 0xc1, 0x86, 0x99, 0x30, 0x42, 0x3c);
+
+#define FREEBT_IOCTL_INDEX 0x0000
+
+
+#define IOCTL_FREEBT_GET_CONFIG_DESCRIPTOR CTL_CODE(FILE_DEVICE_UNKNOWN, \
+ FREEBT_IOCTL_INDEX, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_FREEBT_HCI_SEND_CMD CTL_CODE(FILE_DEVICE_UNKNOWN, \
+ FREEBT_IOCTL_INDEX + 1, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_FREEBT_HCI_GET_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN, \
+ FREEBT_IOCTL_INDEX + 2, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#endif
+
--- /dev/null
+#include "fbtXcpt.h"
+#include "fbtLog.h"
+#include "fbtReg.h"
\ No newline at end of file
--- /dev/null
+// Copyright (c) 2004, Antony C. Roberts
+
+// Use of this file is subject to the terms
+// described in the LICENSE.TXT file that
+// accompanies this file.
+//
+// Your use of this file indicates your
+// acceptance of the terms described in
+// LICENSE.TXT.
+//
+// http://www.freebt.net
+
+#ifndef _FREEBT_WMI_H
+#define _FREEBT_WMI_H
+
+//#define ENABLE_WMI
+
+NTSTATUS FreeBT_WmiRegistration(IN OUT PDEVICE_EXTENSION DeviceExtension);
+NTSTATUS FreeBT_WmiDeRegistration(IN OUT PDEVICE_EXTENSION DeviceExtension);
+NTSTATUS FreeBT_DispatchSysCtrl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+NTSTATUS FreeBT_QueryWmiRegInfo(
+ IN PDEVICE_OBJECT DeviceObject,
+ OUT ULONG *RegFlags,
+ OUT PUNICODE_STRING InstanceName,
+ OUT PUNICODE_STRING *RegistryPath,
+ OUT PUNICODE_STRING MofResourceName,
+ OUT PDEVICE_OBJECT *Pdo);
+
+NTSTATUS FreeBT_SetWmiDataItem(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN ULONG GuidIndex,
+ IN ULONG InstanceIndex,
+ IN ULONG DataItemId,
+ IN ULONG BufferSize,
+ IN PUCHAR Buffer);
+
+NTSTATUS FreeBT_SetWmiDataBlock(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN ULONG GuidIndex,
+ IN ULONG InstanceIndex,
+ IN ULONG BufferSize,
+ IN PUCHAR Buffer);
+
+NTSTATUS FreeBT_QueryWmiDataBlock(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN ULONG GuidIndex,
+ IN ULONG InstanceIndex,
+ IN ULONG InstanceCount,
+ IN OUT PULONG InstanceLengthArray,
+ IN ULONG OutBufferSize,
+ OUT PUCHAR Buffer);
+
+PCHAR WMIMinorFunctionString(UCHAR MinorFunction);
+
+#endif
--- /dev/null
+#ifndef _FBT_EXCEPT_H
+
+#include "fbtLog.h"
+
+#ifdef __cplusplus
+
+#include "fbtSeXcpt.h"
+
+#define FBT_TRY try {
+#define FBT_CATCH } catch (fbtSeException *e) { fbtLog(fbtLog_Failure, "Exception %08X caught at line %u in file %s", e->GetSeCode(), __LINE__, __FILE__); fbtLog(fbtLog_Exception, "Exception %08X caught at line %u in file %s", e->GetSeCode(), __LINE__, __FILE__);
+#define FBT_CATCH_RETURN(RETVAL) FBT_CATCH return RETVAL;}
+#define FBT_CATCH_NORETURN FBT_CATCH return;}
+
+#else
+
+#define FBT_TRY __try{
+#define FBT_CATCH } __except(EXCEPTION_EXECUTE_HANDLER) { fbtLog(fbtLog_Failure, "Exception %08X caught at line %u in file %s (%s)", GetExceptionCode(), __LINE__, __FILE__, GetCommandLine()); fbtLog(fbtLog_Exception, "Exception %08X caught at line %u in file %s (%s)", GetExceptionCode(), __LINE__, __FILE__, GetCommandLine());
+#define FBT_CATCH_RETURN(RETVAL) FBT_CATCH return RETVAL;}
+#define FBT_CATCH_NORETURN FBT_CATCH return;}
+#define FBT_CATCH_NODEBUG_RETURN(x) } __except(EXCEPTION_EXECUTE_HANDLER) { return x;}
+
+#endif // __cplusplus
+
+#endif _FBT_EXCEPT_H
<directory name="battery">
<xi:include href="battery/directory.rbuild" />
</directory>
+<directory name="bluetooth">
+ <xi:include href="bluetooth/directory.rbuild" />
+</directory>
<directory name="bus">
<xi:include href="bus/directory.rbuild" />
</directory>
<directory name="nt4compat">
<xi:include href="nt4compat/directory.rbuild" />
</directory>
- <!--directory name="usbd">
+ <directory name="usbd">
<xi:include href="usbd/usbd.rbuild" />
</directory>
- <directory name="usbhub">
+ <!--directory name="usbhub">
<xi:include href="usbhub/usbhub.rbuild" />
</directory>
<directory name="usbstor">