www.pudn.com > 2004-01-16_SimSerial.rar > Pnp.c
#include#include #include "main.h" #include "..\inc\wdmioctl.h" #ifdef ALLOC_PRAGMA #pragma alloc_text (PAGE, DispatchPnp) #endif extern DEVICE_ARRAY gDeviceArray[ MAX_NUM_DEV ]; extern KSPIN_LOCK gSpinLock; NTSTATUS DispatchPnp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: The plug and play dispatch routines. Most of these the driver will completely ignore. In all cases it must pass on the IRP to the lower driver. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code --*/ { PDEVICE_EXTENSION deviceExtension; PIO_STACK_LOCATION irpStack; NTSTATUS status; KEVENT event; PAGED_CODE(); deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; irpStack = IoGetCurrentIrpStackLocation(Irp); DebugPrint(("Sample %s IRP:0x%x \n", PnPMinorFunctionString(irpStack->MinorFunction), Irp)); status = STATUS_SUCCESS; switch (irpStack->MinorFunction) { case IRP_MN_START_DEVICE: status = PnpStartDevice( DeviceObject, Irp); return status; case IRP_MN_REMOVE_DEVICE: status = PnpRemoveDevice( DeviceObject, Irp ); return status; case IRP_MN_QUERY_STOP_DEVICE: SET_NEW_PNP_STATE(deviceExtension, StopPending); status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_STOP_DEVICE: // // Check to see whether you have received cancel-stop // without first receiving a query-stop. This could happen if someone // above us fails a query-stop and passes down the subsequent // cancel-stop. // if(StopPending == deviceExtension->DevicePnPState) { // // We did receive a query-stop, so restore. // RESTORE_PREVIOUS_PNP_STATE(deviceExtension); } status = STATUS_SUCCESS; // We must not fail this IRP. break; case IRP_MN_STOP_DEVICE: SET_NEW_PNP_STATE(deviceExtension, StopPending); status = STATUS_SUCCESS; break; case IRP_MN_QUERY_REMOVE_DEVICE: SET_NEW_PNP_STATE(deviceExtension, RemovePending); status = STATUS_SUCCESS; break; case IRP_MN_SURPRISE_REMOVAL: SET_NEW_PNP_STATE(deviceExtension, SurpriseRemovePending); status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: // // Check to see whether you have received cancel-remove // without first receiving a query-remove. This could happen if // someone above us fails a query-remove and passes down the // subsequent cancel-remove. // if(RemovePending == deviceExtension->DevicePnPState) { // // We did receive a query-remove, so restore. // RESTORE_PREVIOUS_PNP_STATE(deviceExtension); } status = STATUS_SUCCESS; // We must not fail this IRP. break; default: // // If you don't handle any IRP you must leave the // status as is. // status = Irp->IoStatus.Status; break; } // // Pass the IRP down and forget it. // Irp->IoStatus.Status = status; return DefaultPnpHandler( DeviceObject, Irp ); } NTSTATUS PnpStartDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS status; PDEVICE_EXTENSION deviceExtension; PIO_STACK_LOCATION stack; deviceExtension = DeviceObject->DeviceExtension; status = ForwardAndWait( DeviceObject, Irp); if (!NT_SUCCESS(status)) return CompleteRequest(Irp, status, Irp->IoStatus.Information); stack = IoGetCurrentIrpStackLocation( Irp ); // TODO: other work to start the device in this layer driver status = SerialFinishStartDevice( deviceExtension ); if( !NT_SUCCESS( status ) ){ return CompleteRequest( Irp, status, 0 ); } // 添加Interface,给win32 App提供访问接口 status = AddInterface( deviceExtension ); if( NT_SUCCESS( status ) && NT_SUCCESS( Irp->IoStatus.Status ) ){ SET_NEW_PNP_STATE( deviceExtension, Started ); } return CompleteRequest(Irp, status, 0); } NTSTATUS PnpRemoveDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS status; PDEVICE_EXTENSION deviceExtension; DebugPrint(("+Enter RemoveDevice routine\n" )); deviceExtension = DeviceObject->DeviceExtension; // TODO: handle our remove work at first SerialUndoExternalNaming( deviceExtension ); // 删除Interface DelInterface( deviceExtension ); SerialRemoveDevObj( DeviceObject ); // Pass down the IRP IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( deviceExtension->NextLowerDriver, Irp ); SET_NEW_PNP_STATE(deviceExtension, Deleted); DebugPrint( ("NextLowerDriver: 0x%x\n", deviceExtension->NextLowerDriver )); IoDetachDevice( deviceExtension->NextLowerDriver ); gDeviceArray[ deviceExtension->localInstance ].deviceExtension = NULL; IoDeleteDevice( DeviceObject ); DebugPrint(("-Exit RemoveDevice routine\n")); return status; } NTSTATUS SerialCreateDevObj( IN PDRIVER_OBJECT DriverObject, OUT PDEVICE_OBJECT *NewDeviceObject ) { UNICODE_STRING deviceObjName; UNICODE_STRING instanceStr; PDEVICE_OBJECT deviceObject = NULL; PDEVICE_EXTENSION pDevExt; NTSTATUS status = STATUS_SUCCESS; WCHAR instanceNumberBuffer[20]; ULONG currentInstance; PAGED_CODE(); DebugPrint(("Enter SerialCreateDevObj\n")); for( currentInstance = 0; currentInstance < MAX_NUM_DEV; currentInstance++){ // find the first empty device description in gDeviceArray if( gDeviceArray[ currentInstance ].deviceExtension == NULL ){ break; } } if( currentInstance == MAX_NUM_DEV ){ DebugPrint(("There is no memory in gDeviceArray\n")); status = STATUS_INSUFFICIENT_RESOURCES; *NewDeviceObject = NULL; return status; } // 首先处理deviceObjName,这是一个核心态使用的设备名,形如"\\Device\\SiSerial0" // Zero out allocated memory pointers so we know if they must be freed RtlZeroMemory(&deviceObjName, sizeof(UNICODE_STRING)); deviceObjName.MaximumLength = DEVICE_OBJECT_NAME_LENGTH * sizeof(WCHAR); deviceObjName.Buffer = ExAllocatePool(PagedPool, deviceObjName.MaximumLength + sizeof(WCHAR)); if (deviceObjName.Buffer == NULL) { DebugPrint(("Couldn't allocate memory for device name\n")); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory( deviceObjName.Buffer, deviceObjName.MaximumLength + sizeof(WCHAR)); // now, the size of deviceObjName.Buffer is (128 + 1)(WCHAR) RtlAppendUnicodeToString(&deviceObjName, DEVICE_NAME); // L"\\Device\\SiSerial" // 处理deviceObjName的后缀序号 RtlInitUnicodeString(&instanceStr, NULL); instanceStr.MaximumLength = sizeof(instanceNumberBuffer); instanceStr.Buffer = instanceNumberBuffer; // 20 WCHAR RtlIntegerToUnicodeString( currentInstance, 10, &instanceStr); RtlAppendUnicodeStringToString( &deviceObjName, &instanceStr); DebugPrint(("DeviceName:\n")); DebugPrint(("----------- %ws\n", deviceObjName.Buffer )); // // Create the device object // status = IoCreateDevice(DriverObject, sizeof( DEVICE_EXTENSION ), &deviceObjName, FILE_DEVICE_SERIAL_PORT, FILE_DEVICE_SECURE_OPEN, TRUE, &deviceObject); if (!NT_SUCCESS(status)) { DebugPrint(("SerialAddDevice: Create device failed - %x \n", status )); goto SerialCreateDevObjError; } ASSERT(deviceObject != NULL); gDeviceArray[ currentInstance ].deviceExtension = deviceObject->DeviceExtension; pDevExt = deviceObject->DeviceExtension; // // The device object has a pointer to an area of non-paged // pool allocated for this device. This will be the device // extension. Zero it out. // RtlZeroMemory( pDevExt, sizeof( DEVICE_EXTENSION ) ); // 在DeviceExtension中保存deviceName pDevExt->DeviceName.Buffer = ExAllocatePool(PagedPool, deviceObjName.Length + sizeof(WCHAR)); if (!pDevExt->DeviceName.Buffer) { DebugPrint(("SERIAL: Couldn't allocate memory for DeviceName\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto SerialCreateDevObjError; } pDevExt->DeviceName.MaximumLength = deviceObjName.Length + sizeof(WCHAR); // Zero fill it. RtlZeroMemory(pDevExt->DeviceName.Buffer, pDevExt->DeviceName.MaximumLength); RtlAppendUnicodeStringToString(&pDevExt->DeviceName, &deviceObjName); //++ Initialize common devExtension // 设置本设备的instance序号和与其相联接的设备序号(目前是没有连接,所以设为Invalid_Instance pDevExt->localInstance = currentInstance; pDevExt->remoteInstance = INVALID_INSTANCE; pDevExt->Self = deviceObject; pDevExt->bIsOpen = FALSE; pDevExt->PowerState = PowerDeviceD0; pDevExt->CreatedSymbolicLink = FALSE; pDevExt->CreatedSerialCommEntry = FALSE; pDevExt->BufferSize = 1024; //+ by zcz //deviceObject->DeviceType = deviceExtension->NextLowerDriver->DeviceType; //deviceObject->Characteristics = // deviceExtension->NextLowerDriver->Characteristics; //--- //++ Initialize serial section KeInitializeSpinLock( &pDevExt->CancelSpinLock ); InitializeListHead( &pDevExt->ReadIrpQueue ); InitializeListHead( &pDevExt->WriteIrpQueue ); InitializeListHead( &pDevExt->ReadDataQueue ); KeInitializeSpinLock( &pDevExt->ReadQueueSpinLock ); //- // // Set the initial state of the Filter DO // *NewDeviceObject = deviceObject; ExFreePool(deviceObjName.Buffer); DebugPrint(("Leave SerialCreateDevObj\n") ); return STATUS_SUCCESS; SerialCreateDevObjError: DebugPrint(("SERIAL: SerialCreateDevObj Error, Cleaning up\n") ); // // Free the allocated strings for the NT and symbolic names if they exist. // if (deviceObjName.Buffer != NULL) { ExFreePool(deviceObjName.Buffer); } if (deviceObject) { if (pDevExt->DeviceName.Buffer != NULL) { ExFreePool(pDevExt->DeviceName.Buffer); } gDeviceArray[ currentInstance ].deviceExtension = NULL; IoDeleteDevice(deviceObject); } *NewDeviceObject = NULL; DebugPrint(("SERIAL: Leave SerialCreateDevObj\n") ); 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 SerialRemoveDevObj\n")); // // 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); } if( pDevExt->BufferSize != 0 ){ pDevExt->BufferSize = 0; } DebugPrint(("SERIAL: Leave SerialRemoveDevObj\n")); return STATUS_SUCCESS; } NTSTATUS SerialDoExternalNaming( IN PDEVICE_EXTENSION deviceExtension, IN LONG ComX ) { 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 commentry\n")); 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设置为 \DosDevices\COMn 的形式。其中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 name\n")); 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: %wZ\n", 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 name\n")); 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: %wZ\n", &deviceExtension->DosName )); DebugPrint(("DeviceName: %wZ\n", &deviceExtension->DeviceName )); // 生成符号连接,至此本设备对win32应用表现的Dos设备名为 \DosDevices\COMn status = IoCreateSymbolicLink( &deviceExtension->SymbolicLinkName, &deviceExtension->DeviceName ); if( !NT_SUCCESS( status )){ DebugPrint(("SERIAL: Couldn't create the symbolic link with error %d\n", status)); goto SerialDoExternalNamingError; }else{ DebugPrint(("Create the symbolic link OK\n")); deviceExtension->CreatedSymbolicLink = TRUE; } // 在注册表的 HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM 中,添加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 entry\n------- for port %wZ\n", 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; } NTSTATUS SerialUndoExternalNaming( IN PDEVICE_EXTENSION deviceExtension ) { 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 failed\n")); } ExFreePool( deviceExtension->DosName.Buffer ); deviceExtension->DosName.Buffer = NULL; deviceExtension->CreatedSerialCommEntry = FALSE; }else{ ASSERT( deviceExtension->DosName.Buffer == NULL ); } return status; } NTSTATUS SerialFinishStartDevice( IN PDEVICE_EXTENSION deviceExtension ) { // Default Line control protocol. 7E1 // // Seven data bits. // Even parity. // 1 Stop bits. // //deviceExtension->LineControl = SERIAL_7_DATA | SERIAL_EVEN_PARITY | SERIAL_NONE_PARITY; deviceExtension->LineControl.WordLength = 8; deviceExtension->LineControl.Parity = 0; deviceExtension->LineControl.StopBits = 1; deviceExtension->CurrentBaud = 1200; deviceExtension->SpecialChars.XonChar = SERIAL_DEF_XON; deviceExtension->SpecialChars.XoffChar = SERIAL_DEF_XOFF; deviceExtension->SpecialChars.EofChar = 0; deviceExtension->SpecialChars.ErrorChar = 0; deviceExtension->SpecialChars.BreakChar = 0; deviceExtension->SpecialChars.EventChar = 0; deviceExtension->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL; deviceExtension->HandFlow.FlowReplace = SERIAL_DSR_SENSITIVITY;//SERIAL_RTS_CONTROL; deviceExtension->HandFlow.XonLimit = 4096; deviceExtension->HandFlow.XoffLimit = 1024; return STATUS_SUCCESS; } //++ Register device interface for win32app NTSTATUS AddInterface( IN PDEVICE_EXTENSION deviceExtension ) { NTSTATUS status; status = IoRegisterDeviceInterface( deviceExtension->PhysicalDeviceObject, (LPGUID)&GUID_CLASS_COMPORT, NULL, &deviceExtension->InterfaceName ); if( !NT_SUCCESS( status )){ DebugPrint(("SERIAL: Couldn't register class association\n")); deviceExtension->InterfaceName.Buffer = NULL; return status; } status = IoSetDeviceInterfaceState( &deviceExtension->InterfaceName, TRUE ); if( !NT_SUCCESS( status )){ DebugPrint(("SERIAL: Couldn't set class association\n")); } return status; } VOID DelInterface( IN PDEVICE_EXTENSION deviceExtension ) { NTSTATUS status; if( deviceExtension->InterfaceName.Buffer ){ status = IoSetDeviceInterfaceState( &deviceExtension->InterfaceName, FALSE ); if( !NT_SUCCESS( status )){ DebugPrint(("SERIAL: IoSetDeviceInterface failed\n")); } RtlFreeUnicodeString( &deviceExtension->InterfaceName ); } }