Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Developing a WDF USB Kernel Mode Driver for the OSR USB FX2

, 30 Mar 2006
This article describes the process of developing a USB Kernel mode device driver using the WDF Kernel Mode Driver Foundation.
article_demo.zip
kmdf_usb_driver.zip
WDF_Usb_driver
makefile
sources
wdf_usb_man.inf
#include "ProtoTypes.h"

#pragma alloc_text(PAGE, InitPowerManagement)
#pragma alloc_text(PAGE, EvtDeviceD0Entry)
#pragma alloc_text(PAGE, EvtDeviceD0Exit)
#pragma alloc_text(PAGE, PowerName)

/*............................................................................*/
/* this function is called when the device is either started or woken up.     */
/*............................................................................*/
NTSTATUS
EvtDeviceD0Entry(
    IN WDFDEVICE  Device,
    IN WDF_POWER_DEVICE_STATE  PreviousState
    )
{
  NTSTATUS status = STATUS_SUCCESS;
  PDEVICE_CONTEXT devCtx = NULL;

  KdPrint((__DRIVER_NAME "Device D0 Entry. Coming from %s\n",
    PowerName(PreviousState)));

  devCtx = GetDeviceContext(Device);
  status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(devCtx->UsbInterruptPipe));
  if(!NT_SUCCESS(status))
  {
    KdPrint((__DRIVER_NAME
      "WdfIoTargetStart failed with status 0x%08x\n", status));
    return status;
  }

  /*restore the state of the LED array if the device is waking up from a
    D3 power state.*/
  if(PreviousState == PowerDeviceD3)
  {
    status = llSetLightBar(devCtx, devCtx->WdfMemLEDArrayState);
  }

  return status;
}

/*............................................................................*/
/* this function is called when the device is powered down.                   */
/* the current IO is left pending, because otherwise the continuous interrupt */
/* read IO will also be cancelled, and it would have to be reconfigured.      */
/*............................................................................*/
NTSTATUS
EvtDeviceD0Exit(
    IN WDFDEVICE  Device,
    IN WDF_POWER_DEVICE_STATE  TargetState
    )
{
  NTSTATUS status = STATUS_SUCCESS;
  PDEVICE_CONTEXT devCtx = NULL;

  devCtx = GetDeviceContext(Device);

  KdPrint((__DRIVER_NAME "Device D0 Exit. Going to %s\n",
    PowerName(TargetState)));

  /*save the state of the LED array if the device is waking up from a
    D3 power state.*/
  if(TargetState == PowerDeviceD3)
  {
    status = llGetLightBar(devCtx, devCtx->WdfMemLEDArrayState);
    if(!NT_SUCCESS(status))
      return status;
  }

  WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(devCtx->UsbInterruptPipe),
                  WdfIoTargetLeaveSentIoPending);

  return status;
}

/*............................................................................*/
/* initialize the power management functionality of our USB device.           */
/* we want it to support system wake-up with the on-board switch, and         */
/* idle- time sleep that puts the device into a sleeping state if it is       */
/* idle for a specified duration.                                             */
/*............................................................................*/
NTSTATUS
InitPowerManagement(
    IN WDFDEVICE  Device,
    IN PDEVICE_CONTEXT Context)
{
  NTSTATUS status = STATUS_SUCCESS;
  WDF_USB_DEVICE_INFORMATION usbInfo;

  KdPrint((__DRIVER_NAME "Device init power management\n"));

  WDF_USB_DEVICE_INFORMATION_INIT(&usbInfo);
  status = WdfUsbTargetDeviceRetrieveInformation(
                                Context->UsbDevice,
                                &usbInfo);
  if(!NT_SUCCESS(status))
  {
    KdPrint((__DRIVER_NAME
      "WdfUsbTargetDeviceRetrieveInformation failed with status 0x%08x\n",
      status));
    return status;
  }
  
  KdPrint((__DRIVER_NAME  "Device self powered: %d",
    usbInfo.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED ? 1 : 0));
  KdPrint((__DRIVER_NAME  "Device remote wake capable: %d",
    usbInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE ? 1 : 0));
  KdPrint((__DRIVER_NAME  "Device high speed: %d",
    usbInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED ? 1 : 0));

  if(usbInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE)
  {
    WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;
    WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings;

    WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings,
                                               IdleUsbSelectiveSuspend);
    idleSettings.IdleTimeout = 10000;
    status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings);
    if(!NT_SUCCESS(status))
    {
      KdPrint((__DRIVER_NAME
        "WdfDeviceAssignS0IdleSettings failed with status 0x%08x\n",
        status));
      return status;
    }
    
    WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings);
    wakeSettings.DxState = PowerDeviceD2;
    status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings);
    if(!NT_SUCCESS(status))
    {
      KdPrint((__DRIVER_NAME
        "WdfDeviceAssignSxWakeSettings failed with status 0x%08x\n",
        status));
      return status;
    }
  }

  return status;
}

/*............................................................................*/
/* for debugging purposes it is nice to be able to print out power state      */
/*  names so that we can see where we are coming from, and where we are       */
/*  going to.                                                                 */
/*............................................................................*/
LPCSTR PowerName(WDF_POWER_DEVICE_STATE PowerState)
{
  char * name = "";

  switch(PowerState)
  {
  case PowerDeviceUnspecified: name = "PowerDeviceUnspecified"; break;
  case PowerDeviceD0: name = "PowerDeviceD0"; break;
  case PowerDeviceD1: name = "PowerDeviceD1"; break;
  case PowerDeviceD2: name = "PowerDeviceD2"; break;
  case PowerDeviceD3: name = "PowerDeviceD3"; break;
  case PowerDeviceMaximum: name = "PowerDeviceMaximum"; break;
  default:
    name = "PowerDeviceUnknown"; break;
  }
  return name;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License

About the Author

Bruno van Dooren
Web Developer
Belgium Belgium
I am a professional software developer with an interest in everything that is about making hardware work.
 
In the course of my work, I have programmed device drivers and services on Windows and linux.
 
I have written firmware for embedded devices in C and assembly language, and have designed and implemented real-time applications for testing of sattelite payload equipment.
 
Generally, finding out how to interface hardware with software is my hobby and job.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 30 Mar 2006
Article Copyright 2006 by Bruno van Dooren
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid