📄 xbcd_driver.c
字号:
/*
Copyright 2003 Helder Acevedo
This file is part of XBCD.
XBCD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
XBCD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "XBCD_driver.h"
#pragma PAGEDCODE
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
HID_MINIDRIVER_REGISTRATION hidMinidriverRegistration;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = XBCDCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = XBCDClose;
pDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = XBCDDispatchIntDevice;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = XBCDDispatchDevice;
pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = XBCDDispatchSystem;
pDriverObject->MajorFunction[IRP_MJ_POWER] = XBCDDispatchPower;
pDriverObject->MajorFunction[IRP_MJ_PNP] = XBCDDispatchPnp;
pDriverObject->DriverUnload = XBCDUnload;
pDriverObject->DriverExtension->AddDevice = XBCDAddDevice;
RtlZeroMemory(&hidMinidriverRegistration, sizeof(HID_MINIDRIVER_REGISTRATION));
hidMinidriverRegistration.Revision = HID_REVISION;
hidMinidriverRegistration.DriverObject = pDriverObject;
hidMinidriverRegistration.RegistryPath = pRegistryPath;
hidMinidriverRegistration.DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
hidMinidriverRegistration.DevicesArePolled = TRUE;
status = HidRegisterMinidriver(&hidMinidriverRegistration);
if (NT_SUCCESS(status))
{
KdPrint(("Minidriver Registration Worked"));
RegistryPath.Buffer = (PWSTR) ExAllocatePool(PagedPool, pRegistryPath->Length + sizeof(WCHAR));
RegistryPath.MaximumLength = pRegistryPath->Length + sizeof(WCHAR);
RtlCopyUnicodeString(&RegistryPath, pRegistryPath);
RegistryPath.Buffer[pRegistryPath->Length/sizeof(WCHAR)] = 0;
KdPrint(("%ws", RegistryPath.Buffer));
}
else
{
KdPrint(("Minidriver Registration Failed"));
}
return status;
}
NTSTATUS XBCDCreate(IN PDEVICE_OBJECT pFdo, IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
KdPrint(("XBCDCreate"));
return status;
}
NTSTATUS XBCDClose(IN PDEVICE_OBJECT pFdo, IN PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
KdPrint(("XBCDClose"));
return STATUS_SUCCESS;
}
#pragma PAGEDCODE
NTSTATUS XBCDAddDevice(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pPdo)
{
NTSTATUS status = STATUS_SUCCESS;
NTSTATUS ntstatus;
PDEVICE_OBJECT pFdo = pPdo;
PDEVICE_EXTENSION pDevExt = GET_MINIDRIVER_DEVICE_EXTENSION(pFdo);
PAGED_CODE();
pDevExt->pPdo = pPdo;
KeInitializeSpinLock(&pDevExt->polllock);
//KeInitializeSpinLock(&pDevExt->readlock);
InitializeRemoveLock(&pDevExt->RemoveLock,'XBCD',0,0);
// Set power management flags in the device object
pFdo->Flags |= DO_POWER_PAGABLE | DO_DIRECT_IO;
pDevExt->pLowerPdo = GET_LOWER_DEVICE_OBJECT(pFdo);
if(!NT_SUCCESS(CreateInterruptUrb(pFdo)))
{
KdPrint(("XBCDAddDevice - Could not create interrupt urb"));
}
// Clear the "initializing" flag so that we can get IRPs
pFdo->Flags &= ~DO_DEVICE_INITIALIZING;
KdPrint(("XBCDAddDevice"));
return status;
}
#pragma PAGEDCODE
VOID XBCDUnload(IN PDRIVER_OBJECT pDriverObject)
{
KdPrint(("XBCDUnload"));
if (RegistryPath.Buffer != NULL)
{
RtlFreeUnicodeString(&RegistryPath);
}
return;
}
#pragma PAGEDCODE
NTSTATUS XBCDDispatchPnp(IN PDEVICE_OBJECT pFdo, IN PIRP pIrp)
{
PDEVICE_EXTENSION pDevExt = GET_MINIDRIVER_DEVICE_EXTENSION(pFdo);
PIO_STACK_LOCATION stack;
NTSTATUS status = STATUS_SUCCESS;
KEVENT event;
PAGED_CODE();
status = AcquireRemoveLock(&pDevExt->RemoveLock, pIrp);
if (!NT_SUCCESS(status))
{
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
status = XBCDIncRequestCount(pDevExt);
if (!NT_SUCCESS(status))
{
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
stack = IoGetCurrentIrpStackLocation(pIrp);
switch (stack->MinorFunction)
{
case IRP_MN_START_DEVICE:
{
KdPrint(("XBCDDispatchPnp - IRP_MN_START_DEVICE entry"));
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp, XBCDPnPComplete, &event, TRUE, TRUE, TRUE);
status = IoCallDriver(pDevExt->pLowerPdo, pIrp);
if (status == STATUS_PENDING)
{
status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
}
if(NT_SUCCESS(status))
{
status = XBCDStartDevice(pFdo, pIrp);
}
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
ReleaseRemoveLock(&pDevExt->RemoveLock, pIrp);
KdPrint(("XBCDDispatchPnp - IRP_MN_START_DEVICE exit"));
break;
}
case IRP_MN_REMOVE_DEVICE:
{
KdPrint(("XBCDDispatchPnp - IRP_MN_REMOVE_DEVICE entry"));
pDevExt->DeviceRemoved = TRUE;
IoCancelIrp(pDevExt->pIrp);
if (!pDevExt->SurpriseRemoved)
{
ReleaseRemoveLockAndWait(&pDevExt->RemoveLock, pIrp);
KdPrint(("XBCDDispatchPnp - Stop device"));
XBCDStopDevice(pFdo, pIrp);
}
KdPrint(("XBCDDispatchPnp - release and wait removelock"));
KdPrint(("XBCDDispatchPnp - Call removedevice"));
XBCDRemoveDevice(pFdo, pIrp);
pIrp->IoStatus.Status = STATUS_SUCCESS;
KdPrint(("XBCDDispatchPnp - Pass irp down"));
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pDevExt->pLowerPdo, pIrp);
if (InterlockedDecrement(&pDevExt->RequestCount) > 0)
{
KeWaitForSingleObject(&pDevExt->RemoveEvent, Executive, KernelMode, FALSE, NULL );
}
status = STATUS_SUCCESS;
KdPrint(("XBCDDispatchPnp - IRP_MN_REMOVE_DEVICE exit"));
return status;
}
case IRP_MN_STOP_DEVICE:
{
KdPrint(("XBCDDispatchPnp - IRP_MN_STOP_DEVICE"));
IoCancelIrp(pDevExt->pIrp);
ReleaseRemoveLockAndWait(&pDevExt->RemoveLock, pIrp);
XBCDStopDevice(pFdo, pIrp);
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pDevExt->pLowerPdo, pIrp);
break;
}
case IRP_MN_QUERY_CAPABILITIES:
{
KdPrint(("XBCDDispatchPnp - IRP_MN_QUERY_CAPABILITIES"));
stack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
stack->Parameters.DeviceCapabilities.Capabilities->EjectSupported = FALSE;
stack->Parameters.DeviceCapabilities.Capabilities->Removable = TRUE;
stack->Parameters.DeviceCapabilities.Capabilities->DockDevice = FALSE;
stack->Parameters.DeviceCapabilities.Capabilities->LockSupported = FALSE;
stack->Parameters.DeviceCapabilities.Capabilities->D1Latency = 0;
stack->Parameters.DeviceCapabilities.Capabilities->D2Latency = 0;
stack->Parameters.DeviceCapabilities.Capabilities->D3Latency = 0;
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
ReleaseRemoveLock(&pDevExt->RemoveLock, pIrp);
break;
}
case IRP_MN_SURPRISE_REMOVAL:
{
KdPrint(("XBCDDispatchPnp - IRP_MN_SURPRISE_REMOVAL entry"));
pDevExt->SurpriseRemoved = TRUE;
IoCancelIrp(pDevExt->pIrp);
ReleaseRemoveLockAndWait(&pDevExt->RemoveLock, pIrp);
XBCDStopDevice(pFdo, pIrp);
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pDevExt->pLowerPdo, pIrp);
KdPrint(("XBCDDispatchPnp - IRP_MN_SURPRISE_REMOVAL exit"));
break;
}
default:
{
KdPrint(("XBCDDispatchPnp - Irp %d not supported", stack->MinorFunction));
IoSkipCurrentIrpStackLocation (pIrp);
status = IoCallDriver(pDevExt->pLowerPdo, pIrp);
ReleaseRemoveLock(&pDevExt->RemoveLock, pIrp);
break;
}
}
XBCDDecRequestCount(pDevExt);
return status;
}
#pragma PAGEDCODE
NTSTATUS XBCDPnPComplete(PDEVICE_OBJECT pFdo, PIRP pIrp, PVOID Context)
{
NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
PAGED_CODE();
UNREFERENCED_PARAMETER(pFdo);
KeSetEvent((PKEVENT) Context, 0, FALSE);
// If the lower driver returned PENDING, mark our stack location as
// pending also. This prevents the IRP's thread from being freed if
// the client's call returns pending.
if(pIrp->PendingReturned)
{
IoMarkIrpPending(pIrp);
}
return status;
}
#pragma LOCKEDCODE
NTSTATUS XBCDIncRequestCount(PDEVICE_EXTENSION pDevExt)
{
NTSTATUS Status;
InterlockedIncrement( &pDevExt->RequestCount );
ASSERT(pDevExt->RequestCount > 0);
if (pDevExt->DeviceRemoved)
{
// PnP has already told us to remove the device so fail and make
// sure that the event has been set.
if (0 == InterlockedDecrement(&pDevExt->RequestCount))
{
KeSetEvent(&pDevExt->RemoveEvent, IO_NO_INCREMENT, FALSE);
}
Status = STATUS_DELETE_PENDING;
}
else
{
Status = STATUS_SUCCESS;
}
return Status;
}
VOID XBCDDecRequestCount(PDEVICE_EXTENSION pDevExt)
{
LONG LocalCount;
LocalCount = InterlockedDecrement(&pDevExt->RequestCount);
ASSERT(pDevExt->RequestCount >= 0);
if (LocalCount == 0)
{
// PnP has already told us to remove the device so the PnP remove
// code should have set device as removed and should be waiting on
// the event.
if(pDevExt->DeviceRemoved)
{
KeSetEvent(&pDevExt->RemoveEvent, IO_NO_INCREMENT, FALSE);
}
}
return;
}
#pragma PAGEDCODE
NTSTATUS XBCDStartDevice(PDEVICE_OBJECT pFdo, PIRP pIrp)
{
NTSTATUS status;
PDEVICE_EXTENSION pDevExt = GET_MINIDRIVER_DEVICE_EXTENSION(pFdo);
ULONG size;
URB urb; // URB for use in this subroutine
USB_CONFIGURATION_DESCRIPTOR tcd;
PUSB_CONFIGURATION_DESCRIPTOR pcd;
PUSB_INTERFACE_DESCRIPTOR pid;
USBD_INTERFACE_LIST_ENTRY interfaces[2] = {{NULL, NULL},{NULL,NULL}};
PURB selurb;
PUSBD_INTERFACE_INFORMATION pii;
//PAGED_CODE();
// Read our device descriptor. The only real purpose to this would be to find out how many
// configurations there are so we can read their descriptors. There's only one configuration.
KdPrint(("XBCDStartDevice - getting device descriptor"));
UsbBuildGetDescriptorRequest(&urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_DEVICE_DESCRIPTOR_TYPE,
0, 0, &pDevExt->dd, NULL, sizeof(pDevExt->dd), NULL);
status = SendAwaitUrb(pFdo, &urb);
if (!NT_SUCCESS(status))
{
KdPrint(("XBCDStartDevice - Error %X trying to read device descriptor", status));
return status;
}
// Read the descriptor of the first configuration. This requires two steps. The first step
// reads the fixed-size configuration descriptor alone. The second step reads the
// configuration descriptor plus all imbedded interface and endpoint descriptors.
KdPrint(("XBCDStartDevice - getting configuration descriptor"));
UsbBuildGetDescriptorRequest(&urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE,
0, 0, &tcd, NULL, sizeof(tcd), NULL);
status = SendAwaitUrb(pFdo, &urb);
if (!NT_SUCCESS(status))
{
KdPrint(("XBCDStartDevice - Error %X trying to read configuration descriptor 1", status));
return status;
}
size = tcd.wTotalLength;
pcd = (PUSB_CONFIGURATION_DESCRIPTOR) ExAllocatePool(NonPagedPool, size);
if (!pcd)
{
KdPrint(("XBCDStartDevice - Unable to allocate %X bytes for configuration descriptor", size));
return STATUS_INSUFFICIENT_RESOURCES;
}
KdPrint(("XBCDStartDevice - Getting second part of configuration descriptor"));
UsbBuildGetDescriptorRequest(&urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE,
0, 0, pcd, NULL, size, NULL);
status = SendAwaitUrb(pFdo, &urb);
if (!NT_SUCCESS(status))
{
KdPrint(("XBCDStartDevice - Error %X trying to read configuration descriptor 1", status));
return status;
}
// Locate the descriptor for the one and only interface we expect to find
pid = USBD_ParseConfigurationDescriptorEx(pcd, pcd, -1, -1, -1, -1, -1);
// Create a URB to use in selecting a configuration.
interfaces[0].InterfaceDescriptor = pid;
interfaces[0].Interface = NULL;
interfaces[1].InterfaceDescriptor = NULL;
interfaces[1].Interface = NULL;
KdPrint(("XBCDStartDevice - selecting the configuration"));
selurb = USBD_CreateConfigurationRequestEx(pcd, interfaces);
if (!selurb)
{
KdPrint(("XBCDStartDevice - Unable to create configuration request"));
return STATUS_INSUFFICIENT_RESOURCES;
}
// Verify that the interface describes exactly the endpoints we expect
/*if (pid->bNumEndpoints != 3)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -