Sample Code

Windows Driver Samples/ Fakemodem Driver/ C++/ driver.c/

/*++

Copyright (c) Microsoft Corporation.  All rights reserved.

    THIS CODE AND INFORMATION 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.

Module Name:

    Driver.c

Abstract:

    This is a simple form of function driver for fakemodem device. The driver
    doesn't handle any PnP and Power events because the framework provides
    default behaviour for those events. This driver has enough support to
    allow an user application (toast/notify.exe) to open the device
    interface registered by the driver and send read, write or ioctl requests.

Environment:

    Kernel mode

--*/

#include "fakemodem.h"

#ifdef ALLOC_PRAGMA
    #pragma alloc_text (INIT, DriverEntry)
    #pragma alloc_text (PAGE, FmEvtDeviceAdd)
    #pragma alloc_text (PAGE, FmCreateDosDevicesSymbolicLink)
    #pragma alloc_text (PAGE, FmDeviceCleanup)
#endif


NTSTATUS
DriverEntry(
           IN PDRIVER_OBJECT  DriverObject,
           IN PUNICODE_STRING RegistryPath
           )
/*++

Routine Description:
    DriverEntry initializes the driver and is the first routine called by the
    system after the driver is loaded. DriverEntry specifies the other entry
    points in the function driver, such as FmAddDevice and FmUnload.

Parameters Description:

    DriverObject - represents the instance of the function driver that is loaded
    into memory. DriverEntry must initialize members of DriverObject before it
    returns to the caller. DriverObject is allocated by the system before the
    driver is loaded, and it is released by the system after the system unloads
    the function driver from memory.

    RegistryPath - represents the driver specific path in the Registry.
    The function driver can use the path to store driver related data between
    reboots. The path does not store hardware instance specific data.

Return Value:

    STATUS_SUCCESS if successful,
    STATUS_UNSUCCESSFUL otherwise.

--*/
{
    NTSTATUS            status = STATUS_SUCCESS;
    WDF_DRIVER_CONFIG   config;

    KdPrint(("Fakemode Function Driver Sample - Driver Framework Edition.\n"));
    KdPrint(("Built %s %s\n", __DATE__, __TIME__));

    WDF_DRIVER_CONFIG_INIT( &config, FmEvtDeviceAdd );

    //
    // Create a framework driver object to represent our driver.
    //
    status = WdfDriverCreate(
                            DriverObject,
                            RegistryPath,
                            WDF_NO_OBJECT_ATTRIBUTES,
                            &config,          // Driver Config Info
                            WDF_NO_HANDLE
                            );

    if (!NT_SUCCESS(status)) {
        KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status));
    }

    return status;
}


NTSTATUS
FmEvtDeviceAdd(
              IN WDFDRIVER       Driver,
              IN PWDFDEVICE_INIT DeviceInit
              )
/*++
Routine Description:

    FmEvtDeviceAdd is called by the framework in response to AddDevice
    call from the PnP manager. We create and initialize a device object to
    represent a new instance of Fm device.

Arguments:

    Driver - Handle to a framework driver object created in DriverEntry

    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS                    status = STATUS_SUCCESS;
    PFM_DEVICE_DATA             fmDeviceData;
    WDF_IO_QUEUE_CONFIG         queueConfig;
    WDF_OBJECT_ATTRIBUTES       fdoAttributes;
    WDFDEVICE                   hDevice;
    WDFQUEUE                    defQueue;

    UNREFERENCED_PARAMETER(Driver);

    KdPrint( ("FmEvtDeviceAdd routine \n"));

    PAGED_CODE();

    //
    // Modem type is serial port.
    //
    WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SERIAL_PORT);

    //
    // Use Buffered IO.
    //
    WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered);

    //
    // Specify the size of device extension where we track per device
    // context.
    //
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FM_DEVICE_DATA);
    //
    // Register a cleanup callback on the device to free up some resources at the
    // time the device is deleted.
    //
    fdoAttributes.EvtCleanupCallback = FmDeviceCleanup;
    //
    // By opting for SynchronizationScopeDevice, we tell the framework to
    // synchronize callbacks events of all the objects directly associated
    // with the device. In this driver, we will associate queues.
    // By doing that we don't have to worrry about synchronizing
    // access to device-context by various io Events.
    // Framework will serialize them by using an internal device-lock.
    //
    fdoAttributes.SynchronizationScope = WdfSynchronizationScopeDevice;
    //
    // Create a framework device object.This call will inturn create
    // a WDM deviceobject, attach to the lower stack and set the
    // appropriate flags and attributes.
    //

    status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &hDevice);

    if (!NT_SUCCESS(status)) {
        KdPrint( ("WdfDeviceCreate failed with Status code 0x%x\n", status));
        return status;
    }

    //
    // Get the DeviceExtension and initialize it.
    //
    fmDeviceData = FmDeviceDataGet(hDevice);

    //
    // Tell the Framework that this device will need an interface
    //
    status = WdfDeviceCreateDeviceInterface(
                                           hDevice,
                                           (LPGUID) &GUID_DEVINTERFACE_MODEM,
                                           NULL
                                           );

    if (!NT_SUCCESS (status)) {
        KdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status));
        return status;
    }

    fmDeviceData->Flags = 0;
    status = FmCreateDosDevicesSymbolicLink(hDevice, fmDeviceData);

    if (!NT_SUCCESS(status)) {
        KdPrint( ("FmCreateDosDevicesSymbolicLink failed with Status code 0x%x\n", status));
        return status;
    }

    //
    // Initialize the context
    //
    fmDeviceData->BaudRate=1200;
    fmDeviceData->LineControl = SERIAL_7_DATA |  SERIAL_EVEN_PARITY | SERIAL_NONE_PARITY;

    //
    // Register I/O callbacks to tell the framework that you are interested
    // in handling IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests.
    // In case a specific handler is not specified for one of these,
    // the request will be dispatched to the EvtIoDefault handler, if any.
    // If there is no EvtIoDefault handler, the request will be failed with
    // STATUS_INVALID_DEVICE_REQUEST.
    // WdfIoQueueDispatchParallel means that we are capable of handling
    // all the I/O request simultaneously and we are responsible for protecting
    // data that could be accessed by these callbacks simultaneously.
    //

    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig,
                                           WdfIoQueueDispatchParallel);

    queueConfig.EvtIoRead = FmEvtIoRead;
    queueConfig.EvtIoWrite = FmEvtIoWrite;
    queueConfig.EvtIoDeviceControl = FmEvtIoDeviceControl;

    __analysis_assume(queueConfig.EvtIoStop != 0);
    status = WdfIoQueueCreate(
                             hDevice,
                             &queueConfig,
                             WDF_NO_OBJECT_ATTRIBUTES,
                             &defQueue // pointer to default queue
                             );
    __analysis_assume(queueConfig.EvtIoStop == 0);
	
    if (!NT_SUCCESS (status)) {

        //
        // We don't need to cleanup symbolic link here. The destroy callback for
        // the device object will do it.
        //
        return status;
    }

    //
    // Create a manual queue to hold pending read requests. By keeping
    // them in the queue, framework takes care of cancelling them if the app exits
    //
    WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,
                             WdfIoQueueDispatchManual);

    __analysis_assume(queueConfig.EvtIoStop != 0);
    status = WdfIoQueueCreate(hDevice,
                              &queueConfig,
                              WDF_NO_OBJECT_ATTRIBUTES,
                              &fmDeviceData->FmReadQueue
                             );
    __analysis_assume(queueConfig.EvtIoStop == 0);
	
    if (!NT_SUCCESS (status)) {
        KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status));
        return status;
    }

    //
    // Create a manual queue to hold pending ioctl wait mask requests. By keeping
    // them in the queue, framework takes care of cancelling them if the app exits
    //
    WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,
                             WdfIoQueueDispatchManual);

    __analysis_assume(queueConfig.EvtIoStop != 0);
    status = WdfIoQueueCreate(hDevice,
                              &queueConfig,
                              WDF_NO_OBJECT_ATTRIBUTES,
                              &fmDeviceData->FmMaskWaitQueue
                             );
    __analysis_assume(queueConfig.EvtIoStop == 0);
	
    if (!NT_SUCCESS (status)) {
        KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status));
        return status;
    }

    return status;
}


VOID
FmDeviceCleanup(
               WDFOBJECT Device
               )
/*++
Routine Description:

    This event is called when the device object is destroyed.
    Cleanup any associated data.

Arguments:

Return Value:

   VOID

--*/
{
    PFM_DEVICE_DATA   fmData;

    PAGED_CODE();

    fmData = FmDeviceDataGet((WDFDEVICE)Device);

    if (fmData->Flags & REG_VALUE_CREATED_FLAG) {
        RtlDeleteRegistryValue(
                              RTL_REGISTRY_DEVICEMAP,
                              L"SERIALCOMM",
                              fmData->PdoName.Buffer
                              );
    }
}

NTSTATUS
FmCreateDosDevicesSymbolicLink(
                              WDFDEVICE       Device,
                              PFM_DEVICE_DATA FmDeviceData
                              )
{
    NTSTATUS        status;
    UNICODE_STRING  comPort;
    UNICODE_STRING  pdoName;
    UNICODE_STRING  symbolicLink;
    WDFKEY          hKey = NULL;
    DECLARE_CONST_UNICODE_STRING(valueName, L"PortName");
    WDFSTRING       string = NULL;
    WDFMEMORY       memory;
    WDF_OBJECT_ATTRIBUTES  memoryAttributes;
    size_t          bufferLength;


    PAGED_CODE();

    symbolicLink.Buffer = NULL;

    //
    // Open the device registry and read the "PortName" value written by the
    // class installer.
    //
    status = WdfDeviceOpenRegistryKey(Device,
                                      PLUGPLAY_REGKEY_DEVICE,
                                      STANDARD_RIGHTS_ALL,
                                      NULL, // PWDF_OBJECT_ATTRIBUTES
                                      &hKey);

    if (!NT_SUCCESS (status)) {
        goto Error;
    }
    status = WdfStringCreate(
                            NULL,
                            WDF_NO_OBJECT_ATTRIBUTES ,
                            &string
                            );

    if (!NT_SUCCESS(status)) {
        goto Error;
    }

    //
    // Retrieve the value of ValueName from registry
    //
    status = WdfRegistryQueryString(
                                   hKey,
                                   &valueName,
                                   string
                                   );


    if (!NT_SUCCESS (status)) {
        goto Error;
    }

    //
    // Retrieve the UNICODE_STRING from string object
    //
    WdfStringGetUnicodeString(
                             string,
                             &comPort
                             );

    WdfRegistryClose(hKey);
    hKey = NULL;

    symbolicLink.Length=0;
    symbolicLink.MaximumLength = sizeof(OBJECT_DIRECTORY) + comPort.MaximumLength;

    symbolicLink.Buffer = ExAllocatePoolWithTag(PagedPool,
                                                symbolicLink.MaximumLength + sizeof(WCHAR),
                                                'wkaF');

    if (symbolicLink.Buffer == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto Error;
    }
    RtlZeroMemory(symbolicLink.Buffer, symbolicLink.MaximumLength);
    RtlAppendUnicodeToString(&symbolicLink, OBJECT_DIRECTORY);
    RtlAppendUnicodeStringToString(&symbolicLink, &comPort);
    //
    // This DDI will get the underlying PDO name and create a symbolic to that
    // because our FDO doesn't have a name.
    //
    status = WdfDeviceCreateSymbolicLink(Device,
                                         &symbolicLink);

    if (!NT_SUCCESS(status)) {
        goto Error;
    }

    WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
    memoryAttributes.ParentObject = Device;

    status = WdfDeviceAllocAndQueryProperty(Device,
                                            DevicePropertyPhysicalDeviceObjectName,
                                            PagedPool,
                                            &memoryAttributes,
                                            &memory);
    if (!NT_SUCCESS(status)) {
        //
        // We expect a zero length buffer. Anything else is fatal.
        //
        goto Error;
    }

    pdoName.Buffer = WdfMemoryGetBuffer(memory, &bufferLength);

    if (pdoName.Buffer == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto Error;

    }
    pdoName.MaximumLength = (USHORT) bufferLength;
    pdoName.Length = (USHORT) bufferLength - sizeof(UNICODE_NULL);

    status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
                                   L"SERIALCOMM",
                                   pdoName.Buffer,
                                   REG_SZ,
                                   comPort.Buffer,
                                   comPort.Length);

    if (!NT_SUCCESS(status)) {
        goto Error;
    }
    FmDeviceData->Flags |= REG_VALUE_CREATED_FLAG;
    //
    // Store it so it can be deleted later.
    //

    FmDeviceData->PdoName = pdoName;

    Error:

    if (symbolicLink.Buffer != NULL) {
        ExFreePool(symbolicLink.Buffer);
    }

    if (hKey != NULL) {
        WdfRegistryClose(hKey);
    }
    if (string != NULL) {
        WdfObjectDelete(string);
    }

    return status;
}

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS