main.c
资源名称:虚拟串口驱动程序.rar [点击查看]
上传用户:zanmei2
上传日期:2010-03-06
资源大小:775k
文件大小:19k
源码类别:
通讯编程文档
开发平台:
C/C++
- /*++
- Copyright (c) 2005 Changzhi Zhou All Rights Reserved
- Module Name:
- main.c
- Abstract:
- This module is main module that deals with
- DriverEntry, AddDevice, Unload, handles to device name.
- SampleIoCrement and SampleIoDecrement.
- Environment:
- Kernel mode
- Revision History:
- Changzhi Zhou Dec 20 2004
- --*/
- #include <wdm.h>
- #include <ntddk.h>
- #include <initguid.h>
- #include "main.h"
- #include "..incwdmioctl.h"
- #include <wmistr.h>
- #include <wmilib.h>
- #ifdef ALLOC_PRAGMA
- #pragma alloc_text (INIT, DriverEntry)
- #pragma alloc_text (PAGE, AddDevice)
- #pragma alloc_text (PAGE, SamplePnpDispatch)
- #pragma alloc_text (PAGE, Unload)
- #endif
- NTSTATUS
- DriverEntry(
- IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath
- )
- /*++
- Routine Description:
- Installable driver initialization entry point.
- This entry point is called directly by the I/O system.
- Arguments:
- DriverObject - pointer to the driver object
- RegistryPath - pointer to a unicode string representing the path,
- to driver-specific key in the registry.
- Return Value:
- STATUS_SUCCESS if successful,
- STATUS_UNSUCCESSFUL otherwise.
- --*/
- {
- NTSTATUS status;
- UNREFERENCED_PARAMETER (RegistryPath);
- DbgPrint("------ VirtualSerial Build on %s %s -------n", __DATE__, __TIME__ );
- status = STATUS_SUCCESS;
- DriverObject->MajorFunction[IRP_MJ_PNP] = SamplePnpDispatch;
- DriverObject->MajorFunction[IRP_MJ_POWER] = SamplePowerDispatch;
- DriverObject->MajorFunction[IRP_MJ_CREATE] = SampleCreate;
- DriverObject->MajorFunction[IRP_MJ_CLOSE] = SampleClose;
- DriverObject->MajorFunction[IRP_MJ_CLEANUP ] = SampleCleanup;
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SampleIoControl;
- DriverObject->MajorFunction[IRP_MJ_WRITE] = SampleWrite;
- DriverObject->MajorFunction[IRP_MJ_READ] = SampleRead;
- DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ToasterSystemControl;
- DriverObject->DriverExtension->AddDevice = AddDevice;
- DriverObject->DriverUnload = Unload;
- return status;
- }
- NTSTATUS
- AddDevice(
- IN PDRIVER_OBJECT DriverObject,
- IN PDEVICE_OBJECT PhysicalDeviceObject
- )
- /*++
- Routine Description:
- The Plug & Play subsystem is handing us a brand new PDO, for which we
- (by means of INF registration) have been asked to provide a driver.
- We need to determine if we need to be in the driver stack for the device.
- Create a function device object to attach to the stack
- Initialize that device object
- Return status success.
- Remember: We can NOT actually send ANY non pnp IRPS to the given driver
- stack, UNTIL we have received an IRP_MN_START_DEVICE.
- Arguments:
- DeviceObject - pointer to a device object.
- PhysicalDeviceObject - pointer to a device object created by the
- underlying bus driver.
- Return Value:
- NT status code.
- --*/
- {
- NTSTATUS status = STATUS_SUCCESS;
- PDEVICE_OBJECT deviceObject = NULL;
- PDEVICE_EXTENSION deviceExtension;
- UNICODE_STRING deviceObjName;
- PAGED_CODE ();
- DbgPrint("------- AddDevice build on %s %s ---------n", __DATE__, __TIME__);
- if( FALSE == InitializeSerialDevName( &deviceObjName ) )
- return STATUS_INSUFFICIENT_RESOURCES;
- status = IoCreateDevice (DriverObject,
- sizeof (DEVICE_EXTENSION),
- &deviceObjName,
- FILE_DEVICE_SERIAL_PORT,
- FILE_DEVICE_SECURE_OPEN,
- FALSE,
- &deviceObject);
- if (!NT_SUCCESS (status)) {
- DebugPrint(("IoCreateDevice failedn"));
- if ( deviceObjName.Buffer != NULL )
- ExFreePool ( deviceObjName.Buffer );
- return status;
- }
- DebugPrint (("AddDevice PDO (0x%x) FDO (0x%x)n", PhysicalDeviceObject, deviceObject));
- deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
- deviceExtension->DeviceName.MaximumLength = deviceObjName.MaximumLength;
- deviceExtension->DeviceName.Length = deviceObjName.Length;
- deviceExtension->DeviceName.Buffer = deviceObjName.Buffer;
- deviceExtension->CreatedSerialCommEntry = FALSE;
- deviceExtension->CreatedSymbolicLink = FALSE;
- // for working thread
- KeInitializeSpinLock( &deviceExtension->ThreadSpinLock );
- deviceExtension->NextLowerDriver = IoAttachDeviceToDeviceStack (
- deviceObject,
- PhysicalDeviceObject);
- if(NULL == deviceExtension->NextLowerDriver) {
- IoDeleteDevice(deviceObject);
- return STATUS_UNSUCCESSFUL;
- }
- DebugPrint(("AddDevice: %x to %x->%x n", deviceObject,
- deviceExtension->NextLowerDriver,
- PhysicalDeviceObject));
- // 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);
- deviceExtension->OutStandingIO = 1;
- deviceExtension->bIsOpen = FALSE;
- KeInitializeSpinLock( &deviceExtension->IOCountLock );
- if ( PhysicalDeviceObject->Flags & DO_POWER_PAGABLE) {
- deviceObject->Flags |= DO_POWER_PAGABLE;
- }
- deviceObject->Flags |= DO_DIRECT_IO;
- deviceExtension->Self = deviceObject;
- // Initialize serial-related parameters
- deviceExtension->WaitOnMaskIrp = NULL;
- deviceExtension->CurrentBaud = 0;
- deviceExtension->PendingReadIrp = NULL;
- KeInitializeTimer ( &deviceExtension->ReadTimer );
- KeInitializeDpc ( &deviceExtension->ReadDpc, ReadDpcRoutine, (PVOID)deviceExtension );
- RtlZeroMemory( &deviceExtension->SerialStatus, sizeof( SERIAL_STATUS ) );
- // initialize members relevant to TDI.
- deviceExtension->RxBuffer = ExAllocatePoolWithTag( NonPagedPool, RINGBUFFER_SIZE, 'RBuf' );
- if ( deviceExtension->RxBuffer == NULL )
- goto Error_Exit;
- deviceExtension->lpRead = deviceExtension->RxBuffer;
- deviceExtension->lpRx = deviceExtension->RxBuffer;
- deviceExtension->hTransAddr = NULL;
- deviceExtension->lpTransAddrFileObject = NULL;
- deviceExtension->TDILowerDeviceObject = NULL;
- deviceExtension->RemoteAddress = 0x601a8c0; // 192.168.1.6
- deviceExtension->RemotePort = 0x7217; // 6002
- RtlZeroMemory( (PVOID)&deviceExtension->recvContext, sizeof( RECV_CONTEXT ) );
- deviceExtension->recvContext.RemainderBuffer = ExAllocatePoolWithTag ( NonPagedPool, RECVREMAINDER_BUFFER_SIZE, 'Rrem' );
- if ( deviceExtension->recvContext.RemainderBuffer == NULL )
- goto Error_Exit;
- KeInitializeEvent(&deviceExtension->recvContext.Event,
- SynchronizationEvent,
- FALSE);
- RtlZeroMemory ( (PVOID)&deviceExtension->recvContext.ReceiveDatagramInfo, sizeof ( TDI_CONNECTION_INFORMATION ) );
- RtlZeroMemory ( (PVOID)&deviceExtension->recvContext.ReturnInfo, sizeof ( TDI_CONNECTION_INFORMATION ) );
- INITIALIZE_PNP_STATE(deviceExtension);
- //++ Register device interface for win32app
- status = IoRegisterDeviceInterface( PhysicalDeviceObject,
- (LPGUID)&GUID_CLASS_COMPORT,
- NULL,
- &deviceExtension->InterfaceName );
- DebugPrint(("InterfaceName: %wsn", deviceExtension->InterfaceName.Buffer ));
- if( !NT_SUCCESS ( status ) ){
- DebugPrint(( "AddDevice: IoRegisterDeviceInterface failed (%x) n", status ));
- goto Error_Exit;
- }
- //--
- deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
- return STATUS_SUCCESS;
- Error_Exit:
- if( deviceExtension->RxBuffer )
- {
- ExFreePool ( deviceExtension->RxBuffer );
- deviceExtension->RxBuffer = NULL;
- }
- if ( deviceExtension->recvContext.RemainderBuffer )
- {
- ExFreePool ( deviceExtension->recvContext.RemainderBuffer );
- deviceExtension->recvContext.RemainderBuffer = NULL;
- }
- IoDetachDevice( deviceExtension->NextLowerDriver );
- IoDeleteDevice( deviceObject );
- return status;
- }
- NTSTATUS
- SerialDoExternalNaming(
- IN PDEVICE_EXTENSION deviceExtension,
- IN LONG ComX
- )
- /*++
- Routine Description:
- Create external name, SymbolicLinkName and DOS name.
- Arguments:
- deviceExtension - pointer to a device object extension.
- ComX - indicates the number of Serial Ports.
- Return Value:
- NT status code.
- --*/
- {
- NTSTATUS status;
- ULONG bufLen;
- WCHAR ComXBuffer[ 4 ];
- UNICODE_STRING instanceStr;
- DebugPrint(("Enter SerialdoExternalNaming routine...n"));
- if( deviceExtension->CreatedSymbolicLink || deviceExtension->CreatedSerialCommEntry ){
- DebugPrint(("Already create symboliclink or serial commentryn"));
- return STATUS_UNSUCCESSFUL;
- }
- ASSERT( deviceExtension->SymbolicLinkName.Buffer == NULL );
- ASSERT( deviceExtension->DosName.Buffer == NULL );
- RtlInitUnicodeString(&instanceStr, NULL);
- instanceStr.MaximumLength = sizeof( ComXBuffer );
- instanceStr.Buffer = ComXBuffer; // 4 WCHAR
- RtlIntegerToUnicodeString( ComX, 10, &instanceStr );
- // 将SymbolicLinkName设置为 DosDevicesCOMn 的形式。其中n = ComX
- RtlZeroMemory( &deviceExtension->SymbolicLinkName, sizeof( UNICODE_STRING ) );
- deviceExtension->SymbolicLinkName.MaximumLength = DEVICE_OBJECT_NAME_LENGTH + sizeof( WCHAR );
- deviceExtension->SymbolicLinkName.Buffer = ExAllocatePoolWithTag( PagedPool, deviceExtension->SymbolicLinkName.MaximumLength, 'SymL' );
- if( deviceExtension->SymbolicLinkName.Buffer == NULL ){
- DebugPrint(("SERIAL: Couldn't allocate memory for symbolic link namen"));
- status = STATUS_INSUFFICIENT_RESOURCES;
- goto SerialDoExternalNamingError;
- }
- RtlZeroMemory( deviceExtension->SymbolicLinkName.Buffer, deviceExtension->SymbolicLinkName.MaximumLength );
- RtlAppendUnicodeToString( &deviceExtension->SymbolicLinkName, DOS_DEVICE_NAME ); //L"\DosDevices\COM"
- RtlAppendUnicodeStringToString( &deviceExtension->SymbolicLinkName, &instanceStr);
- DebugPrint(("SymbolicLinkName: %wZn", deviceExtension->SymbolicLinkName ));
- // 将DosName初始化 COMn 的形式, 其中 n = ComX
- deviceExtension->DosName.MaximumLength = 64 + sizeof(WCHAR);
- deviceExtension->DosName.Buffer = ExAllocatePoolWithTag( PagedPool, 64 + sizeof( WCHAR ), 'Name' );
- if( deviceExtension->DosName.Buffer == NULL ){
- DebugPrint(("SERIAL: Couldn't allocate memory for Dos namen"));
- status = STATUS_INSUFFICIENT_RESOURCES;
- goto SerialDoExternalNamingError;
- }
- deviceExtension->DosName.Length = 0;
- RtlZeroMemory( deviceExtension->DosName.Buffer, deviceExtension->DosName.MaximumLength );
- RtlAppendUnicodeToString( &deviceExtension->DosName, L"COM" );
- RtlAppendUnicodeStringToString( &deviceExtension->DosName, &instanceStr);
- DebugPrint(("DosName: %wZn", &deviceExtension->DosName ));
- DebugPrint(("DeviceName: %wZn", &deviceExtension->DeviceName ));
- // 生成符号连接,至此本设备对win32应用表现的Dos设备名为 DosDevicesCOMn
- status = IoCreateSymbolicLink( &deviceExtension->SymbolicLinkName, &deviceExtension->DeviceName );
- if( !NT_SUCCESS( status )){
- DebugPrint(("SERIAL: Couldn't create the symbolic link with error %dn", status));
- goto SerialDoExternalNamingError;
- }else{
- DebugPrint(("Create the symbolic link OKn"));
- deviceExtension->CreatedSymbolicLink = TRUE;
- }
- // 在注册表的 HKEY_LOCAL_MACHINEHARDWAREDEVICEMAPSERIALCOMM 中,添加ComX的键值
- // 若不进行这一步,则超级终端程序无法检测到本虚拟串口设备
- status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,
- deviceExtension->DeviceName.Buffer, REG_SZ,
- deviceExtension->DosName.Buffer,
- deviceExtension->DosName.Length + sizeof(WCHAR));
- if( !NT_SUCCESS( status )){
- DebugPrint(("SERIAL: Couldn't create the device map entryn------- for port %wZn", deviceExtension->DeviceName ));
- goto SerialDoExternalNamingError;
- }
- deviceExtension->ComX = ComX;
- deviceExtension->CreatedSerialCommEntry = TRUE;
- SerialDoExternalNamingError:
- if( !NT_SUCCESS( status )){
- if( deviceExtension->DosName.Buffer != NULL ){
- ExFreePool( deviceExtension->DosName.Buffer );
- deviceExtension->DosName.Buffer = NULL;
- deviceExtension->CreatedSerialCommEntry = FALSE;
- }
- if( deviceExtension->CreatedSymbolicLink ){
- IoDeleteSymbolicLink( &deviceExtension->SymbolicLinkName );
- deviceExtension->CreatedSymbolicLink = FALSE;
- }
- if( deviceExtension->SymbolicLinkName.Buffer != NULL ){
- ExFreePool( deviceExtension->SymbolicLinkName.Buffer );
- deviceExtension->SymbolicLinkName.Buffer = NULL;
- }
- }
- return status;
- }
- BOOLEAN InitializeSerialDevName( PUNICODE_STRING lpDeviceName )
- /*++
- Routine Description:
- Initialize serial device name. This name is available in Kernel Mode.
- Arguments:
- PUNICODE_STRING lpDeviceName - the pointer to device name string.
- Return Value:
- return TRUE if it is successful, otherwise return FALSE.
- --*/
- {
- WCHAR instanceNumberBuffer[ 4 ];
- UNICODE_STRING instanceStr;
- static ULONG currentInstance = 10;
- // 首先处理deviceObjName,这是一个核心态使用的设备名,形如"\Device\SiSerial0"
- // Zero out allocated memory pointers so we know if they must be freed
- RtlZeroMemory( lpDeviceName, sizeof(UNICODE_STRING) );
- lpDeviceName->MaximumLength = DEVICE_OBJECT_NAME_LENGTH * sizeof(WCHAR);
- lpDeviceName->Buffer = ExAllocatePool(PagedPool, lpDeviceName->MaximumLength + sizeof(WCHAR));
- if ( lpDeviceName->Buffer == NULL) {
- DebugPrint(("Couldn't allocate memory for device namen"));
- return FALSE;
- }
- RtlZeroMemory( lpDeviceName->Buffer, lpDeviceName->MaximumLength + sizeof(WCHAR));
- // now, the size of deviceObjName.Buffer is (128 + 1)(WCHAR)
- RtlAppendUnicodeToString( lpDeviceName, DEVICE_NAME); // L"\Device\VSer"
- // 处理 lpDeviceName 的后缀序号
- RtlInitUnicodeString(&instanceStr, NULL);
- instanceStr.MaximumLength = sizeof(instanceNumberBuffer);
- instanceStr.Buffer = instanceNumberBuffer; // 20 WCHAR
- currentInstance++;
- RtlIntegerToUnicodeString( currentInstance, 10, &instanceStr);
- RtlAppendUnicodeStringToString( lpDeviceName, &instanceStr);
- DebugPrint(("DeviceName:n"));
- DebugPrint(("----------- %wsn", lpDeviceName->Buffer ));
- return TRUE;
- }
- NTSTATUS
- SerialUndoExternalNaming(
- IN PDEVICE_EXTENSION deviceExtension
- )
- /*++
- Routine Description:
- Delete or unregister external name, SymbolicLinkName and DOS name.
- Arguments:
- deviceExtension - pointer to a device object extension.
- Return Value:
- NT status code.
- --*/
- {
- NTSTATUS status = STATUS_SUCCESS;
- if( deviceExtension->CreatedSymbolicLink ){
- IoDeleteSymbolicLink( &deviceExtension->SymbolicLinkName );
- ExFreePool( deviceExtension->SymbolicLinkName.Buffer );
- deviceExtension->SymbolicLinkName.Buffer = NULL;
- deviceExtension->CreatedSymbolicLink = FALSE;
- }else{
- ASSERT( deviceExtension->SymbolicLinkName.Buffer == NULL );
- }
- ASSERT( deviceExtension->DeviceName.Buffer != NULL );
- if( deviceExtension->CreatedSerialCommEntry ){
- status = RtlDeleteRegistryValue( RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP, deviceExtension->DeviceName.Buffer );
- if( !NT_SUCCESS( status ) ){
- DebugPrint(("RtlDeleteRegistryValue device map failedn"));
- }
- ExFreePool( deviceExtension->DosName.Buffer );
- deviceExtension->DosName.Buffer = NULL;
- deviceExtension->CreatedSerialCommEntry = FALSE;
- }else{
- ASSERT( deviceExtension->DosName.Buffer == NULL );
- }
- return status;
- }
- NTSTATUS
- SerialRemoveDevObj(IN PDEVICE_OBJECT PDevObj)
- /*++
- Routine Description:
- Removes a serial device object from the system.
- Arguments:
- PDevObj - A pointer to the Device Object we want removed.
- Return Value:
- Always TRUE
- --*/
- {
- PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)PDevObj->DeviceExtension;
- PAGED_CODE();
- DebugPrint(("SERIAL: Enter SerialRemoveDevObjn"));
- //
- // Free memory allocated in the extension
- //
- if (pDevExt->DeviceName.Buffer != NULL) {
- ExFreePool(pDevExt->DeviceName.Buffer);
- }
- if (pDevExt->SymbolicLinkName.Buffer != NULL) {
- ExFreePool(pDevExt->SymbolicLinkName.Buffer);
- }
- if (pDevExt->DosName.Buffer != NULL) {
- ExFreePool(pDevExt->DosName.Buffer);
- }
- DebugPrint(("SERIAL: Leave SerialRemoveDevObjn"));
- return STATUS_SUCCESS;
- }
- NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status, IN ULONG info)
- {
- Irp->IoStatus.Status = status;
- Irp->IoStatus.Information = info;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return status;
- }
- VOID
- Unload(
- IN PDRIVER_OBJECT DriverObject
- )
- /*++
- Routine Description:
- Free all the allocated resources in DriverEntry, etc.
- Arguments:
- DriverObject - pointer to a driver object.
- Return Value:
- VOID.
- --*/
- {
- PAGED_CODE ();
- //
- // The device object(s) should be NULL now
- // (since we unload, all the devices objects associated with this
- // driver must be deleted.
- //
- DebugPrint( ("Is unloading......n") );
- ASSERT(DriverObject->DeviceObject == NULL);
- //
- // We should not be unloaded until all the devices we control
- // have been removed from our queue.
- //
- DebugPrint (("Unload: unloadn"));
- return;
- }
- LONG
- SampleIoIncrement(
- IN OUT PDEVICE_EXTENSION DeviceExtension
- )
- /* ++
- Routine Description:
- Increment deviceExtension->OutStandingIO within the scope of IOCountLock.
- Arguments:
- deviceExtension - pointer to a device object extension.
- Return Value:
- deviceExtension->OutStandingIO
- --*/
- {
- LONG result = 0;
- KIRQL oldIrql;
- KeAcquireSpinLock(&DeviceExtension->IOCountLock, &oldIrql);
- result = InterlockedIncrement(&DeviceExtension->OutStandingIO);
- //
- // when OutStandingIO bumps from 1 to 2, clear the StopEvent
- //
- if(result == 2) {
- KeClearEvent(&DeviceExtension->StopEvent);
- }
- KeReleaseSpinLock(&DeviceExtension->IOCountLock, oldIrql);
- DebugPrint(("SampleIncrement: %dn", result));
- return result;
- }
- LONG
- SampleIoDecrement(
- IN OUT PDEVICE_EXTENSION DeviceExtension
- )
- /*++
- Routine Description:
- Decrement deviceExtension->OutStandingIO within the scope of IOCountLock.
- Arguments:
- deviceExtension - pointer to a device object extension.
- Return Value:
- deviceExtension->OutStandingIO
- --*/
- {
- LONG result = 0;
- KIRQL oldIrql;
- KeAcquireSpinLock(&DeviceExtension->IOCountLock, &oldIrql);
- result = InterlockedDecrement(&DeviceExtension->OutStandingIO);
- if(result == 1) {
- KeSetEvent(&DeviceExtension->StopEvent, IO_NO_INCREMENT, FALSE);
- }
- if(result == 0) {
- ASSERT(Removed == DeviceExtension->DevicePnPState);
- KeSetEvent(&DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE);
- }
- KeReleaseSpinLock(&DeviceExtension->IOCountLock, oldIrql);
- DebugPrint(("SampleIoDecrement: %dn", result));
- return result;
- }