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

📄 4.c

📁 基于80C196KC微处理器的高速串行通讯、单片机将FIFO中的数据读取出来后
💻 C
📖 第 1 页 / 共 3 页
字号:

//--------------------------------------------------------------------------- 
// 
// RS485NT.C 
// 
// Author: Anthony A. Kempka 
// Device Drivers International, LLC 
// 
// Tel: 218-587-3120 
// Tel: 513-984-4491 
// Web: www.ddiusa.com 
// 
//--------------------------------------------------------------------------- 
// 
// For: Integrity Instruments (a division of Cogito Software, Inc.) 
// 
// Tel: 800-450-2001 
// Web: www.integrityusa.com 
// 
// 
// Last Modified: 
// A. A. Kempka 08/20/97 Original. 
// 
//--------------------------------------------------------------------------- 
// 
// Description: 
// ------------ 
// This file was developed for Integrity Instruments as a Generic 
// Windows NT RS485 driver. This is a Kernel-Mode driver. 
// 
// 
// Application Interface: 
// ---------------------- 
// CreateFile () - Establishes an open channel to this driver 
// WriteFile () - Transmits a buffer of Data via RS485 by asserting 
// RTS during trasnmit and deasserting RTS upon 
// transmitt complete of the final character 
// 
// *CAUTION* WriteFile discards unread receive buffer contents! 
// 
// ReadFile () - Returns the current received character buffer 
// 
// See the sample User mode API in Q_TEST.C 
// 
// 
// Distribution Notice: 
// -------------------- 
// 
// 
// 
//--------------------------------------------------------------------------- 

//--------------------------------------------------------------------------- 
// 
// Include files 
// 
#include "NTDDK.H" 
#include "COM8250.H" 
#include "RS485NT.H" 
#include "RS485IOC.H" 

//--------------------------------------------------------------------------- 
// 
// Define the driver names 
// 
#define NT_DEVICE_NAME L"\\Device\\RS485NT" 
#define DOS_DEVICE_NAME L"\\DosDevices\\RS485NT" 

#define RS_DbgPrint(a) DbgPrint(a) 


//--------------------------------------------------------------------------- 
// 
// Declare forward function references 
// 

NTSTATUS DispatchRoutine (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); 

VOID UnloadDriver (IN PDRIVER_OBJECT DriverObject); 

BOOLEAN ReportUsage (IN PDRIVER_OBJECT DriverObject, 
IN PDEVICE_OBJECT DeviceObject, 
IN PHYSICAL_ADDRESS PortAddress, 
IN BOOLEAN *ConflictDetected); 

BOOLEAN RS485_Isr (IN PKINTERRUPT Interrupt, IN OUT PVOID Context); 

VOID RS485_Dpc_Routine (IN PKDPC Dpc, IN PDEVICE_OBJECT DeviceObject, 
IN PIRP Irp, IN PVOID Context); 

NTSTATUS GetConfiguration (IN PRS485NT_DEVICE_EXTENSION DeviceExtension, 
IN PUNICODE_STRING RegistryPath); 

NTSTATUS Initialize_RS485 (IN PRS485NT_DEVICE_EXTENSION DeviceExtension); 

NTSTATUS RS485_Write (IN PRS485NT_DEVICE_EXTENSION deviceExtension, IN PIRP Irp); 
NTSTATUS RS485_Read (IN PRS485NT_DEVICE_EXTENSION deviceExtension, IN PIRP Irp); 


//--------------------------------------------------------------------------- 
// 
// Begin FUNCTIONS 
// 

//--------------------------------------------------------------------------- 
// DriverEntry 
// 
// Description: 
// NT device Driver Entry point 
// 
// Arguments: 
// DriverObject - Pointer to this device's driver object 
// RegistryPath - Pointer to the Unicode regsitry path name 
// 
// Return Value: 
// NTSTATUS 
// 
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) 
{ 
PDEVICE_OBJECT deviceObject = NULL; 
NTSTATUS status, ioConnectStatus; 
UNICODE_STRING uniNtNameString; 
UNICODE_STRING uniWin32NameString; 
KIRQL irql = DEF_IRQ_LINE; 
KAFFINITY Affinity; 
ULONG MappedVector, AddressSpace = 1; 
PRS485NT_DEVICE_EXTENSION extension; 
BOOLEAN ResourceConflict; 
PHYSICAL_ADDRESS InPortAddr, OutPortAddr; 

RS_DbgPrint ("RS485NT: Enter the driver!\n"); 

// 
// Create counted string version of our device name. 
// 

RtlInitUnicodeString(&amt;uniNtNameString, NT_DEVICE_NAME); 

// 
// Create the device object, single-thread access (TRUE) 
// 

status = IoCreateDevice(DriverObject, sizeof(RS485NT_DEVICE_EXTENSION), 
&amt;uniNtNameString, FILE_DEVICE_UNKNOWN, 0, 
TRUE, &amt;deviceObject); 

if (!NT_SUCCESS (status) ) { 
RS_DbgPrint("RS485NT: IoCreateDevice failed\n"); 
return status; 
} 
// 
// Set the FLAGS field 
// 

deviceObject->Flags |= DO_BUFFERED_IO; 

// 
// Get the configuration information from the Registry 
// 

status = GetConfiguration (deviceObject->DeviceExtension, RegistryPath); 

if (!NT_SUCCESS (status) ) { 
RS_DbgPrint("RS485NT: GetConfiguration failed\n"); 
return status; 
} 

extension = (PRS485NT_DEVICE_EXTENSION) deviceObject->DeviceExtension; 

// 
// This call will map our IRQ to a system vector. It will also fill 
// in the IRQL (the kernel-defined level at which our ISR will run), 
// and affinity mask (which processors our ISR can run on). 
// 
// We need to do this so that when we connect to the interrupt, we 
// can supply the kernel with this information. 
// 
MappedVector = HalGetInterruptVector( 
Isa, // Interface type 
0, // Bus number 
extension->IRQLine, 
extension->IRQLine, 
&amt;irql, // IRQ level 
&amt;Affinity // Affinity mask 
); 

// 
// A little known Windows NT fact, 
// If MappedVector==0, then HalGetInterruptVector failed. 
// 

if (MappedVector == 0) { 
RS_DbgPrint("RS485NT: HalGetInterruptVector failed\n"); 
return (STATUS_INVALID_PARAMETER); 
} 

// 
// Save off the Irql 
// 

extension->Irql = irql; 

// 
// Translate the base port address to a system mapped address. 
// This will be saved in the device extension after IoCreateDevice, 
// because we use the translated port address to access the ports. 
// 

InPortAddr.LowPart = (ULONG)extension->PortAddress; 
InPortAddr.HighPart = 0; 
if (!HalTranslateBusAddress(Isa, 0, InPortAddr, &amt;AddressSpace, 
&amt;OutPortAddr)) { 
RS_DbgPrint("RS485NT: HalTranslateBusAddress failed\n"); 
return STATUS_SOME_NOT_MAPPED; 
} 


if ( NT_SUCCESS(status) ) { 

// 
// Create dispatch points for create/open, close, unload, and ioctl 
// 

DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchRoutine; 
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchRoutine; 
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRoutine; 
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchRoutine; 
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchRoutine; 
DriverObject->DriverUnload = UnloadDriver; 

// 
// check if resources (ports and interrupt) are available 
// 
ReportUsage (DriverObject, deviceObject, OutPortAddr, &amt;ResourceConflict); 

if (ResourceConflict) { 
RS_DbgPrint("RS485NT: Couldn't get resources\n"); 
IoDeleteDevice(deviceObject); 
return STATUS_INSUFFICIENT_RESOURCES; 
} 

// 
// fill in the device extension 
// 
extension = (PRS485NT_DEVICE_EXTENSION) deviceObject->DeviceExtension; 
extension->DeviceObject = deviceObject; 
extension->PortAddress = (PVOID)OutPortAddr.LowPart; 

// 
// connect the device driver to the IRQ 
// 
ioConnectStatus = IoConnectInterrupt(&amt;extension->InterruptObject, 
RS485_Isr, 
extension->DeviceObject, 
NULL, 
MappedVector, 
irql, 
irql, 
Latched, 
FALSE, 
Affinity, 
FALSE); 

if ( !NT_SUCCESS (ioConnectStatus) ) { 
RS_DbgPrint("RS485NT: Couldn't connect interrupt\n"); 
IoDeleteDevice(deviceObject); 
return ioConnectStatus; 
} 

RS_DbgPrint("RS485NT: just about ready!\n"); 

// 
// Create counted string version of our Win32 device name. 
// 

RtlInitUnicodeString( &amt;uniWin32NameString, DOS_DEVICE_NAME); 

// 
// Create a link from our device name to a name in the Win32 namespace. 
// 

status = IoCreateSymbolicLink( &amt;uniWin32NameString, &amt;uniNtNameString ); 

if (!NT_SUCCESS(status)) { 
RS_DbgPrint("RS485NT: Couldn't create the symbolic link\n"); 
IoDeleteDevice (DriverObject->DeviceObject); 
} else { 

// 
// Setup the Dpc for ISR routine 
// 

IoInitializeDpcRequest (DriverObject->DeviceObject, RS485_Dpc_Routine); 

// 
// Initialize the device (enable IRQ's, hit the hardware) 
// 

Initialize_RS485 (extension); 

RS_DbgPrint("RS485NT: All initialized!\n"); 
} 

} else { 
RS_DbgPrint("RS485NT: Couldn't create the device\n"); 
} 
return status; 
} 


//--------------------------------------------------------------------------- 
// RS485_Isr 
// 
// Description: 
// This is our 'C' Isr routine to handle RS485 transmit and recieve 
// 
// Arguments: 
// Interrupt - Pointer to our interrupt object 
// Context - Pointer to our device object 
// 
// Return Value: 
// TRUE - If this was our ISR (assumed) 
// 
BOOLEAN RS485_Isr (IN PKINTERRUPT Interrupt, IN OUT PVOID Context) 
{ 
PDEVICE_OBJECT DeviceObject; 
PRS485NT_DEVICE_EXTENSION DeviceExtension; 
UCHAR ch; 

// 
// Get the Device Object and obtain our Extension 
// 

DeviceObject = Context; 
DeviceExtension = DeviceObject->DeviceExtension; 

// 
// Bump the interrupt count 
// 

DeviceExtension->InterruptCount++; 

RS_DbgPrint ("RS485NT: ISR!\n"); 

// 
// For the 8250 series UART, we must spin and handle ALL interrupts 
// before returning 
// 

ch = READ_PORT_UCHAR (DeviceExtension->ComPort.IIR); 

while ((ch &amt; IIR_INTERRUPT_MASK) != IIR_NO_INTERRUPT_PENDING) { 
switch (ch &amt; IIR_INTERRUPT_MASK) { 

case IIR_RX_ERROR_IRQ_PENDING: // 1st priority interrupt 
RS_DbgPrint ("RS485NT: ISR RX Error!\n"); 
ch = READ_PORT_UCHAR (DeviceExtension->ComPort.LSR); 
DeviceExtension->RcvError++; 
break; 

case IIR_RX_DATA_READY_IRQ_PENDING: // 2nd priority int 

RS_DbgPrint ("RS485NT: ISR RX Data!\n"); 

// 
// Read the UART receive register and stuff byte into buffer 
// 

ch = READ_PORT_UCHAR (DeviceExtension->ComPort.RBR); 

// 
// Check for end of buffer 
// 

if (DeviceExtension->RcvBufferPosition+1 < 
DeviceExtension->RcvBufferEnd) { 

*DeviceExtension->RcvBufferPosition = ch; 
DeviceExtension->RcvBufferPosition++; 
DeviceExtension->RcvBufferCount++; 
} 

// 
// Get the current system time 
// 

KeQuerySystemTime (&amt;DeviceExtension->LastQuerySystemTime); 

break; 

case IIR_TX_HBE_IRQ_PENDING: // 3rd priority interrupt 

RS_DbgPrint ("RS485NT: ISR TX Data!\n"); 

// 
// Is this the last byte sent? 
// 

if (DeviceExtension->XmitBufferCount == 0) { 

// 
// Wait for the entire character to be sent out the UART 
// 

ch = READ_PORT_UCHAR (DeviceExtension->ComPort.LSR); 

while ( (ch &amt; LSR_TX_BOTH_EMPTY) != LSR_TX_BOTH_EMPTY) { 
ch = READ_PORT_UCHAR (DeviceExtension->ComPort.LSR); 
} 

// 
// De-assert RTS 
// 

ch = READ_PORT_UCHAR (DeviceExtension->ComPort.MCR) &amt; 
MCR_DEACTIVATE_RTS; 
WRITE_PORT_UCHAR (DeviceExtension->ComPort.MCR, ch); 

// 
// Clear the Rcv buffer info, a reply is emminent 
// 

DeviceExtension->RcvBufferCount = 0; 
DeviceExtension->RcvBufferPosition = DeviceExtension->RcvBuffer; 

// 
// Schedule the DPC (where the Xmit done event is set) 
// 

IoRequestDpc (DeviceObject, DeviceObject->CurrentIrp, NULL); 

} else { 

// 
// Send the next byte 
// 

WRITE_PORT_UCHAR (DeviceExtension->ComPort.TBR, 
*DeviceExtension->XmitBufferPosition); 

DeviceExtension->XmitBufferPosition++; 
DeviceExtension->XmitBufferCount--; 
} 

// 
// Get the current system time 
// 

KeQuerySystemTime (&amt;DeviceExtension->LastQuerySystemTime); 

break; 

case IIR_MODEM_STATUS_IRQ_PENDING: // 4th priority interrupt 
RS_DbgPrint ("RS485NT: ISR Modem Status!\n"); 

⌨️ 快捷键说明

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