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

📄 device.cpp

📁 pci 底层驱动
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
//  File:   device.cpp
//  Description: The implementation of class Device
//
//  Created:  Wed. Jan 15, 2003
//
//
// Copyright and Disclaimer:
//
//   ---------------------------------------------------------------
//   THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
//   EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//   PARTICULAR PURPOSE.
//
//   IN NO EVENT SHALL CONEXANT BE LIABLE TO ANY PARTY FOR DIRECT,
//   INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
//   INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
//   AND ITS DOCUMENTATION, EVEN IF CONEXANT HAS BEEN ADVISED OF THE
//   POSSIBILITY OF SUCH DAMAGE.
//
//   Copyright (c) 2000-2001 Conexant Systems, Inc.
//
//   All Rights Reserved.
//   ---------------------------------------------------------------
//
// Module Revision Id:
//
//

#include "common.h"
#include "device.h"

/////////////////////////////////////////////////////////////////////////////////////////
//Device::Device (constructor)
//
// This just initializes the member variables.  Most of the real initialization is done 
// when we receive IRP_MN_START_DEVICE (Device::start)
//
Device::Device(PDEVICE_OBJECT p_device_object):
_device_state(DEVICE_STATE_NOT_STARTED),
_p_interrupt(NULL),
_p_ir_control(NULL),
_p_registers(NULL),
_p_device_object(p_device_object),
_power_state(PowerDeviceD0)  //Always start out powered up
{
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::~Device (destructor)
//
// Clean up things initialized if the device was started.
//
Device::~Device()
{
    ULONG old_device_state = _device_state;
    _device_state = DEVICE_STATE_REMOVING;

    // Cancel any outstanding IRPs if the device was running
    if(old_device_state == DEVICE_STATE_RUNNING)
    {
        releaseResources();
    }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_add
//
// This is the AddDevice DDK entry point.  The purpose of this function is to allocate 
// a new Device object.  The pointer to the device is stored in the device extension.
//
// The object is deleted when IRP_MN_REMOVE_DEVICE is received.  
//
// The system calls the AddDevice handler when it detects a new device which the driver
// is supposed to handle.  We are not supposed to touch the device until after it 
// sends IRP_MN_START_DEVICE, handled by Device::start().  That is where most device 
// initialization is done.
//
NTSTATUS Device::static_add(
        PDRIVER_OBJECT p_driver_object,
        PDEVICE_OBJECT p_device_object)
{
    dbgLogInfo(("Device::static_add\n"));

    PDEVICE_EXTENSION deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(p_device_object);

    deviceExtension->p_device = new Device(p_device_object);
    if(!deviceExtension->p_device)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    return STATUS_SUCCESS;
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_pnp
//
// This is the DDK entry point for IRP_MJ_PNP.  In general, this function will call some
// non-static member of Device based on the minor function of the IRP.
//
// The exception is IRP_MN_REMOVE_DEVICE where we must delete the Device object.  So the 
// destructor is the remove handler.
//
// The driver currently only handles IRP_MN_START_DEVICE, IRP_MN_STOP_DEVICE and 
//  IRP_MN_REMOVE_DEVICE
//
NTSTATUS Device::static_pnp(
                           PDEVICE_OBJECT p_device_object,
                           PIRP           p_irp)
{
    // Get a pointer to the device extension
    PDEVICE_EXTENSION p_device_extension = GET_MINIDRIVER_DEVICE_EXTENSION(p_device_object);

    //If there's no device, it must have already been removed.  Fail the IRP.
    if(!p_device_extension->p_device)
    {
        p_irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
        IoCompleteRequest(p_irp, IO_NO_INCREMENT);
        return STATUS_NO_SUCH_DEVICE;
    }

    // Get a pointer to the current location in the Irp
    PIO_STACK_LOCATION p_irp_stack = IoGetCurrentIrpStackLocation(p_irp);
    NTSTATUS status = STATUS_SUCCESS;

    switch (p_irp_stack->MinorFunction)
    {
    case IRP_MN_START_DEVICE:
        status = p_device_extension->p_device->start(p_irp);
        break;

    case IRP_MN_STOP_DEVICE:
        dbgLogTrace(("IRP_MN_STOP_DEVICE\n"));
        status = p_device_extension->p_device->stop(p_irp);
        break;

    case IRP_MN_REMOVE_DEVICE:
        delete p_device_extension->p_device;
        p_device_extension->p_device = NULL;

        status = static_passIrpDown(
            GET_NEXT_DEVICE_OBJECT(p_device_object),
            p_irp);

        break;

    default:
        //If we don't handle the IRP just pass it down to the lower device
        dbgLogTrace(("Unknown PNP IRP Parameter (%lx)\n", p_irp_stack->MinorFunction));

        status = static_passIrpDown(
            GET_NEXT_DEVICE_OBJECT(p_device_object),
            p_irp);
        break;
    }

    dbgLogInfo(("HidMiniPlugnPlay Exit = %x\n", status));

    return status;

}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_passIrpDown
//
// This function passes an IRP down to the next lower device object.  The static version 
// is there for those static functions that might need to pass an IRP down outside of the 
// Device class.  (For instance, we need to pass on the IRP_MN_REMOVE_DEVICE IRP after 
// we delete the Device object.
//
// Most users should use the non-static version of this function.
//
NTSTATUS 
Device::static_passIrpDown(PDEVICE_OBJECT p_lower_device, PIRP p_irp)
{
    IoSkipCurrentIrpStackLocation(p_irp);
    return IoCallDriver(p_lower_device, p_irp);   
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::start
//
// This is the handler for IRP_MJ_PNP, IRP_MN_START_DEVICE.  This is the main IRP for 
// device initialization.  We receive our hardware resources here.  
//
// The start IRP should always be passed down to the lower device first to give it a 
// chance to start the hardware before we try to access it.  
//
// Most of our initialization is done in the init() function, an internal helper function 
// called after the start IRP has been processed by the lower device.
//

NTSTATUS Device::start(PIRP p_irp)
{
    _device_state = DEVICE_STATE_STARTING; 

    //First pass the IRP down to the lower device
    NTSTATUS status = passIrpDownSync(p_irp);
    if(!NT_SUCCESS(status))
    {
        return status;
    }

    status = init(p_irp);

    if (NT_SUCCESS(status))
    {
        dbgLogTrace(("Device was configured!\n"));
        _device_state = DEVICE_STATE_RUNNING; 
    }
    else
    {
        dbgLogError(("Device configuration failed!\n"));
        _device_state = DEVICE_STATE_NOT_STARTED;
    }

    p_irp->IoStatus.Status = status;
    IoCompleteRequest(p_irp, IO_NO_INCREMENT);

    return status;
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::init
//
// This is where we do most of the device initialization.  This is called from 
// Device::start after it passes the IRP down to the lower device.
//
// This function does the following:
// 1) Get hardware resources from the IRP.  
// 2) Allocate the registers object using the memory range
// 3) Allocate the IR_Control object.  This object needs access to the registers object, 
//    and will handle any interrupts generated, so it should be allocated before
//    connecting the interrupt.
// 4) Connect the interrupt.
//
// If the return status is a failure, none of these things were done.  So, we need to 
// clean up in the destructor only if the device was successfully started.
//
NTSTATUS Device::init(PIRP p_irp)
{
    NTSTATUS status = STATUS_SUCCESS;

    //Get our hardware resources
    PCM_PARTIAL_RESOURCE_DESCRIPTOR p_memory = NULL;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR p_interrupt = NULL;
    
    getResources(p_irp, &p_memory, &p_interrupt);
    
    if(!p_memory || !p_interrupt)
    {
        dbgLogError(("Problem getting device resources"));
        status = STATUS_DEVICE_CONFIGURATION_ERROR;
    }   

    //Initialize the memory range and registers object
    if(NT_SUCCESS(status))
    {
        //Map the memory range to a virtual address
        PBYTE p_memory_base = (PBYTE) MmMapIoSpace(
            p_memory->u.Memory.Start, 
            p_memory->u.Memory.Length,
            MmNonCached);
        
        //Initialize the RegisterIo object
        if(p_memory_base)
        {
            _p_registers = new RegisterIo(p_memory_base);
        }
        
        //Oops, allocation failed
        if(!_p_registers)
        {
            //We couldn't allocate memory for the registers
            dbgLogError(("Could not allocate memory for register object\n"));
            status = STATUS_INSUFFICIENT_RESOURCES;
        }
        
    }

    //Initialize the IR_Control object 
    if(NT_SUCCESS(status))
    {
        //Read the value of the IR standard to use from the the registry
        DWORD standard = (DWORD)IR_STANDARD_RC5;
        readRegistryDword("IR_Standard", &standard);

        DWORD table = 0;
        readRegistryDword("IR_Command_table", &table);

        _p_ir_control = new IR_Control(_p_registers, &_hid, (IR_STANDARD)standard, table);
        
        if(!_p_ir_control)
        {
            dbgLogError(("Could not allocate memory for IR Control object\n"));
            status = STATUS_INSUFFICIENT_RESOURCES;
        }
    }

    //Connect the interrupt
    if(NT_SUCCESS(status))
    {
        status =   IoConnectInterrupt(
            &_p_interrupt,                          //Interrupt object
            (PKSERVICE_ROUTINE) static_interruptRoutine,   //ISR
            this,                                   //context
            NULL,                                   //spinlock
            p_interrupt->u.Interrupt.Vector,        //vector
            (KIRQL) p_interrupt->u.Interrupt.Level, //IRQL
            (KIRQL) p_interrupt->u.Interrupt.Level, //Synchronize IRQL    
            (p_interrupt->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive, 
            TRUE,                                   //Shared                
            p_interrupt->u.Interrupt.Affinity,      
            FALSE);                                 //Floating save - must be false                        
        
        if(!NT_SUCCESS(status))
        {
            dbgLogError(("Error connecting interrupt\n"));
        }
        else
        {
            //This actually enables interrupts on the device.
            _p_ir_control->initialize();
        }
    }

    //Something failed.  Clean up.
    if(!NT_SUCCESS(status))
    {
        delete _p_ir_control;
        delete _p_registers;

        _p_registers = NULL;
        _p_ir_control = NULL;
     }
     
     return status;
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::stop
//
// This is the handler for IRP_MJ_PNP, IRP_MN_STOP.  Note that IRP_MN_REMOVE is a better
// indication of when the device is going away.  IRP_MN_STOP usually is not called before
// IRP_MN_REMOVE.
//
// Anyway, we mark the device state as stopped so that we do not queue any further read 
// report requests. We also release all of our hardware resources.
//
// Processing should be done before passing the IRP to the lower device.
//

NTSTATUS Device::stop(PIRP p_irp)
{
    _device_state = DEVICE_STATE_STOPPING;

    //We should release any system resources here
    releaseResources();

    //Cancel any pending requests in the HID class
    _hid.cancelOutstandingRequests();

    NTSTATUS status = passIrpDownSync(p_irp);
    if(!NT_SUCCESS(status))
    {
        return status;
    }

    _device_state = DEVICE_STATE_STOPPED;

    p_irp->IoStatus.Status = status;
    IoCompleteRequest(p_irp, IO_NO_INCREMENT);

    return status;
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_interruptRoutine
//
// This is the interrupt handler, connected to the interrupt in Device::init.  Currently,
// all interrupts are generated and handled by the IR_Control class, so we just call the
// IR_Control class with the interrupt.
//
// Since the interrupt is only connected when the IR_Control class is allocated, there 
// should never be a problem of the pointer being NULL.
//
BOOLEAN Device::static_interruptRoutine(
        PKINTERRUPT interrupt,
        PVOID p_context)
{
    Device* p_device = (Device*) p_context;
    
    if(!p_device || !p_device->_p_ir_control)
    {
        //Should never get here. . .
        return FALSE;
    }

    //Don't try to handle the interrupt if we aren't powered up.
    if(p_device->_power_state == PowerDeviceD3)
    {
        return FALSE;
    }

    return p_device->_p_ir_control->interruptHandler();
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_power
//
// This is the DDK entry point for power IRPs.  Since we are not the power manager for the
// device, we just pass them through to the lower device.
//
// TODO: intercept the power up and down messages so that we can restore the state correctly
// after a hibernate.
//

NTSTATUS Device::static_power(
                             PDEVICE_OBJECT p_device_object,
                             PIRP           p_irp)
{
    //Check for a device set power IRP.  These are the only type we process
    PIO_STACK_LOCATION p_irp_stack = IoGetCurrentIrpStackLocation(p_irp);
    if((p_irp_stack->MinorFunction == IRP_MN_SET_POWER) &&
        (p_irp_stack->Parameters.Power.Type == DevicePowerState))
    {
        //If it's a power down, we should handle it first, and then pass it to the lower
        // device.  

⌨️ 快捷键说明

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