⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xbcd_driver.c

📁 xbox game joystick driver.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	
    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 + -