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

📄 device.cpp

📁 pci 底层驱动
💻 CPP
📖 第 1 页 / 共 2 页
字号:
        if(p_irp_stack->Parameters.Power.State.DeviceState == PowerDeviceD3)
        {
            //Process the IRP
            PDEVICE_EXTENSION p_device_extension =
                GET_MINIDRIVER_DEVICE_EXTENSION(p_device_object);

            p_device_extension->p_device->powerDown();

            //Pass the IRP to the lower device            
            PoStartNextPowerIrp(p_irp);
            IoCopyCurrentIrpStackLocationToNext(p_irp);
            return PoCallDriver(GET_NEXT_DEVICE_OBJECT(p_device_object), p_irp); 
        }

        //If it's a power up, we pass it to the lower device first and
        // handle it in the completion routine. Power IRPs must be handled asynchronously
        else if (p_irp_stack->Parameters.Power.State.DeviceState == PowerDeviceD0)
        {
            PIO_STACK_LOCATION p_next_stack = IoGetNextIrpStackLocation(p_irp);
            //Copy the stack location to the next one
            RtlCopyMemory( 
                p_next_stack,
                p_irp_stack, 
                FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine));
            
            //Set the completion routing
            IoSetCompletionRoutine( 
                p_irp,
                Device::static_powerUpCompletion,
                NULL,                       // completion context
                TRUE,                       // call on success
                TRUE,                       // call on failure
                TRUE );                     // call on cancel
          
            //Pass it to the lower device
            return PoCallDriver(GET_NEXT_DEVICE_OBJECT(p_device_object), p_irp); 
        }
    }

    //We didn't handle it.  Pass it down.
    PoStartNextPowerIrp(p_irp);
    IoCopyCurrentIrpStackLocationToNext(p_irp);
    return PoCallDriver(GET_NEXT_DEVICE_OBJECT(p_device_object), p_irp); 
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_powerUpCompletion
//
// This is the completion routine for static_power() when we receive a request to set the 
// power to PowerDeviceD0 (powered on.) This routine should process the IRP, and then 
// return the IRP's status.
//
NTSTATUS Device::static_powerUpCompletion(
                                  PDEVICE_OBJECT p_device_object,
                                  IN PIRP        p_irp,
                                  IN PVOID       p_context)
{
    //Get the device extension
    PDEVICE_EXTENSION p_device_extension = 
        GET_MINIDRIVER_DEVICE_EXTENSION(p_device_object);

    p_device_extension->p_device->powerUp();

    PoStartNextPowerIrp(p_irp);
    return p_irp->IoStatus.Status;
}


/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_internalDeviceControl
//
// This is the DDK entry point for IRP_MJ_INTERNAL_DEVICE_CONTROL.  We simply call
// the non-static Device::internalDeviceControl here.
//
NTSTATUS Device::static_internalDeviceControl(
                                             PDEVICE_OBJECT p_device_object,
                                             PIRP           p_irp)
{
    PDEVICE_EXTENSION deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(p_device_object);

    if(deviceExtension->p_device)
    {
        return deviceExtension->p_device->internalDeviceControl(p_irp);
    }

    //No device object.  Fail the IRP.
    p_irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
    IoCompleteRequest(p_irp, IO_NO_INCREMENT);
    return STATUS_NO_SUCH_DEVICE;
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::internalDeviceControl
//
// This is the handler for IRP_MJ_INTERNAL_DEVICE_CONTROL.  For an HID mini-driver, the 
// only IRPs received here are HID commands.  We do HID processing in class HidProcessing.
// That class handles filling in the correct HID descriptors, and queuing, cancelling, and 
// completing report requests.
// 
// Note that we do not send it report requests if the device is not running. We do allow
// it to send back HID descriptors when the device is not started, however.
//

NTSTATUS Device::internalDeviceControl(PIRP p_irp)
{
    if(_device_state == DEVICE_STATE_RUNNING)
    {
        //All internal device control requests are HID requests and should be processed by
        //HID class
        return _hid.processHidIoctl(p_irp);
    }
    else
    {
        //Don't send IRPs to HID if we aren't running

        p_irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
        IoCompleteRequest(p_irp, IO_NO_INCREMENT);
        return STATUS_NO_SUCH_DEVICE;
    }
}


/////////////////////////////////////////////////////////////////////////////////////////
//Device::passIrpDownSync
//
// This is a typical synchronous IRP calldown function.  
//
// As is usual, the idea is to create an event that may be signalled when the IRP completes.
// Then pass the IRP down and wait on the event.  This is done by setting a stub completion
// routine on the IRP and passing it a pointer to the IRP as context.  
//
// Our completion routine is static_syncIrpCompletion()
//
// The completion routine returns STATUS_MORE_PROCESSING_REQUIRED which means that we can
// still touch the IRP when it comes back, but that we need to call IoCompleteRequest when
// we are done with it. 
//
// Note that this is not the case if the IRP fails.  In this case, we complete the IRP
// and return the failure status. 
//
// THE USER MAY ONLY TOUCH THE IRP AFTER CALLING THIS ROUTINE IF IT RETURNS STATUS_SUCCESS.
//

NTSTATUS Device::passIrpDownSync(PIRP p_irp)
{
    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

    PIO_STACK_LOCATION current_stack = IoGetCurrentIrpStackLocation(p_irp);
    PIO_STACK_LOCATION next_stack = IoGetNextIrpStackLocation(p_irp);
    ASSERT(next_stack != NULL);

    //Copy the stack location to the next one
    RtlCopyMemory( 
        next_stack,
        current_stack, 
        FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine));
    
    //An event to wait on for when the IRP completes
    KEVENT wait_event;
    KeInitializeEvent( 
        &wait_event,
        NotificationEvent,
        TRUE );

    //Set the completion routing
    IoSetCompletionRoutine( 
        p_irp,
        Device::static_syncIrpCompletion,
        &wait_event,                // completion context
        TRUE,                       // call on success
        TRUE,                       // call on failure
        TRUE );                     // call on cancel

    
    NTSTATUS status = IoCallDriver(GET_NEXT_DEVICE_OBJECT(_p_device_object), p_irp);
    
    if(status == STATUS_PENDING)
    {
        //Wait for the completion routine to signal the event.
        KeWaitForSingleObject(
            &wait_event,
            Executive,
            KernelMode,
            TRUE,
            NULL);
        
        status = p_irp->IoStatus.Status;
    }

    if(!NT_SUCCESS(status))
    {
        IoCompleteRequest(p_irp, IO_NO_INCREMENT);
    }

    return status;
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_syncIrpCompletion
//
// This is the completion routine for passIrpDownSync(), and signals the event to let 
// passIrpSync() know that the IRP is complete.
//
NTSTATUS Device::static_syncIrpCompletion(
                                  PDEVICE_OBJECT p_device_object,
                                  IN PIRP        p_irp,
                                  IN PVOID       p_context)
{
    PKEVENT p_event = (PKEVENT) p_context;

    KeSetEvent(p_event, 0, FALSE );
    return STATUS_MORE_PROCESSING_REQUIRED;
}

/////////////////////////////////////////////////////////////////////////////////////////
//Device::getResources
//
// This is a private helper routine that gets the partial resource descriptors for our 
// memory range and interrupt object from the start device IRP.
//
// *p_memory and *p_interrupt should be set to NULL before calling this.  They will remain
// NULL if ther resource was not found.
//

VOID Device::getResources(             
                  PIRP p_irp,
                  PCM_PARTIAL_RESOURCE_DESCRIPTOR* p_memory,
                  PCM_PARTIAL_RESOURCE_DESCRIPTOR* p_interrupt)
{
    PIO_STACK_LOCATION p_irp_stack = IoGetCurrentIrpStackLocation(p_irp);

    PCM_PARTIAL_RESOURCE_DESCRIPTOR p_partial_raw = 
        p_irp_stack->Parameters.StartDevice.AllocatedResources->List->PartialResourceList.PartialDescriptors;

    PCM_PARTIAL_RESOURCE_DESCRIPTOR p_partial_translated = 
        p_irp_stack->Parameters.StartDevice.AllocatedResourcesTranslated->List->PartialResourceList.PartialDescriptors;
   
    ULONG resource_count =     
        p_irp_stack->Parameters.StartDevice.AllocatedResources->List->PartialResourceList.Count;

    for (USHORT j = 0; j <  resource_count; j++)		
    {
        switch(p_partial_raw->Type)
        {
        case CmResourceTypeMemory:
            //Found our memory resource.  There should only be one.
            ASSERT(*p_memory == NULL);   
            *p_memory = p_partial_translated;
            break;
        case CmResourceTypeInterrupt:
            //Found our interrupt resource.  There should only be one
            ASSERT(*p_interrupt == NULL);
            *p_interrupt = p_partial_translated;
            break;
        default:
            //Do nothing if there are any other resources in the list.
            // There should not be any.
            break;
        }
        
        p_partial_raw++;
        p_partial_translated++;
    }
}


/////////////////////////////////////////////////////////////////////////////////////////
//Adapter::readRegistryDword
//
// Read a DWORD value from the device's "DriverData" registry key.
//
// Parameters
//  name - Name of the DWORD to read
//
//  p_value - Receives the DWORD value.  Remains unchanged if the value didn't exist.
//
// The expected usage is to set the value to it's default, and then call this function
// that will override the default if the registry value exists.
//
VOID 
Device::readRegistryDword(PCHAR name, PDWORD p_value)
{
    HANDLE key_handle = openDriverKey(KEY_READ);
    
    if(key_handle)
    {
        UNICODE_STRING key_name;
        ANSI_STRING  a_key_name;
        
        RtlInitAnsiString(&a_key_name, name);
        if(NT_SUCCESS(RtlAnsiStringToUnicodeString(&key_name, &a_key_name, TRUE)))
        {
            DWORD buffer;
            if(NT_SUCCESS(getRegistryValue(key_handle, &key_name, (PCHAR)&buffer, sizeof(buffer))))
            {
                *p_value  = buffer;
            }
            RtlFreeUnicodeString( &key_name );
        }

        ZwClose(key_handle);
    }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Adapter::openDriverKey
//
// This is a private helper function that opens the driver's registry key.
//
// Parameters
//     desired_access - KEY_READ, KEY_WRITE, etc.
//
HANDLE 
Device::openDriverKey(ACCESS_MASK desired_access)
{
    HANDLE dev_handle = NULL;
    
    NTSTATUS status = IoOpenDeviceRegistryKey(
        GET_PDO(_p_device_object), 
        PLUGPLAY_REGKEY_DRIVER,
        STANDARD_RIGHTS_ALL, 
        &dev_handle);
    
    HANDLE key_handle = NULL;
    if (NT_SUCCESS(status)) 
    {
        OBJECT_ATTRIBUTES attr;
        UNICODE_STRING dev_data_name;
        PWCHAR data_name = L"DriverData";
        
        RtlInitUnicodeString(&dev_data_name, data_name);
        InitializeObjectAttributes(
            &attr, 
            &dev_data_name, 
            OBJ_INHERIT, 
            dev_handle,
            NULL);
        
        if(!NT_SUCCESS(ZwOpenKey(&key_handle, desired_access, &attr)))
        {
            dbgLogInfo(("OpenDriverKey: ZwOpenKey failed!"));
        }
        if (!NT_SUCCESS(ZwClose(dev_handle)))
        {
            dbgLogInfo(("OpenDriverKey: ZwClose failed!"));
        }
    }
    return key_handle;
}

/////////////////////////////////////////////////////////////////////////////////////////
//Adapter::getRegistryValue
//
// A private helper function for retreiving values from the registry.
//
// Parameters
//  handle - Handle to the registry key
//  key_name - Actually the value name
//  data  - buffer to receive the registry data
//  data_length - length of data buffer
//
NTSTATUS 
Device::getRegistryValue(
                          HANDLE handle,
                          const PUNICODE_STRING key_name,
                          PCHAR data, 
                          ULONG data_length)
{
    NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
    
    ULONG length = sizeof( KEY_VALUE_FULL_INFORMATION ) + data_length + key_name->MaximumLength;
    
    PKEY_VALUE_FULL_INFORMATION full_info = (struct _KEY_VALUE_FULL_INFORMATION *)ExAllocatePool(PagedPool, length);
    
    if (full_info) 
    {
        status = ZwQueryValueKey(
            handle,
            key_name, 
            KeyValueFullInformation,
            full_info,
            length, 
            &length);
        
        if (NT_SUCCESS(status)) 
        {
            if (data_length >= full_info->DataLength ) {
                RtlCopyMemory(
                    data, 
                    ((PUCHAR) full_info) + full_info->DataOffset,
                    full_info->DataLength );
                
            } 
            else 
            {
                status = STATUS_BUFFER_TOO_SMALL;
            }                   // buffer right length
        }                       // if success
        ExFreePool(full_info);
    }                           // if fullinfo
    return status;
}


VOID Device::powerDown()
{
    //Notify _p_ir_control to uninitialize so the device stops interrupting.
    if(_p_ir_control)
    {
        _p_ir_control->uninitialize();
    }

    //Save the power state
    _power_state = PowerDeviceD3;
}

VOID Device::powerUp()
{
    //Re-initialize IR_Control since the registers get reset when we power down.
    if(_p_ir_control)
    {
        _p_ir_control->initialize();
    }

    //Save the power state
    _power_state = PowerDeviceD0;
}

⌨️ 快捷键说明

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