<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-
1252">
<META NAME="Generator" CONTENT="Microsoft Word 97">
<TITLE>Toaster</TITLE>
</HEAD>
<BODY LINK="#0000ff">

<FONT FACE="Verdana" SIZE=5><H2>Toaster</H2>
</FONT><FONT FACE="Verdana" SIZE=2>
<P><span style="color:#FF0000;font-size:10pt;font-family:Arial">[This is preliminary 
documentation and subject to change.]</span></P>

<H3>SUMMARY</H3></FONT><FONT FACE="Verdana" SIZE=2><P>
The Toaster driver package provides a starting point for Windows 2000 driver development. It contains annotated code to illustrate the functionality of bus driver, function driver, assorted class, device, and bus filter drivers, and device-specific co-installer for a hypothetical Toaster bus and its devices. 


<H3>Introduction to a New Driver Model</H3></FONT><FONT FACE="Verdana" 
SIZE=2><P>
Every device driver stack for a Plug and Play (PnP) device under the Microsoft Windows 2000 operating system typically comprises a bus driver, a function driver, and from zero to one or more filter drivers. These drivers must support Plug and Play, Power Management, and Windows Management Instrumentation (WMI) to provide a better user experience and greater satisfaction. 

 <p>

These buzzwords make sense if you have developed a driver for Windows 95 or Windows 98. But, a developer who has only worked on Windows NT drivers might wonder: What are these things? Why do I need to worry about them? How do I implement them?

 <p>

Imagine a system with a new type of PnP I/O bus called a toaster bus. A controller chip on the motherboard initializes and manages the bus. The bus has a couple of ports jutting out of the box into which you can plug your toasters.
<p>
 

To provide support for this bus on Windows NT 4.0, you must modify the HAL (hardware abstraction layer) to recognize and initialize the I/O bus during system boot and you must provide a set of HAL functions for scanning the bus and accessing the configuration space of the devices by other drivers. Next, you must write drivers for every type of toaster device that load along with the system, and then use the exported HAL functions to scan the bus to detect the device, read the I/O resource requirements, and configure and initialize the device. These drivers are loaded regardless of whether or not a particular toaster is plugged in.  

 <p>

If another driver requires the I/O resources claimed by your driver, there is no resource distribution mechanism on Windows NT 4.0 to instruct the driver to relinquish them and use other resources if possible. If you want to expose instrumentation data or report some exceptional events to user mode, you must provide your own interface and custom applications. There is no generic interface like WMI and no power management.

 
<P>
To support this bus and its devices under Windows 2000, however, you dont have to modify the HAL or export a new set of functions. All you need to do is write a bus driver that has knowledge of bus architecture, identifies (enumerates) devices on the bus, reads their resource requirements, and configures them. This driver model also makes the operating system independent of its I/O bus. This means you dont need help from Microsoft if you design a new I/O bus to modify the HAL. Then, you write function drivers to control individual devices connected to the bus. Later on, one can write one or more filter drivers to add or modify the features supported by bus, a specific device or class of devices. There can be any number of lower-level or upper-level filter drivers for a bus, a device, or a class of devices. 

 
<p>
The Windows 2000 DDK documentation explains these new concepts and features by providing background information and describing how to implement them in your driver(s). This article and the accompanying sample drivers package provide annotated code samples that illustrate the functionality of various drivers without getting into detailed hardware specifics. These samples will help you start coding right away.

 <P>

To make the sample code closer to a real-world driver, I have defined a new class of devices called the TOASTER class and wrote a bus driver, function driver, and all possible class, device, and bus filter drivers for this hypothetical TOASTER bus and its devices. I have also provided a sample of coinstaller DLL to show how you can parse a custom section from an INF file and perform some special operations before and after the installation of a device, and how you can create FriendlyName for a device. The function and bus driver also show how you can provide power manager and WMI support.

 <P>

You can learn the implementation details of these sample drivers by looking at the code and reading the Windows 2000 DDK documentation. The rest of this article discusses the contents of the package that accompanies this article and how to install, build, and test these drivers. This article also briefly examines the various registry entries created by the system to setup and load the drivers.  

 
<P>

 
<H3>Introduction to the Toaster Sample
</H3></FONT><FONT FACE="Verdana" SIZE=2><P>

This sample driver package contains <I>bus</I>, <I>func</I>, <I>filter</I>, <I>exe</I>, <I>inc</I>, <I>coinstaller</I> and <I>inf</I> directories. The following summary describes the directories and key files.

 <P>

<I>bus</I>

 <BLOCKQUOTE> This directory contains the source code of the toaster bus driver (Busenum.sys). The job of this driver is to service the TOASTER bus controller, enumerate devices that are plugged in, and perform bus-level power management. The bus driver supports D0 and D3 power states. It also has a WMI interface.</BLOCKQUOTE>

 <P>

<I>func</I>

 <BLOCKQUOTE> This directory contains the source code of the function driver (Toaster.sys) for standard toaster devices. This driver owns the power policy for the toaster device and supports D0 and D3 power states. It also provides WMI interface.</BLOCKQUOTE>

 

<I>inc</I>

 <BLOCKQUOTE>This directory contains headers files that are shared among drivers and applications.
</BLOCKQUOTE>
 

<I>exe </I>

 <BLOCKQUOTE>This directory contains two subdirectories, <I>enum</I> and <I>toast</I>, with files to produce <I>enum.exe</I> and <I>toast.exe</I> (user-mode console applications):

 
<UL>
    

    <LI>
    <I>Enum.exe</I> is a user-mode enumerator, a simple console application. Because the toaster bus is not real, you need to have a mechanism to tell the bus driver when you plug in, unplug, and eject devices from the system. This application serves that purpose. Typically its written as a control panel applet for non-Plug and Play (legacy) devices. For example, <I>game.cpl</I>. 

 <p>

Usage: Enum [-a SerialNo] Plugs in a device.  SerialNo. must be greater than zero.<br>

                     [-r SerialNo or 0] Unplugs device(s) - specify 0 to unplug all the devices enumerated so far.<br>


                          [-e SerialNo or 0] Ejects device(s) - specify 0 to eject all the devices enumerated so far.<p>
By design every toaster device will have a globally unique serial number.
<p>

     <LI>
   <I>Toast.exe</I>: This is a user-mode console application to control the toaster. 

 </BLOCKQUOTE>

</UL>

<I>filter</I>
<p>
 This directory contains six different subdirectories, each producing one of the following drivers from a common source file (<I>filter.c</I>): <p>
<UL>
   
<LI>
        Class upper filter (<I>clsupper.sys</I>)

<LI>
        Class lower filter (<I>clslower.sys</I>)

<LI>
        Device upper filter (<I>devupper.sys</I>)

<LI>
        Device lower filter (<I>devlower.sys</I>)

<LI>
        Bus FDO upper filter (<I>bfdoupr.sys</I>) 

<LI>
         Bus FDO lower filter (<I>bfdolwr.sys</I>) 

 </UL>

<I>coinstaller</I>

 <BLOCKQUOTE>This directory contains source code of the device-specific coinstaller (<I>coinst.dll</I>). The DDK documentation has a good overview of coinstaller and its operation. The coinstaller demonstrates how to create a FriendlyName for a device based on its unique instance id. In this sample, during enumeration, the bus driver provides the serial number in the UINumber field of the device capabilities. The FriendlyName is required to uniquely identify multiple devices of the same interface class. The coinstaller also shows how to open an INF file and parse a custom section.
</BLOCKQUOTE>
 

<I>inf </I>
<p>
 This directory contains following files:
<p>
 
<UL>
  <LI>
       <I>bus.inf</I>: This .inf installs the <I>basenum.sys</I>, <I>toaster.inf</I> file and sets up the registry.

 

<LI>
       <I>toaster.inf</I>: This .inf creates <B>Toaster</B> class, installs <I>toaster.sys</I> and sets up the registry.

 

<LI>
       <I>busf.inf</I> and <I>toasterf.inf</I>: These two .inf files are functionally similar to the above INF files but also install all the previously mentioned filter drivers. 

 

<LI>
       <I>busco.inf</I> and <I>toastco.inf</I>: These two .inf files are functionally similar to <I>toaster.inf</I> and <I>bus.inf</I> except that <I>busco.inf</I> copies <I>toastco.inf</I> during installation. The <I>toastco.inf</I> installs a device-specific coinstaller.

 

<LI>
        <I>filter.inf</I>: This .inf installs just a device upper filter for the toaster device. Please read the Filter section in this article on how to use this .inf file.

 

</UL>

<p>

<H3>BUILDING THE SAMPLE</H3></FONT><FONT FACE="Verdana" 
SIZE=2><P>
To build the sample drivers, you must first set up the DDK environment on your host machine. The Installation and Release Notes in the Windows 2000 DDK has a complete description on how to do this.

 <OL>


 <LI>
     Run the build ceZ command in the Toaster directory to build <I>busenum.sys</I>, <I>toaster.sys</I>, <I>enum.exe</I>, <I>toast.exe</I>, <I>coinst.dll</I> and the six filter drivers mentioned previously. 

 

 <LI>
     Copy all the .sys, .exe, .dll, and .inf files to a floppy disk or a temporary directory on the target system
</OL>
  <P>


<H3>INSTALLING   
 THE SAMPLE</H3></FONT><FONT FACE="Verdana" 
SIZE=2><P>


To install the bus driver: <p>

<OL>
  
<LI>
      Double-click the Add/Remove Hardware wizard in Control Panel.

<LI>
      Click Add/Troubleshoot a Device.

<LI>
      Select Add a new device and then click Next.

<LI>
      Select No, I Want to Select the Hardware from a list.

<LI>
      Select System Devices and then click Next. 

<LI>
      Click Have Disk and choose one of  Toaster Bus Enumerator, Toaster Bus Enumerator with Filters or Toaster Bus Enumerator (Coinstaller). The <I>bus.inf</I> file just installs the bus enumerator and it refers to <I>toaster.inf</I> file for installing the toaster device. But the <I>busf.inf</I> installs the bus enumerator and its upper and lower filters. It also refers to <I>toasterf.inf</I> file, which not only installs the toaster device but also the class and device lower and upper filters. The <I>busco.inf</I> file installs the bus enumerator and it refers to <I>toastco.inf</I>, which loads the coinstaller to create a FriendlyName for each plugged in toaster device. 

 </OL>

<p>
The system copies the <I>busenum.sys</I> file to the <I>%Systemroot%\system32\drivers</I> directory, copies the <I>toaster.inf</I> file to the <I>%Systemroot%\inf</I> directory, and sets up the following registry keys to represent the bus driver to the PnP manager:
<p>

 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E97D-E325-11CE-BFC1-08002BE10318}\nnnn 
<br>
  // nnnn is the instance number of this System Class driver on the system.
<p>
 

It then copies the INF file as OEM.n.INF, where n is a zero-based number, to the system INF directory. It also creates the standard Services keys to load the driver:
<p>
 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\busenum. 
<p>
 

 

Once installed the system creates device registry keys (Hardware keys) under:

 <p>

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\SYSTEM\nnnn
<br>
  // nnnn is the instance number of this System Class driver on the system.
<p>
 

Another quick way to install the bus driver without going through so many mouse clicks would be to use the Installer sample application present in the <I>ntddk\src\general\setup\install</I> directory. This sample allows you to root-enumerate a driver with one simple command. Please read the help file included in the sample on how to build and use the application to install this driver. 

<p>


<H3>RUNNING THE SAMPLE</H3></FONT><FONT FACE="Verdana" 
SIZE=2><P>

Once the Toaster bus driver is installed and started by the PnP Manager, you can run the <I>enum.exe</I> application from the command prompt to simulate plug in, unplug or ejection of toaster devices on the system. <I>Enum.exe</I> basically sends an I/O control (IOCTL) to the bus driver with the user provided globally unique serial number and Hardware ID of the device, and triggers the entire enumeration process. If the device ID matches the ID specified in the INF file for <I>toaster.sys</I>, the PnP manager installs and loads the toaster driver. You can remove/eject a single device by giving its serial number or remove/eject all the devices by specifying 0 (zero) as the serial number of the device. 

 <p>

<B>To plug in a device (or rather simulate a device arrival):
</B>
 
<BLOCKQUOTE>
C:\>enum -p 1
</BLOCKQUOTE>
 

<B>To unplug a device:
</B>
 

<BLOCKQUOTE>C:\>enum -u 1
</BLOCKQUOTE>
 

<B>To eject a device:
</B>
 

<BLOCKQUOTE>C:\>enum -e 1
</BLOCKQUOTE>
 

To test a plugged in device, you can use the <I>toast.exe</I> application. This application basically enumerates all the toaster class devices, displays its properties such as FriendlyName, InstanceId, and opens the last enumerated device to perform a read operation and send a DeviceIoControl to the device depending on the user command line option. 

 <p>

If you invoke without any option it basically opens the last enumerated interface and prompts you to initiate a Read operation in a loop. You press any key to continue the read loop or press q to break out of the loop. If you use the h option it opens the last enumerated interface and sends a DeviceIoControl to hide the device from the Device Manager before performing read.

 <p>

Usage: Toast <h> {-h option causes the device to hide from Device Manager UI}

 <p>

Both these applications use the SetupDi functions to enumerate and open the device interfaces. These functions are documented in the Windows 2000 DDK documentation.


<p>

<H3>Filters</H3></FONT><FONT FACE="Verdana" 
SIZE=2><P>

You can install device filter drivers by specifying LowerFilters or UpperFilters to the Hardware registry key (HKLM\ \SYSTEM\CurrentControlSet\Enum) for the device; and class filters by specifying them to the Software registry key (HKLM\SYSTEM\CurrentControlSet\Control\Class\<GUID>) for the device class. 
<p>
Because this is an MULTI_SZ string, you can specify more than one filter for the device or class. If you specify more than one, the load order is in the order they are listed  the filter at the end of list is the topmost driver in the stack, and so on. You can install device specific filters by using a [.HW] section that specifies AddReg section, and class specific filters by specifying AddReg section from the base install section in your INF file. The <I>busf.inf</I> and <I>toasterf.inf</I> show how to do that. 
<p>
 

The <I>filter.inf</I> file is a special .inf file that enables you to install a filter driver for the toaster device after it has been installed and enumerated. To install an upper device filter for a toaster device: 

 <OL>
  
<LI>
      Enumerate a toaster device.

<LI>
      Open the Device Manager. 

<LI>
      Open the Properties of the Toaster device for which you want to install filter.

<LI>
       Click the Driver tab, and then click Update Driver. 

<LI>
      Follow the wizard's prompts, and when prompted, select the Display a list of the known drivers option. 

<LI>
      Click Have Disk and point to the location of the filter.inf file. 

<LI>
      Proceed through the rest of the install. 
</OL>

Currently, uninstalling the filter has some problems. To install you must write a write a coinstaller to remove explicitly UpperFilters or LowerFilters values from the Hardware registry key for the device. 

 <p>


<H3>Device Parameters Subkey</H3></FONT><FONT FACE="Verdana" 
SIZE=2><P>


Currently the sample doesnt show how to read Device Parameters value from the registry. This feature will be added in the future updates of this driver.
<P>
Under Windows 2000, the configuration information is not stored under the Services key of the driver. It is stored in three different places, depending on whether its device instance specific, driver specific or interface specific. 

 <P>

You can store device-specific configuration information under the Hardware key of that particular device instance (HKLM\SYSTEM\CCS\Enum\&lt;DeviceId&gt;\&lt;VendorId&gt;\&lt;InstanceId&gt;\Device Parameters) and driver-specific information under the Software key (HKLM\SYSTEM\CCS\Control\Class\&lt;GUID&gt;\&lt;driver-instance-id&gt;\ Device Parameters) of the driver by using <B>IoOpenDeviceRegistryKey</B> function. 

 <P>

You can store interface-specific information under the device-interface key (HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\&lt;SymbolicLinkName&gt;\Device Parameters) by calling <B>IopenDeviceInterfaceRegistryKey</B> with the symbolic link name of the device interface. Both of these functions return the handle to the <B>Device Parameters</B> subkey. For legacy support, you can continue to store information under the Services key.

<P>
<H3>Power Management</H3></FONT><FONT FACE="Verdana" 
SIZE=2><P>


In this example, the function driver acts as a power policy owner for the toaster device and supports DO and D3 power mode. You can use the same power logic to implement power policy in the bus driver. You need a system with an ACPI-compatible BIOS in order to test the power management code. If you have an ACPI compatible system, you will see a Standby option in the Shutdown submenu. 

 
<P>

<H3>WMI</H3></FONT><FONT FACE="Verdana" 
SIZE=2><P>

A WMI interface is provided to both the function and bus driver. The WMI library is used to handle WMI IRPs. The MOF files, which define WMI data and event blocks, are compiled along with the driver and included in the drivers binary image. 

 <P>

To test the WMI interface, first install the WMI SDK on your system. Then, use either <I>wbemtest.exe</I> or CIM Studio to enumerate the instances registered by these drivers. 

 <P>

For example, to see the data exported by the Toaster driver:  <P>


<OL>
 
 <LI>
     Run <I>wbemtest.exe</I>. 

 <LI>
      Connect to root\WMI class. 

 <LI>
      Click Enum Instances. 

 <LI>
     Type ToasterDeviceInformation and press Enter. 

 </OL>

You should see the toaster device instances. The DebugPrintLevel data in both the drivers have been made read/write, so that it is possible to dynamically change the value of these variables with the WMI application and control the driver debug trace seen on Windbg.

 <P>



</FONT><P ALIGN="CENTER"><A HREF="#top"><FONT FACE="Verdana" SIZE=2>Top of page</FONT></A><FONT FACE="Verdana" SIZE=2> </P></FONT>
<TABLE CELLSPACING=0 BORDER=0 WIDTH=624>
<TR><TD VALIGN="MIDDLE" BGCOLOR="#00ffff" HEIGHT=2>
<P></TD>
</TR>
</TABLE>

<FONT FACE="MS Sans Serif" SIZE=1><P>&copy; Microsoft Corporation 1999</FONT><FONT FACE="Verdana" SIZE=2> </P></FONT></BODY>
</HTML>

