VBoxUsbDev.cpp revision 97b634ea021fd984782256de4ba4ff31cdb96c47
/* $Id$ */
/** @file
* VBoxUsbDev.cpp - USB device.
*/
/*
* Copyright (C) 2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include "VBoxUsbCmn.h"
#include <iprt/assert.h>
#include <VBox/log.h>
#define VBOXUSB_MEMTAG 'bUBV'
DECLHIDDEN(PVOID) vboxUsbMemAlloc(SIZE_T cbBytes)
{
PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXUSB_MEMTAG);
Assert(pvMem);
return pvMem;
}
DECLHIDDEN(PVOID) vboxUsbMemAllocZ(SIZE_T cbBytes)
{
PVOID pvMem = vboxUsbMemAlloc(cbBytes);
if (pvMem)
{
RtlZeroMemory(pvMem, cbBytes);
}
return pvMem;
}
DECLHIDDEN(VOID) vboxUsbMemFree(PVOID pvMem)
{
ExFreePoolWithTag(pvMem, VBOXUSB_MEMTAG);
}
VBOXUSB_GLOBALS g_VBoxUsbGlobals = {0};
static NTSTATUS vboxUsbDdiAddDevice(PDRIVER_OBJECT pDriverObject,
PDEVICE_OBJECT pPDO)
{
PDEVICE_OBJECT pFDO = NULL;
NTSTATUS Status = IoCreateDevice(pDriverObject,
sizeof (VBOXUSBDEV_EXT),
NULL, /* IN PUNICODE_STRING pDeviceName OPTIONAL */
FILE_DEVICE_UNKNOWN, /* IN DEVICE_TYPE DeviceType */
FILE_AUTOGENERATED_DEVICE_NAME, /* IN ULONG DeviceCharacteristics */
FALSE, /* IN BOOLEAN fExclusive */
&pFDO);
Assert(Status == STATUS_SUCCESS);
if (Status == STATUS_SUCCESS)
{
PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pFDO->DeviceExtension;
/* init Device Object bits */
pFDO->Flags |= DO_DIRECT_IO;
if (pPDO->Flags & DO_POWER_PAGABLE)
pFDO->Flags |= DO_POWER_PAGABLE;
/* now init our state bits */
pDevExt->cHandles = 0;
pDevExt->pFDO = pFDO;
pDevExt->pPDO = pPDO;
pDevExt->pLowerDO = IoAttachDeviceToDeviceStack(pFDO, pPDO);
Assert(pDevExt->pLowerDO);
if (pDevExt->pLowerDO)
{
vboxUsbDdiStateInit(pDevExt);
Status = vboxUsbRtInit(pDevExt);
if (Status == STATUS_SUCCESS)
{
/* we're done! */
pFDO->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
IoDetachDevice(pDevExt->pLowerDO);
}
else
Status = STATUS_NO_SUCH_DEVICE;
IoDeleteDevice(pFDO);
}
return Status;
}
static VOID vboxUsbDdiUnload(PDRIVER_OBJECT pDriverObject)
{
LogRel(("VBoxUsb::DriverUnload. Built Date (%s) Time (%s)\n", __DATE__, __TIME__));
VBoxDrvToolStrFree(&g_VBoxUsbGlobals.RegPath);
vboxUsbRtGlobalsTerm();
PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL);
if (pLogger)
{
RTLogDestroy(pLogger);
}
pLogger = RTLogSetDefaultInstance(NULL);
if (pLogger)
{
RTLogDestroy(pLogger);
}
}
static NTSTATUS vboxUsbDispatchCreate(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension;
NTSTATUS Status = STATUS_INVALID_HANDLE;
do
{
if (vboxUsbPnPStateGet(pDevExt) != ENMVBOXUSB_PNPSTATE_STARTED)
{
Status = STATUS_INVALID_DEVICE_STATE;
break;
}
PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
PFILE_OBJECT pFObj = pSl->FileObject;
if (!pFObj)
{
Status = STATUS_INVALID_PARAMETER;
break;
}
pFObj->FsContext = NULL;
if (pFObj->FileName.Length)
{
Status = STATUS_INVALID_PARAMETER;
break;
}
Status = vboxUsbRtCreate(pDevExt, pIrp);
if (!NT_SUCCESS(Status))
{
AssertFailed();
break;
}
ASMAtomicIncU32(&pDevExt->cHandles);
Status = STATUS_SUCCESS;
break;
} while (0);
Status = VBoxDrvToolIoComplete(pIrp, Status, 0);
return Status;
}
static NTSTATUS vboxUsbDispatchClose(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension;
PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
PFILE_OBJECT pFObj = pSl->FileObject;
NTSTATUS Status = STATUS_SUCCESS;
Assert(pFObj);
Assert(!pFObj->FileName.Length);
Status = vboxUsbRtClose(pDevExt, pIrp);
if (NT_SUCCESS(Status))
{
ASMAtomicDecU32(&pDevExt->cHandles);
}
else
{
AssertFailed();
}
Status = VBoxDrvToolIoComplete(pIrp, Status, 0);
return Status;
}
static NTSTATUS vboxUsbDispatchDeviceControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension;
NTSTATUS Status = STATUS_INVALID_HANDLE;
if (vboxUsbDdiStateRetainIfStarted(pDevExt))
{
return vboxUsbRtDispatch(pDevExt, pIrp);
}
else
{
Status = STATUS_INVALID_DEVICE_STATE;
}
Status = VBoxDrvToolIoComplete(pIrp, Status, 0);
return Status;
}
static NTSTATUS vboxUsbDispatchCleanup(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension;
NTSTATUS Status = STATUS_SUCCESS;
Status = VBoxDrvToolIoComplete(pIrp, Status, 0);
return Status;
}
static NTSTATUS vboxUsbDevAccessDeviedDispatchStub(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension;
if (!vboxUsbDdiStateRetainIfNotRemoved(pDevExt))
{
VBoxDrvToolIoComplete(pIrp, STATUS_DELETE_PENDING, 0);
return STATUS_DELETE_PENDING;
}
NTSTATUS Status = STATUS_ACCESS_DENIED;
Status = VBoxDrvToolIoComplete(pIrp, Status, 0);
vboxUsbDdiStateRelease(pDevExt);
return Status;
}
static NTSTATUS vboxUsbDispatchSystemControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension;
if (!vboxUsbDdiStateRetainIfNotRemoved(pDevExt))
{
VBoxDrvToolIoComplete(pIrp, STATUS_DELETE_PENDING, 0);
return STATUS_DELETE_PENDING;
}
IoSkipCurrentIrpStackLocation(pIrp);
NTSTATUS Status = IoCallDriver(pDevExt->pLowerDO, pIrp);
vboxUsbDdiStateRelease(pDevExt);
return Status;
}
static NTSTATUS vboxUsbDispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
#ifdef DEBUG_misha
AssertFailed();
#endif
return vboxUsbDevAccessDeviedDispatchStub(pDeviceObject, pIrp);
}
static NTSTATUS vboxUsbDispatchWrite(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
#ifdef DEBUG_misha
AssertFailed();
#endif
return vboxUsbDevAccessDeviedDispatchStub(pDeviceObject, pIrp);
}
RT_C_DECLS_BEGIN
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath);
RT_C_DECLS_END
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
{
LogRel(("VBoxUsb::DriverEntry. Built Date (%s) Time (%s)\n", __DATE__, __TIME__));
NTSTATUS Status = vboxUsbRtGlobalsInit();
Assert(Status == STATUS_SUCCESS);
if (Status == STATUS_SUCCESS)
{
Status = VBoxDrvToolStrCopy(&g_VBoxUsbGlobals.RegPath, pRegistryPath);
Assert(Status == STATUS_SUCCESS);
if (Status == STATUS_SUCCESS)
{
g_VBoxUsbGlobals.pDrvObj = pDriverObject;
pDriverObject->DriverExtension->AddDevice = vboxUsbDdiAddDevice;
pDriverObject->DriverUnload = vboxUsbDdiUnload;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = vboxUsbDispatchCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = vboxUsbDispatchClose;
pDriverObject->MajorFunction[IRP_MJ_READ] = vboxUsbDispatchRead;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = vboxUsbDispatchWrite;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = vboxUsbDispatchDeviceControl;
pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = vboxUsbDispatchCleanup;
pDriverObject->MajorFunction[IRP_MJ_POWER] = vboxUsbDispatchPower;
pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = vboxUsbDispatchSystemControl;
pDriverObject->MajorFunction[IRP_MJ_PNP] = vboxUsbDispatchPnP;
return STATUS_SUCCESS;
}
vboxUsbRtGlobalsTerm();
}
LogRel(("VBoxUsb::DriverEntry. failed with Status (0x%x)\n", Status));
return Status;
}
#ifdef DEBUG
DECLHIDDEN(VOID) vboxUsbPnPStateGbgChange(ENMVBOXUSB_PNPSTATE enmOldState, ENMVBOXUSB_PNPSTATE enmNewState)
{
/* *ensure the state change is valid */
switch (enmNewState)
{
case ENMVBOXUSB_PNPSTATE_STARTED:
Assert(enmOldState == ENMVBOXUSB_PNPSTATE_START_PENDING
|| ENMVBOXUSB_PNPSTATE_REMOVE_PENDING
|| ENMVBOXUSB_PNPSTATE_STOPPED
|| ENMVBOXUSB_PNPSTATE_STOP_PENDING);
break;
case ENMVBOXUSB_PNPSTATE_STOP_PENDING:
Assert(enmOldState == ENMVBOXUSB_PNPSTATE_STARTED);
break;
case ENMVBOXUSB_PNPSTATE_STOPPED:
Assert(enmOldState == ENMVBOXUSB_PNPSTATE_STOP_PENDING);
break;
case ENMVBOXUSB_PNPSTATE_SURPRISE_REMOVED:
Assert(enmOldState == ENMVBOXUSB_PNPSTATE_STARTED);
break;
case ENMVBOXUSB_PNPSTATE_REMOVE_PENDING:
Assert(enmOldState == ENMVBOXUSB_PNPSTATE_STARTED);
break;
case ENMVBOXUSB_PNPSTATE_REMOVED:
Assert(enmOldState == ENMVBOXUSB_PNPSTATE_REMOVE_PENDING
|| enmOldState == ENMVBOXUSB_PNPSTATE_SURPRISE_REMOVED);
break;
default:
AssertBreakpoint();
break;
}
}
#endif