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

📄 rs485nt.c

📁 RS485设备驱动源代码
💻 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(&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 + -