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

📄 usb2com.adddev.cpp

📁 这是一个关于USB转接串口的驱动程序开发
💻 CPP
字号:
//********************************************************************
//	created:	11:7:2008   21:33
//	file:		usb2com.adddev.cpp
//	author:		tiamo
//	purpose:	add device
//********************************************************************

#include "stdafx.h"

//
// we need to instantiate the GUID,see ntddser.h for detail
//
#include <initguid.h>
#include <ntddser.h>

#pragma alloc_text(PAGED,Usb2ComAddDevice)

//
// add device
//
NTSTATUS Usb2ComAddDevice(__in PDRIVER_OBJECT DriverObject,__in PDEVICE_OBJECT Pdo)
{
	PAGED_CODE();

	NTSTATUS Status										= STATUS_OBJECT_NAME_EXISTS;
	PDEVICE_OBJECT Fdo									= 0;
	UNICODE_STRING DeviceName;

	__try
	{
		//
		// alloc device name buffer
		//
		DeviceName.MaximumLength						= static_cast<USHORT>(sizeof(L"\\Device\\Serial0"));
		DeviceName.Length								= static_cast<USHORT>(DeviceName.MaximumLength - sizeof(WCHAR));
		DeviceName.Buffer								= static_cast<PWCH>(ExAllocatePoolWithTag(PagedPool,DeviceName.MaximumLength,'Name'));
		if(!DeviceName.Buffer)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		RtlCopyMemory(DeviceName.Buffer,L"\\Device\\Serial0",DeviceName.MaximumLength);

		//
		// always skip COM1 and COM2
		//
		ULONG DeviceNumber								= 3;
		ULONG DevNumIndex								= DeviceName.Length / sizeof(WCHAR) - 1;
		
		//
		// loop until we got a device object
		//
		while(!Fdo && DeviceNumber < 10)
		{
			//
			// build device name,DeviceNumber will always contain only one digit,because we limited it to be less than 10
			//
			DeviceName.Buffer[DevNumIndex]				= static_cast<WCHAR>(DeviceNumber + L'0');

			//
			// try to create the device object,this call may fail because the device with the name already exists,
			// if failed,we simply try another device name
			//
			Status										= IoCreateDevice(DriverObject,sizeof(USB2COM_DEVICE_EXTENSION),&DeviceName,FILE_DEVICE_SERIAL_PORT,0,TRUE,&Fdo);
			if(NT_SUCCESS(Status))
				break;

			//
			// try next device number,check the return value first?
			//
			DeviceNumber								+= 1;
		}

		//
		// we can't create a fdo,Status has already been set correctly.
		//
		if(!Fdo)
			try_leave(NOTHING);

		//
		// actually there is no need to zero it out,but well, for safe
		//
		PUSB2COM_DEVICE_EXTENSION DevExt				= static_cast<PUSB2COM_DEVICE_EXTENSION>(Fdo->DeviceExtension);
		RtlZeroMemory(DevExt,sizeof(USB2COM_DEVICE_EXTENSION));

		//
		// allocate dos device name buffer
		//
		DevExt->DosDeviceName.MaximumLength				= 0x100;
		DevExt->DosDeviceName.Buffer					= static_cast<PWCH>(ExAllocatePoolWithTag(PagedPool,DevExt->DosDeviceName.MaximumLength,'Name'));
		if(!DevExt->DosDeviceName.Buffer)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		RtlZeroMemory(DevExt->DosDeviceName.Buffer,DevExt->DosDeviceName.MaximumLength);
		RtlCopyMemory(DevExt->DosDeviceName.Buffer,L"\\DosDevices\\COM0",sizeof(L"\\DosDevices\\COM0"));

		//
		// read port name from reg
		//
		Status											= Usb2ComReadPortName(&DevExt->DosDeviceName,Pdo);
		if(!NT_SUCCESS(Status))
			try_leave(NOTHING);

		//
		// create dos device name
		//
		Status											= IoCreateSymbolicLink(&DevExt->DosDeviceName,&DeviceName);
		if(!NT_SUCCESS(Status))
			try_leave(NOTHING);

		//
		// write name map into registry
		//
		RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,L"SERIALCOMM",DeviceName.Buffer,REG_SZ,DevExt->DosDeviceName.Buffer,DevExt->DosDeviceName.MaximumLength);

		//
		// attach ourself to device stack
		//
		DevExt->LowerDeviceObject						= IoAttachDeviceToDeviceStack(Fdo,Pdo);
		if(!DevExt->LowerDeviceObject)
			try_leave(Status = STATUS_UNSUCCESSFUL);

		//
		// register device interface
		//
		Status											= IoRegisterDeviceInterface(Pdo,&GUID_CLASS_COMPORT,0,&DevExt->SymbolicLinkName);
		if(!NT_SUCCESS(Status))
			try_leave(NOTHING);

		//
		// allocate bulk in irp,urb,buffer
		//
		DevExt->BulkInBuffer							= ExAllocatePoolWithTag(NonPagedPool,0x40,'uBIb');
		if(!DevExt->BulkInBuffer)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		DevExt->BulkInUrb								= static_cast<PURB>(ExAllocatePoolWithTag(NonPagedPool,sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),'uBIu'));
		if(!DevExt->BulkInUrb)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		DevExt->BulkInIrp								= IoAllocateIrp(DevExt->LowerDeviceObject->StackSize,FALSE);
		if(!DevExt->BulkInIrp)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		KeInitializeEvent(&DevExt->BulkInUrbStopEvent,NotificationEvent,TRUE);

		//
		// allocate bulk out irp,urb,buffer
		//
		DevExt->BulkOutBuffer							= ExAllocatePoolWithTag(NonPagedPool,0x40,'uBOb');
		if(!DevExt->BulkOutBuffer)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		DevExt->BulkOutUrb								= static_cast<PURB>(ExAllocatePoolWithTag(NonPagedPool,sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),'uBOu'));
		if(!DevExt->BulkOutUrb)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		DevExt->BulkOutIrp								= IoAllocateIrp(DevExt->LowerDeviceObject->StackSize,FALSE);
		if(!DevExt->BulkOutIrp)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		KeInitializeEvent(&DevExt->BulkOutUrbStopEvent,NotificationEvent,TRUE);

		//
		// allocate interrupt irp,urb,buffer
		//
		DevExt->InterruptBuffer							= ExAllocatePoolWithTag(NonPagedPool,0x04,'uIb ');
		if(!DevExt->InterruptBuffer)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		DevExt->InterruptUrb							= static_cast<PURB>(ExAllocatePoolWithTag(NonPagedPool,sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),'uIu '));
		if(!DevExt->InterruptUrb)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		DevExt->InterruptIrp							= IoAllocateIrp(DevExt->LowerDeviceObject->StackSize,FALSE);
		if(!DevExt->InterruptIrp)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		KeInitializeEvent(&DevExt->InterruptUrbStopEvent,NotificationEvent,TRUE);

		//
		// allocate read buffer
		//
		DevExt->ReadBuffer								= static_cast<PUCHAR>(ExAllocatePoolWithTag(NonPagedPool,0x2000,'RDBF'));
		if(!DevExt->ReadBuffer)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		KeInitializeSpinLock(&DevExt->ReadLock);
		KeInitializeSpinLock(&DevExt->WriteLock);
		KeInitializeSpinLock(&DevExt->InterruptLock);
		InitializeListHead(&DevExt->ReadQueueListHead);
		InitializeListHead(&DevExt->WriteQueueListHead);

		//
		// setup the device extension
		//
		DevExt->DeviceName								= DeviceName;
		DevExt->DeviceNumber							= DeviceNumber;
		DevExt->FunctionDeviceObject					= Fdo;
		DevExt->PhysicalDeviceObject					= Pdo;
		DevExt->Signature								= 'U2C ';

		//
		// we only support buffered io
		//
		Fdo->Flags										|= (DO_BUFFERED_IO | DO_POWER_PAGABLE);
		Fdo->Flags										&= ~DO_DEVICE_INITIALIZING;

		//
		// initialize remove lock
		//
		IoInitializeRemoveLock(&DevExt->RemoveLock,DevExt->Signature,0,0);
	}
	__finally
	{
		if(!NT_SUCCESS(Status) || AbnormalTermination())
		{
			if(DeviceName.Buffer)
				ExFreePool(DeviceName.Buffer);

			if(Fdo)
				Usb2ComCleanupFunctionDeviceObject(Fdo);
		}
	}

	return Status;
}

//
// cleanup fdo
//
VOID Usb2ComCleanupFunctionDeviceObject(__in PDEVICE_OBJECT Fdo)
{
	PUSB2COM_DEVICE_EXTENSION DeviceExtension			= static_cast<PUSB2COM_DEVICE_EXTENSION>(Fdo->DeviceExtension);

	//
	// deattach from the device stack
	//
	if(DeviceExtension->LowerDeviceObject)
		IoDetachDevice(DeviceExtension->LowerDeviceObject);

	//
	// delete dos device symbolic link
	//
	if(DeviceExtension->DosDeviceName.Buffer)
		IoDeleteSymbolicLink(&DeviceExtension->DosDeviceName);

	//
	// free device name
	//
	if(DeviceExtension->DeviceName.Buffer)
	{
		RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP,L"SERIALCOMM",DeviceExtension->DeviceName.Buffer);
		ExFreePool(DeviceExtension->DeviceName.Buffer);
	}

	//
	// free dos device name
	//
	if(DeviceExtension->DosDeviceName.Buffer)
		ExFreePool(DeviceExtension->DosDeviceName.Buffer);

	//
	// delete device interface symbolic link name
	//
	if(DeviceExtension->SymbolicLinkName.Buffer)
		RtlFreeUnicodeString(&DeviceExtension->SymbolicLinkName);

	//
	// free bulk in urb,irp,buffer
	//
	if(DeviceExtension->BulkInIrp)
		IoFreeIrp(DeviceExtension->BulkInIrp);

	if(DeviceExtension->BulkInBuffer)
		ExFreePool(DeviceExtension->BulkInBuffer);

	if(DeviceExtension->BulkInUrb)
		ExFreePool(DeviceExtension->BulkInUrb);

	//
	// free bulk out urb,irp,buffer
	//
	if(DeviceExtension->BulkOutIrp)
		IoFreeIrp(DeviceExtension->BulkOutIrp);

	if(DeviceExtension->BulkOutBuffer)
		ExFreePool(DeviceExtension->BulkOutBuffer);

	if(DeviceExtension->BulkOutUrb)
		ExFreePool(DeviceExtension->BulkOutUrb);

	//
	// free interrupt urb,irp,buffer
	//
	if(DeviceExtension->InterruptIrp)
		IoFreeIrp(DeviceExtension->InterruptIrp);

	if(DeviceExtension->InterruptBuffer)
		ExFreePool(DeviceExtension->InterruptBuffer);

	if(DeviceExtension->InterruptUrb)
		ExFreePool(DeviceExtension->InterruptUrb);

	//
	// free read buffer
	//
	if(DeviceExtension->ReadBuffer)
		ExFreePool(DeviceExtension->ReadBuffer);

	//
	// delete device
	//
	IoDeleteDevice(Fdo);
}

//
// read port name
//
NTSTATUS Usb2ComReadPortName(__in __out PUNICODE_STRING DosDeviceName,__in PDEVICE_OBJECT Pdo)
{
	NTSTATUS Status										= STATUS_SUCCESS;
	HANDLE RegKey										= 0;
	PKEY_VALUE_FULL_INFORMATION FullInfo				= 0;
	UNICODE_STRING KeyName;

	__try
	{
		Status											= IoOpenDeviceRegistryKey(Pdo,PLUGPLAY_REGKEY_DEVICE,STANDARD_RIGHTS_READ,&RegKey);
		if(!NT_SUCCESS(Status))
			try_leave(NOTHING);

		PWCHAR PortName									= DosDeviceName->Buffer + sizeof(L"\\DosDevices\\") / sizeof(WCHAR) - 1;
		ULONG PortNameLength							= DosDeviceName->MaximumLength - sizeof(L"\\DosDevices\\") - sizeof(WCHAR) - sizeof(WCHAR);

		RtlInitUnicodeString(&KeyName,L"PortName");

		ULONG Length									= sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(L"PortName") + PortNameLength;
		FullInfo										= static_cast<PKEY_VALUE_FULL_INFORMATION>(ExAllocatePoolWithTag(PagedPool,Length,'REG '));
		if(!FullInfo)
			try_leave(Status = STATUS_INSUFFICIENT_RESOURCES);

		Status											= ZwQueryValueKey(RegKey,&KeyName,KeyValueFullInformation,FullInfo,Length,&Length);

		if(NT_SUCCESS(Status) && PortNameLength >= FullInfo->DataLength)	
		{
			RtlCopyMemory(PortName,static_cast<PUCHAR>(static_cast<PVOID>(FullInfo)) + FullInfo->DataOffset,FullInfo->DataLength);

			DosDeviceName->Length						= static_cast<USHORT>(sizeof(L"\\DosDevices\\") - sizeof(WCHAR) + FullInfo->DataLength - sizeof(WCHAR));
		}
	}
	__finally
	{
		if(RegKey)
			ZwClose(RegKey);

		if(FullInfo)
			ExFreePool(FullInfo);
	}

	return Status;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -