?? rs485nt.c
字號:
//---------------------------------------------------------------------------
//
// 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(&uniNtNameString, NT_DEVICE_NAME);
//
// Create the device object, single-thread access (TRUE)
//
status = IoCreateDevice(DriverObject, sizeof(RS485NT_DEVICE_EXTENSION),
&uniNtNameString, FILE_DEVICE_UNKNOWN, 0,
TRUE, &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,
&irql, // IRQ level
&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, &AddressSpace,
&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, &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(&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( &uniWin32NameString, DOS_DEVICE_NAME);
//
// Create a link from our device name to a name in the Win32 namespace.
//
status = IoCreateSymbolicLink( &uniWin32NameString, &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 & IIR_INTERRUPT_MASK) != IIR_NO_INTERRUPT_PENDING) {
switch (ch & 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 (&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 & 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) &
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 (&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 + -