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

📄 initunlo.cpp

📁 这个是串口驱动程序开发包
💻 CPP
📖 第 1 页 / 共 5 页
字号:
#include "precomp.h"

NTSTATUS SerialItemCallBack(QUERY_RESULT* Results, PVOID Context);
NTSTATUS SerialConfigCallBack(QUERY_RESULT* Results, PVOID Context);

// This is exported from the kernel.  It is used to point
// to the address that the kernel debugger is using.
extern "C"
{
    extern PUCHAR *KdComPortInUse;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
/*++
Routine Description:
    The entry point that the system point calls to initialize
    any driver.

    This routine will gather the configuration information,
    report resource usage, attempt to initialize all serial
    devices, connect to interrupts for ports.  If the above
    goes reasonably well it will fill in the dispatch points,
    reset the serial devices and then return to the system.

Arguments:
    DriverObject - Just what it says,  really of little use
    to the driver itself, it is something that the IO system
    cares more about.

    PathToRegistry - points to the entry for this driver
    in the current control set of the registry.

Return Value:
    STATUS_SUCCESS if we could initialize a single device,
    otherwise STATUS_SERIAL_NO_DEVICE_INITED.
--*/
{
    NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; 
    new KdSerialDriver(Status, DriverObject, RegistryPath); 
    
    if (!NT_SUCCESS(Status) && KdDriver::Driver())
        KdDriver::Driver()->Unload();
    return Status;
}

// Initialization of our driver.
KdSerialDriver::KdSerialDriver(NTSTATUS &Status, PDRIVER_OBJECT pDriverObject, PUNICODE_STRING puniRegistryPath):
    KdDriver(Status, pDriverObject, puniRegistryPath)
{
    if (!NT_SUCCESS(Status))
    {
        DebugDump(DBG_ERRORS , ("ERROR KdDriver::KdDriver() FAILED!\n") );
        return;
    }
    // Pointer to a device object in the device object chain
    // hanging off of the driver object.
    PKdSerialDevice pCurrentDevice;

    // Holds a pointer to a ulong that the Io system maintains
    // of the count of serial devices.
    PULONG countSoFar;

    // We use this to query into the registry as to whether we
    // should break at driver entry.
    KdRegistry Registry;
    ULONG debugLevel;
    ULONG shouldBreak;
    ULONG forceFifoEnableDefault;
    ULONG rxFIFODefault;
    ULONG txFIFODefault;
    ULONG permitShareDefault;
    ULONG logFifoDefault;
    ULONG notThereDefault = 1234567;

    // Since the registry path parameter is a "counted" UNICODE string, it
    // might not be zero terminated.  For a very short time allocate memory
    // to hold the registry path zero terminated so that we can use it to
    // delve into the registry.
    //
    // NOTE NOTE!!!! This is not an architected way of breaking into
    // a driver.  It happens to work for this driver because the author
    // likes to do things this way.

    if (!NT_SUCCESS(Registry.Init()))
    {
        shouldBreak = 0;
        debugLevel = 0;
    }
    else
    {
        Registry.QueryDWORD(L"BreakOnEntry", &shouldBreak);
        Registry.QueryDWORD(L"DebugLevel", &debugLevel);
        Registry.QueryDWORD(L"ForceFifoEnable", &forceFifoEnableDefault, notThereDefault);
        Registry.QueryDWORD(L"RxFIFO", &rxFIFODefault, notThereDefault);
        Registry.QueryDWORD(L"TxFIFO", &txFIFODefault, notThereDefault);
        Registry.QueryDWORD(L"PermitShare", &permitShareDefault, notThereDefault);
        Registry.QueryDWORD(L"LogFifo", &logFifoDefault, notThereDefault);
    }

    DriverDebugLevel = debugLevel;

    if (shouldBreak) 
        DbgBreakPoint();

    // Check to see if there was a forcefifo or an rxfifo size.
    // If there isn't then write out values so that they could
    // be adjusted later.

    if (forceFifoEnableDefault==notThereDefault) 
    {
        forceFifoEnableDefault = 1;
        Registry.SetDWORD(L"ForceFifoEnable", forceFifoEnableDefault);
    }
    if (rxFIFODefault==notThereDefault) 
    {
        rxFIFODefault = 8;
        Registry.SetDWORD(L"RxFIFO", rxFIFODefault);
    }
    if (txFIFODefault==notThereDefault) 
    {
        txFIFODefault = 1;
        Registry.SetDWORD(L"TxFIFO", txFIFODefault);
    }
    if (permitShareDefault==notThereDefault) 
    {
        permitShareDefault = 0;
        // Only share if the user actual changes switch.
        Registry.SetDWORD(L"PermitShare", permitShareDefault);
    }
    if (logFifoDefault==notThereDefault) 
    {
        // Wasn't there.  After this load don't log
        // the message anymore.  However this first
        // time log the message.
        Registry.SetDWORD(L"LogFifo", 0);
        logFifoDefault = 1;
    }

    // Just dump out how big the device is.
    DebugDump(DBG_DIAG1, ("The number of bytes in the device is: %d\n",
         sizeof(KdSerialDevice)) );

    countSoFar = &IoGetConfigurationInformation()->SerialCount;

    KdConfigList ConfigList(CONFIG_LIST_OFFSET);
    GetConfigInfo(
        forceFifoEnableDefault,
        rxFIFODefault,
        txFIFODefault,
        permitShareDefault,
        logFifoDefault,
        &ConfigList
        );

    // Initialize each item in the list of configuration records.

    while (!ConfigList.IsEmpty()) 
        InitializeRootInterrupt(ConfigList.RemoveHead());

    // We've initialized all of the hardware that this driver
    // will ever know about.  All of the hardware that we know
    // about is set up to NOT interrupt.  We now go through
    // all of the devices and connect an interrupt object for
    // all.

    pCurrentDevice = (PKdSerialDevice) GetFirstDevice();

    while (pCurrentDevice) 
    {
        // This loop will only connect the interrupt for the
        // "root" controller.  When we initialize a root controller
        // we then propagate that interrupt object to all associate
        // controllers.  If a device doesn't already have an interrupt
        // and it has an isr then we attempt to connect to the
        // interrupt.  Note that if we fail to connect to an interrupt
        // we will delete all of the associated devices.

        if ((!pCurrentDevice->m_KdInterrupt.IsConnected()) &&
            (pCurrentDevice->m_Isr.pFunction!=NULL)) 
        {
            DebugDump(DBG_DIAG5, ("About to connect to interrupt for port %ws\n"
                 "------- address of device is %x\n",
                 pCurrentDevice->DeviceName(), pCurrentDevice) );

            NTSTATUS status = pCurrentDevice->m_KdInterrupt.Connect(&pCurrentDevice->m_Isr);

            if (!NT_SUCCESS(status)) 
            {
                // Hmmm, how'd that happen?  Somebody either
                // didn't report their resources, or they
                // sneaked in since the last time I looked.
                //
                // Oh well,  delete this device as well as
                // any of the devices that were hoping to
                // share this interrupt.

                DebugDump(DBG_ERRORS, ("Couldn't connect to interrupt for %ws\n",
                     pCurrentDevice->DeviceName()));
                LogError(
                    1,
                    status,
                    SERIAL_UNREPORTED_IRQL_CONFLICT,
                    pCurrentDevice,
                    pCurrentDevice->m_OriginalController,
                    pCurrentDevice->m_sSymbolicLinkName
                    );

                delete pCurrentDevice;

                // The above call deleted all the associated
                // device objects.  Who knows what the device
                // list looks like now!  Start over from
                // the beginning of the device list.

                pCurrentDevice = (PKdSerialDevice) GetFirstDevice();
            } 
            else 
            {
                pCurrentDevice->PropagateDeleteSharers(countSoFar, pCurrentDevice->m_KdInterrupt);
                pCurrentDevice = (PKdSerialDevice) GetFirstDevice();
            }
        } 
        else 
        {
            // We've already done this device.  We can go on
            // to the next device.
            pCurrentDevice = (PKdSerialDevice)pCurrentDevice->GetNextDevice();
        }
    }

    // Well if we connected to any interrupts then we should
    // have some device objects.  Go through all of the devices
    // and reset each device.

    pCurrentDevice = (PKdSerialDevice) GetFirstDevice();

    while (pCurrentDevice) 
    {
        PKdSerialDevice pNextDevice = (PKdSerialDevice)pCurrentDevice->GetNextDevice();
        // While the device isn't open, disable all interrupts.
        DISABLE_ALL_INTERRUPTS(pCurrentDevice->m_pController);

        if (pCurrentDevice->m_Jensen) 
            pCurrentDevice->m_pController->WriteByte(MODEM_CONTROL_REGISTER, (UCHAR)SERIAL_MCR_OUT2);
        else 
            pCurrentDevice->m_pController->WriteByte(MODEM_CONTROL_REGISTER, (UCHAR)0);

        // This should set up everything as it should be when
        // a device is to be opened.  We do need to lower the
        // modem lines, and disable the stupid fifo so that it
        // will show up if the user boots to dos.

        pCurrentDevice->m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) pCurrentDevice->Reset);
        //Disables the fifo
        pCurrentDevice->m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) pCurrentDevice->MarkClose);
        pCurrentDevice->m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) pCurrentDevice->ClrRTS);
        pCurrentDevice->m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) pCurrentDevice->ClrDTR);

        pCurrentDevice = pNextDevice;
    }
    if (Driver()->GetFirstDevice())   // Cheack if that at least one device was created
        Status = STATUS_SUCCESS;
    else
        Status = STATUS_UNSUCCESSFUL;
}

VOID KdSerialDevice::PropagateDeleteSharers(PULONG CountSoFar, PKINTERRUPT Interrupt)
/*++
Routine Description:
    This routine will either propagate the interrupt object
    to all devices sharing the same interrupt, or it will
    delete all devices sharing the same interrupt.

Arguments:
    CountSoFar - If interrupt is present and this is present,
                 we will increment the longword pointed to
                 by this pointer for each device
                 we stick the interrupt into.

                 If interrupt is *not* present and this
                 pointer *is* present, we will decrement the
                 longword pointed to by this value for
                 each device we delete.

                 If this isn't present, well, then, I guess
                 we won't do anything with it.

    Interrupt - If this is present, we propagate it to
                all devices on that want to share the interrupt.
--*/
{
    ASSERT(m_Isr.pFunction!=NULL);

    DebugDump(DBG_DIAG3, ("In SerialPropagateDeleteSharers\n"
         "------- device: %x CountSoFar: %d Interrupt: %x\n",
         this, CountSoFar ? *CountSoFar : 0, Interrupt) );

    if (Interrupt) 
    {
        PLIST_ENTRY currentEntry;
        PLIST_ENTRY firstEntry;

        DebugDump(DBG_DIAG5, ("In the report propagate RegistryPath\n") );

        // Were supposed to place the interrupt object
        // in every associated device object.

        currentEntry = &m_CommonInterruptObject;
        firstEntry = currentEntry;

        do 
        {
            PKdSerialDevice pCurrentDevice;
            pCurrentDevice = CONTAINING_RECORD(currentEntry, KdSerialDevice, m_CommonInterruptObject);
            pCurrentDevice->m_KdInterrupt = m_KdInterrupt;

            if (CountSoFar) 
                *CountSoFar += 1;
            currentEntry = pCurrentDevice->m_CommonInterruptObject.Flink;
        } while (currentEntry != firstEntry);
        
        return;
    } 

    LIST_ENTRY listHead;
    // We are supposed to delete all of the devices in the linked list.
    //
    // First we make a local list head that doesn't have the current device as part of the list.
    // Then we cleanup and delete the "root" device.
    //
    // The we traverse all of the associated devices and null out the interrupt object
    // (this way subsequent cleanup code won't attempt to disconnect the interrupt object) then we
    // cleanup and delete the device.
    DebugDump(DBG_DIAG5, ("In the deletion/unreport RegistryPath\n") );

    InitializeListHead(&listHead);

    if (!IsListEmpty(&m_CommonInterruptObject)) 
    {
        PLIST_ENTRY old = m_CommonInterruptObject.Flink;

        RemoveEntryList(&m_CommonInterruptObject);
        InsertTailList(old, &listHead);
    }

    if (CountSoFar) 
        *CountSoFar -= 1;

    while (!IsListEmpty(&listHead)) 
    {
        PLIST_ENTRY head;
        PKdSerialDevice pCurrentDevice;
        head = RemoveHeadList(&listHead);
        pCurrentDevice = CONTAINING_RECORD(head, KdSerialDevice, m_CommonInterruptObject);

        if (CountSoFar) 
            *CountSoFar -= 1;
        delete pCurrentDevice;
    }
}

VOID KdSerialDriver::InitializeRootInterrupt(PCONFIG_DATA ConfigData)
/*++
Routine Description:
    This routine attempts to build a list suitable for dispatching
    to multiple devices for devices that want to share an interrupt.
    Note that this includes the degenerate case of a single port who

⌨️ 快捷键说明

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