ࡱ>  usqywqop  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstvwxyz{|}~Root Entry F@sxECompObj^WordDocument ObjectPool`xE`xE  FMicrosoft Word 6.0 Document MSWordDoc9qࡱ> _Oh+'0(Lp   $ Hl C:\OFFICE\NORMAL.DOT    ܥe- e  f ff f f f     r 8            L1 L} . T B f  S      f f  r     f  f   f & @f f f f    , Plug and Play Drivers Plug and Play Introduction Plug and Play Device Drivers Configuration Manager Device Information Files Plug and Play and PCMCIA Plug and Play Installation Property Page Providers Device Registry Keys and Values Registry Services Multifunction Plug and Play Hardware Dynamic Registry Keys in Windows 95 Chapter SEQ CHAPTER \R 11 Plug and Play Introduction About Plug and Play The Plug and Play framework makes it easy for computer users to add new hardware. Plug and Play prevents conflicts between devices, allows hot docking, and enables the enumeration of devices on the system. Plug and Play does not create a new device-driver model. It specifies a set of API elements that are used in addition to, not in place of, existing driver architectures. The Plug and Play framework has the following goals: SYMBOL 183 \f "Symbol" Easy installation and configuration of new devices. Plug and Play devices will be capable of identifying themselves and declaring their services and resource requirements. This information will enable the operating system to determine and set a working configuration and load the appropriate device drivers without any user intervention. Installing a new device will be as easy as plugging it in and copying a file to the driver directory. SYMBOL 183 \f "Symbol" Seamless dynamic configuration changes. The Plug and Play framework allows hot docking of portable computers, and hot insertion of devices. When an insertion event occurs, the operating system will recognize the new device, its services, and its requirements, and load the necessary drivers. Applications will be notified about dynamic events so they can take advantage of the new functionality or stop using unavailable devices. The user is prompted only when the required resources are not available to the new device. SYMBOL 183 \f "Symbol" Compatibility with installed base and old peripherals. Specific components in the Plug and Play framework hide the lack of a device reporting mechanism for devices that are not Plug and Play enabled. Information about these devices is kept in the registry. Devices which cannot be configured using software receive first priority in resource allocation. When unresolvable conflicts occur, the configuration manager may be accessed via a smart user interface which leverages information such as .INF-format files to guide the user through device configuration options. SYMBOL 183 \f "Symbol" Operating system and hardware independence. The Plug and Play framework defines several base components which can be implemented in any operating environment. Buses, devices, and resources are abstracted from the base components via hardware specific enumerators, arbitrators and device drivers. This ensures that this framework is extensible not only to other environments but also to future bus and device architectures. SYMBOL 183 \f "Symbol" Reduce complexity and increase flexibility of hardware. The Plug and Play framework includes guidelines for BIOS, system, and hardware vendors on building Plug and Play compatible hardware. An integral part of this document is the ISA Plug and Play design specification that defines a complete hardware and firmware design for ISA devices. Similar schemes are supported by architectures such as PCMCIA, SCSI, and PCI. The common denominator for all hardware devices is the device node (Dev_Node) defined by this framework. Hardware vendors will need to ensure that their devices, driver disks, and systems provide sufficient information to populate their device nodes if they want them to be Plug and Play! Plug and Play System Components The Plug and Play framework defines a single object that has several attributes. This object is called a device node. One of its attributes identifies devices that provide resources (buses). The collection of device nodes that describes a computer is called the devnode tree. The Plug and Play framework defines several software components that have been added to the operating system: Configuration Manager, enumerators, and resource arbitrators. Enumerators build the devnode tree and may participate in configuring the devices on their bus. The enumeration process takes place every time the computer starts. There are two phases of enumeration in the current implementation of the operating system: BIOS POST, and protected-mode. At the end of the enumeration process, the devnode tree includes information about available system resources, required device drivers, and resource requirements. Configuration Manager uses resource arbitrators to find a working resource allocation which satisfies the overall requirements of currently enumerated devices. Device drivers are then notified of their assigned configuration. Windows 95 accommodates dynamic system events by broadcasting system messages to applications and device drivers. When an event such as the insertion or removal of a device occurs, applications and device drivers are notified. They can then take any required action or, in some cases, veto the configuration change. The Plug and Play framework also uses and extends the registry and device information files (with the .INF filename extension). The registry stores information about all devices ever installed on a particular machine, including devices that are not Plug and Play enabled (but detected when the operating system was installed), Plug and Play devices which have been located by an enumerator, device-specific state information, bindings of devices to device drivers, and data about the last known configuration, which is used to accelerate the allocation of resources. The device information files contain information about known devices and their configurations. The system provides some class-information files (for example, SCSI.INF and MODEM.INF); others are provided by the device manufacturer. When a new device is detected or enumerated, all known .INF files are searched for entries matching the device ID. When a match is found, the appropriate files are copied and the required data is copied into a newly created registry entry. Interaction of Plug and Play Components The following diagram shows how the Plug and Play components fit together. When the operating system is installed, detection modules are loaded based on the list in the MSDET.INF information file. When a device is detected that is not enabled for Plug and Play, information about it is retrieved from the appropriate device information file and stored in a new node created under the HKEY_LOCAL_MACHINE\ENUM\Root branch in the registry. On the first boot after initial installation (and on each subsequent boot) the system loads the enumerators and the same process occurs so that devices which can be enumerated rather than detected can be found, thus completing the list of known hardware. Enumerated devices appear under the relevant ENUM\enumerator name branch. When the system starts, Configuration Manager loads enumerators to enumerate the devices in the system. Enumerators create a device node in the devnode tree for each enumerated device and populate it with information retrieved from the registry. The bus-specific naming schemes ensure that the root_key\device identifier is actually the device node's path in the registry. Drivers are loaded based on the driver information bound to each device in the registry, and are given a handle to their device node. EMBED ShapewareVISIO20 Plug and Play Boot Process During the real-mode boot process, devices use only static configurations; no dynamic resource allocation or arbitration is provided. When a user adds a new device to the system, no software attempts to enable the device until the protect mode Configuration Manager has been able to set up the device successfully. One possible exception to this is that a Plug and Play BIOS may enable plug & play devices which are required for booting the system. The boot process goes through four phases: 1. BIOS in control (Phase 0) 2. MS-DOS compatibility driver and TSR loading (Phase 1) 3. VMM32.VXD real-mode initialization (Phase 2) 4. Operating system in Control in protected mode (Phase 3) BIOS in Control (Phase 0) Non-Plug and Play BIOS Computers that are not Plug and Play enabled behave as always. Plug and Play ISA cards that have option ROMs should power up with the option ROM enabled only if the ROM is actually required for proper functionality, for example a Plug and Play SCSI card which needs to boot from one of the attached hard drives. If the ROM is enabled and the device is active when Windows 95 protect mode initialization begins, that Plug and Play device will be treated as unmovable for purposes of resource allocation. This is because real mode drivers may have been loaded for the device in Phase 1 which would be unable to handle a shift in resource allocation. The phase 0 boot process for an old ROM acts exactly as it always has. Plug and Play BIOS Plug and Play enabled BIOSs will access non-volatile RAM to determine which Plug and Play ISA cards should be enabled and where their option ROMs should be mapped, and what I/O, DMA, and other assignments to give to the card. The BIOS will then program the Plug and Play cards prior to the power-on self test (POST). All cards that do not have a configuration stored in the BIOS will be disabled completely, eliminating the chance of a conflict. The Plug and Play BIOS will also configure all devices on the motherboard. Some devices may have been disabled or assigned to different I/O, IRQ, or other resources by Configuration Manager. Operating System in Control in Real Mode (Phase 1) There is no automated device enumeration at this phase of the boot process. The hardware profile for docking purposes is computed. Drivers that need to be loaded must be explicitly specified in CONFIG.SYS or AUTOEXEC.BAT. The following list gives the process for real-mode initialization: SYMBOL 183 \f "Symbol" Compute hardware profile. SYMBOL 183 \f "Symbol" Process CONFIG.SYS. SYMBOL 183 \f "Symbol" Process AUTOEXEC.BAT. SYMBOL 183 \f "Symbol" Start Windows 95 real mode loader (boot phase 2). Windows 95 Real Mode Loader (Phase 2) The final step before initializing the protected-mode Configuration Manager is to load static VxDs. For compatibility reasons, the real-mode loader will first load devices specified in SYSTEM.INI. This is the first phase of configuration management in which automated device enumeration takes place, and access to the registry is available, but there is still no automated resource assignment. Based on the type of bus hardware detected by the real-mode Configuration Manager driver, the system loads the appropriate enumerator VxD. For example, the ISA enumerator will be loaded during this phase if an ISA bus exists on the system. If the machine has a Plug and Play BIOS, the BIOS enumerator loads. In all cases, the root enumerator loads during this phase. Operating System in Control in Protected Mode (Phase 3) Once VMM32.VXD has initialized, the full-featured protected-mode Configuration Manager is initialized. Configuration Manager imports device identifier information from the real-mode loader. Drivers are loaded and initialized at this phase in exactly the same manner as with dynamic enumeration and device loading. Enumerators create device nodes, Configuration Manager calls the appropriate device loader, and the process continues. Example Boot Sequence This section describes the boot process for an ideal configuration: a computer with a new BIOS and new Plug and Play cards, but no non-Plug and Play hardware or real-mode device drivers. Phase 0: BIOS Initialization The BIOS configures all motherboard devices. Next it executes the ISA Plug and Play isolation algorithm and assigns configurations to all devices required for booting. It then checks the expansion card ROMs during the power-on self test and boot loads the operating system (phase 1). Phase 1: Real Mode MS-DOS Driver Loading CONFIG.SYS and AUTOEXEC.BAT are processed in the standard manner. Phase 2: Real Mode VxD Loader The system loads VxDs specified in SYSTEM.INI. The real mode loader loads the PnPBIOS enumerator if appropriate, as determined by detection at Windows 95 install time. If there is no PnPBIOS in the machine, the appropriate bus drivers are loaded based on what was detected at install time. In PnPBIOS machines, the BIOS is responsible for telling the operating system which busses are on the machine, which in turn drives the decision as to which bus drivers need to be loaded. The ISA enumerator, for example, is now loaded and enumerates all ISA devices, which, in turn, could have static VxDs that enumerate their children, and so on. Once all static VxDs have loaded, the system enters phase 3 of the boot process. Phase 3: Protected Mode Operating System Initialization Some VxDs are loaded during phase 2 of configuration management, but they initialize in protected mode during phase 3. Devices such as VPICD and VDMAD are passed a handle to the device node that caused them to load. Resource arbitrators need to register with Configuration Manager during Sys_Critical_Init so that devices that register later in the boot process can allocate these resources. Enumerators, such as the ISA bus enumerator, may add new device nodes to the in-memory devnode tree. Some of these nodes may also have children. When all devices have been enumerated, all conflicts have been resolved, and all devices have been initialized, the system is ready to be used. The devnode tree will contain a complete description of every device connected to the machine as well as the resource requirements of those devices. Chapter SEQ CHAPTER \R 22 Plug and Play Device Drivers Introduction An ideal Plug and Play driver has the following capabilities: SYMBOL 183 \f "Symbol" Retrieves configuration information from Configuration Manager. SYMBOL 183 \f "Symbol" Is dynamically loadable. SYMBOL 183 \f "Symbol" Is dynamically reconfigurable. SYMBOL 183 \f "Symbol" Requires minimal user interaction to select the proper driver. SYMBOL 183 \f "Symbol" Reacts to system messages about the insertion or removal of new devices. SYMBOL 183 \f "Symbol" May need to understand state information; that is, the settings for the device may need to change based on which user is logged in, whether the machine is docked or undocked (in the case of a docking station architecture) or both. Most of the Plug and Play work required for device drivers is producing a callback entry point that the system uses to assign a configuration. For information about this entry point, see Driver Callback Entry Point later in this chapter. For a sample Plug and Play device driver, see Sample Plug and Play Driver later in this chapter. Many Plug and Play system components, such as enumerators and arbitrators, will not be written by the majority of device driver writers. However, a basic understanding of what each of these components does is important for a complete understanding of how they interact. Drivers for different architectures will interact with Plug and Play in different ways. Many VxDs will interact directly with Configuration Manager, but drivers that are a part of a layered driver model may get configuration information through another layer. For example, Windows 95 network drivers are based on the NDIS driver model, with extensions for Plug and Play capabilities. The net wrapper interacts with the Windows 95 configuration manager and routes the appropriate configuration information to the extended NDIS drivers. Windows 95 disk and SCSI drivers are based on the Windows NT SCSI mini-port model, with extensions for Plug and Play. IOS routes configuration information to these drivers. VxDs such as Virtual Display Devices can interact directly with Configuration Manager. For each of these driver models, the interface with Configuration Manager is different. However, the basic requirements are the same. Components of Plug and Play Architecture All configuration management in the Plug and Play system is directed by the Configuration Manager, which is implemented as a VxD. Configuration Manager manipulates three major data stores: SYMBOL 183 \f "Symbol" Device nodes SYMBOL 183 \f "Symbol" Devnode tree SYMBOL 183 \f "Symbol" Registry Configuration Manager works with four major software components: SYMBOL 183 \f "Symbol" Enumerators SYMBOL 183 \f "Symbol" Arbitrators SYMBOL 183 \f "Symbol" Device loaders SYMBOL 183 \f "Symbol" Device drivers Device Nodes A device node is the basic in-memory representation of a device that is physically present on the system. This data structure contains information relating to the device and its drivers. The major information stored in a device node is: SYMBOL 183 \f "Symbol" Device ID SYMBOL 183 \f "Symbol" Currently assigned configuration SYMBOL 183 \f "Symbol" Possible logical configurations SYMBOL 183 \f "Symbol" Status information SYMBOL 183 \f "Symbol" Device driver entry point SYMBOL 183 \f "Symbol" Enumerator entry point (optional) SYMBOL 183 \f "Symbol" Arbitrator entry point(s) (optional) Device nodes are created only by enumerators. The creation of a device node causes the appropriate driver to be loaded. Driver writers typically need not concern themselves with creating device nodes or device IDs. Device ID A device ID is a unique ASCII string. This string can be used to cross-reference data about the device stored in the registry. Examples of device IDs are: SYMBOL 183 \f "Symbol" Root\*PNP0000\0 SYMBOL 183 \f "Symbol" ISAPNP\ADP1522_DEV0000\E8124123 SYMBOL 183 \f "Symbol" BIOS\*PNP0100\0 SYMBOL 183 \f "Symbol" PCMCIA\MEGAHERTZ-XJ124FM-936B For more information about device IDs, see Device IDs later in this chapter. Assigned Configuration Drivers examine this portion of the device node to determine which resources have been allocated for the device. For Plug and Play cards, the assigned resources for a given device may change from one boot to the next, or even while the computer is running (dynamically). Logical Configurations Logical configurations describe the various configurations that are valid for a given piece of hardware. Most driver writers will not need to examine or modify the logical configuration list for a given device node. Enumerators are responsible for creating the appropriate logical configurations when they create a device node. Status Information Information about the state of a device, such as whether it is disabled or configured, is maintained by Configuration Manager in each device node. Drivers can query this information. Device Driver Entry Point When a driver is loaded for a specific device node, it registers with Configuration Manager, passing an entry point that will be called to assign or change hardware configurations. Enumerator Entry Point Device nodes that have child nodes will have enumerators. Enumerators are the components of Plug and Play that identify installed hardware and create device nodes. Most driver writers will not need to write an enumerator. Arbitrator Entry Point(s) Arbitrators are the components of Plug and Play that assign ownership of various resources, such as IRQs and I/O ports. Most driver writers will not need to write an arbitrator. Devnode Tree The devnode tree is a hierarchical tree of device nodes. Any device node that has an enumerator can create new child device nodes. Any of these child device nodes can have an enumerator that creates further children of that device node. Normally, drivers do not know or care about their exact location within the tree. Drivers typically are only concerned with their own hardware device or device node, and are oblivious to the layers above or below them in the tree. The devnode tree has two purposes: 1. Describe all hardware that is present in the system. 2. Provide a mechanism for enumerators to configure their childrens hardware, allowing bus-independent drivers. The distinction between the devnode tree and the registry is important. In a fully Plug and Play system, the devnode tree will be an accurate hierarchical representation of the currently installed devices. By contrast, the registry contains information for all devices ever installed (even if they are not currently present) and the location of a device in the registry does not fully reflect the hierarchical structure described in the devnode tree. (In the registry, devices are located beneath their enumerator but all enumerators are kept in a flat list.) The devnode tree exists in memory only, whereas the registry is saved on disk. Sample Devnode Tree The following sample devnode tree shows the device IDs of some typical devices and where in the hierarchy one might expect to find them. The actual contents of each device node other than the device ID are not shown. Htree\Root\0 - Root node of devnode tree \Root\*PNP0801\0 - Old-style Sound Blaster compatible sound device \Root\*PNP0C00\0 - Plug and Play BIOS \BIOS\*PNP0901\0 - Super VGA compatible display adapter \BIOS\*PNP0000\0 - AT Interrupt Controller \BIOS\*PNP0100\0 - AT Timer \BIOS\*PNP0200\0 - AT DMA Controller \BIOS\*PNP0301\0 - PS/2 Style Keyboard Contoller \BIOS\*PNP0400\0 - Standard LPT printer port \BIOS\*PNP0400\1 - Standard LPT printer port \BIOS\*PNP0501\0 - 16550 COM port \BIOS\*PNP0501\1 - 16550 COM port \BIOS\*PNP0700\0 - PC standard floppy disk controller \BIOS\*PNP0800\0 - AT style speaker sound \BIOS\*PNP0901\0 - SVGA compatible display adapter \BIOS\*PNP0B00\0 - AT Real Time Clock \BIOS\*PNP0C01\0 - System memory \BIOS\*PNP0E00\0 - PCMCIA Controller \PCMCIA\3C08AF\0 - Network adapter Registry The registry is a system-wide database, accessed in both Windows 95 and Windows NT through the Microsoft Win32 API set. Additionally, Windows 95 provides real-mode access to the registry to allow its use during boot-up prior to the switch to protected mode. The registry stores a hierarchical tree of Keys and Values, similar to entries in Windows 3.1-format .INI files (except that Windows 3.1 .INI files have a flat structure, as opposed to the tree structure of the registry.) Windows 95 Plug and Play uses the registry to store information about which drivers should be loaded when a particular device is enumerated, as well as such information as the driver revision number, manufacturer, and potential logical configurations of the device. Most Plug and Play registry entries are stored in the ENUM tree. (That is, \\HKEY_LOCAL_MACHINE\ENUM.) Under ENUM, each enumerator gets its own branch, with one child under the enumerator for each device it has ever enumerated and set up. There is one special enumerator branch called ENUM\ROOT which contains the registry entries for old-style, non-Plug and Play hardware for which there is no enumerator but which can be detected using other means. The Device Installer creates new registry entries when an enumerator detects a device for which there is no registry entry. Most of the information is provided either by the .INF file provided with the device or directly by the devices setup module. The registry also stores configuration-specific information (that is, information which is relevant to whether a capable portable computer is docked or undocked) as well as user-specific information. For any particular setting, the application or device driver must determine whether it is configuration-aware or user-aware, and write the entries to the registry in the proper location. General configuration-specific information is stored in the \\HKEY_LOCAL_MACHINE\CONFIG\configname branch of the registry. The rules for storing information in these configuration specific branches should be the same as the rules for their grandparents. Typically, creators and consumers of config- and user-specific information read and write to the predefined keys HKEY_CURRENT_CONFIG\ and HKEY_CURRENT_USER which automatically selects the appropriate subbranch of the CONFIG and HKEY_USERS trees. Since information about static devices (that is, non-Plug and Play hardware) is stored in \\HKEY_LOCAL_MACHINE\ENUM\ROOT\*, information about static devices that only applies to a particular configuration is stored in: \\HKEY_LOCAL_MACHINE\CONFIG\xxxx\ENUM\ROOT. Sample Registry Entries ENUM\ROOT\*PNP0000\0000 DrvDesc=Programmable Interrupt Controller Class=System BootConfig=(I/O ports 20h, 21h, A0h, and A1h - Binary resource data) Driver=System\0000 HardwareID=*PNP0000 InfName=MACHINE.INF Mfg=Microsoft NoSetupUI=1 ENUM\BIOS\*PNP0000\0000\LogConfig 0=(Binary resource data, in this case same as BootConfig above) SYSTEM\CurrentControlSet\Services\Class\System\0000 DriverDesc=Programmable Interrupt Controller DevLoader=*VPICD EnumPropPages=Sysclass.dll,EnumPropPages Device IDs Device IDs are unique ASCII strings that are created by enumerators to identify a hardware device. IDs are made up of three distinct parts, separated by a backslash. The first part of the ID identifies the enumerator that created the ID. The second part is the ID itself. If this part of the string begins with an asterisk (*), this is an EISA-format ID, which are three letters followed by four hexadecimal digits. The 3-letter prefixes are assigned on a per-company basis and hardware vendors must only use those letters assigned to their company, or the PNPxxxx identifiers discussed below. EISA identifiers may be obtained from: If you are a hardware manufacturer building ISA Plug and Play adapter boards, you are expected to procure your own three letter EISA identifier and assign your own IDs for your hardware. EISA identifiers may be obtained from: BCPR Services, Inc. P.O. Box 11137 Spring, Texas 77391-1137 (713)251-4770 (phone) (713)251-4832 (fax) Many enumerators generate EISA IDs when enumerating devices, and the * indicates that the ID comes from this generic pool, thus allowing setup to select the appropriate driver regardless of which enumerator created the ID. An ID that does not start with an * will require setup information specific to the enumerator that created the ID to find the appropriate driver. The third part of the ID is a unique instance number for this computer. This is used to distinguish two or more identical devices in a single computer from one another. For example, two COM ports require two unique instances. Since many devices do not have an EISA ID, Microsoft has defined IDs for every device that Windows 95 supplies drivers for. We have reserved the EISA manufacturers ID PNP and defined a set of IDs for base system components: SYMBOL 183 \f "Symbol" PNP0000 AT interrupt controller SYMBOL 183 \f "Symbol" PNP0100 AT timer SYMBOL 183 \f "Symbol" PNP0200 AT DMA controller Other base system components are numbered in the same way. The complete current list of compatibility IDs is available on Compuserve in the PLUGPLAY forum, under the filename DEVIDS.ZIP. ISA device IDs have the following form: ISAPNP\device ID+_DEV0000, 0001, ...\serial number In this example, device ID is taken from the first four bytes of the card. The entries for _DEV numbers are required only if there are many devices on the card. The following table gives some sample ISA device IDs: Device IDDescriptionISAPNP\FDC0000\00000012future domainISAPNP\ADP1522_DEV0000\E8124123Adaptec SCSI device (function 0)ISAPNP\ADP1522_DEV0001\E8124123Adaptec floppy device (function 1) For PCMCIA, the device ID is created from tuple information on the card. The goal is to create a unique ID for each card. The ID is created by concatenating the PCMCIA prefix, the manufacturer-name string, the product-name string, a 16-bit CRC, and the instance value for the card. PCMCIA\manufacturer_name-product_name-crc\instance A PCMCIA device identifier might look like the following example: PCMCIA\MEGAHERTZ-XJ124FM-936B The CRC is created from the following tuple data: SYMBOL 183 \f "Symbol" CISTPL_CFTABLE_ENTRY SYMBOL 183 \f "Symbol" CISTPL_CONFIG SYMBOL 183 \f "Symbol" CISTPL_DEVICE SYMBOL 183 \f "Symbol" CISTPL_MANFID SYMBOL 183 \f "Symbol" CISTPL_VERS_1 If the CISTPL_VERS_1 tuple is not available or the manufacturer name is NULL, the string "UNKNOWN_MANUFACTURER" is used for the manufacturer name. PCMCIA\UNKNOWN_MANUFACTURER_crc\instance The total length of the device ID string is limited to 128 characters, including the null terminator. The manufacturer and product name are truncated, if necessary, to maintain this length restriction in the ID string. The characters in the manufacturer and product name strings that are greater than or equal to a space (0x20) or less than (0x7F) will be copied into the name string. Any characters outside this range are skipped. This restriction makes it easier to include these characters in the .INF files for the device. Boot Process The boot process has several distinct steps, each of which provides different services, driver models, and requirements. The full Windows 95 boot sequence can be broken down as follows: 1. BIOS Bootstrap 2. MS-DOS Configuration Management Pre-Config.Sys 3. Process Config.Sys and Autoexec.Bat 4. VMM32 Real Mode Loader 5. Pre-Sys_Critical_Init Processing 6. VxD Initialization 7. Windows GUI Driver Initialization 8. (Post-boot) Dynamic Events BIOS Bootstrap Microsoft has worked with several OEMs to define a new Plug and Play BIOS specification. This specification discusses the interactions between a Plug and Play BIOS and Plug and Play devices and option ROMs. MS-DOS Configuration Management Pre-CONFIG.SYS The following sections describe the configuration management carried out during early initialization of the operating system and before the statements of the CONFIG.SYS file are processed. Hardware Profile Detection Hardware profile detection determines the computers hardware profile. Although most desktop computers will have only one hardware profile, dockable portables typically have one hardware profile for the undocked state and another for each dock to which they connect. Hardware profile detection runs before the CONFIG.SYS file is executed during MS-DOS startup. Hardware profile detection combines interrupt checksums, BIOS COM/LPT data, BIOS machine identification data, Plug and Play BIOS Docking Station data, and, if possible, docking station data which is unique to each OEM and builds a 2 byte value known as the current hardware profile (or the current configuration). Each hardware profile has a friendly name. If the current hardware profiles friendly name exactly matches a top-level menu item in a multi-configured CONFIG.SYS file, that menu item or submenu is automatically selected. The registry uses the current hardware profile to point the predefined key HKEY_CURRENT_CONFIG to the correct location (subsidiary to the predefined key HKEY_LOCAL_MACHINE). For example, if the current hardware profile were 0x5107, HKEY_CURRENT_CONFIG would be initialized to HKEY_LOCAL_MACHINE\CONFIG\5107. Select Appropriate Boot Configuration Windows 95 expands on the MS-DOS 6.0 ability to allow multiple-configuration boots. Windows 95 allows Windows applications and drivers to be configuration-aware. By examining a DockSerialID returned by a Plug and Play BIOS, the system will attempt to automatically determine the appropriate state to boot the system in. If the appropriate state can not be determined, the user will be prompted to select the correct state from several configurations with the same DockSerialID. If a new DockSerialID is generated that the user has not had before (for example, if the user plugs into a new docking station in a friends office), the user is asked to run full-scale hardware detection and associate a friendly name (for example, Docked in Janes office,) with the new DockSerialID. Processing CONFIG.SYS and AUTOEXEC.BAT In Windows 95, CONFIG.SYS and AUTOEXEC.BAT are processed similarly to the way they are processed under MS-DOS 6.x. MS-DOS drivers and TSRs are loaded in real mode. Any hardware drivers that load at this point should use the MS-DOS configuration management services to determine how their hardware has been configured. The difference between the Windows 95 implementation and the process with MS-DOS 6.0 is that the system attempts to calculate the current configuration if the computer is a docking system. A hardware profile is selected before CONFIG.SYS is processed. If the friendly name of the hardware profile matches a multi-configuration menu item name (that is, the long text in the menu, not the section name enclosed in square brackets), the system automatically selects that multi-configuration menu item and automatically process the corresponding section of CONFIG.SYS. For more information about hardware profiles, see Hardware Profile Detection earlier in this chapter. VMM32 Real Mode Loader All VxDs were loaded under Windows 3.x by the real-mode VxD loader. Windows 95 supports both dynamically loaded drivers and static VxDs. Static VxDs can have a real-mode initialization portion. Windows 95 has added several new capabilities for statically loaded VxDs: SYMBOL 183 \f "Symbol" Access to the registry SYMBOL 183 \f "Symbol" Ability to enumerate devices SYMBOL 183 \f "Symbol" Can pass a block of data from real mode to protected mode SYMBOL 183 \f "Symbol" VxDs can be loaded from the registry The VMM32 loader loads VxDs in three distinct steps: 1. Base drivers specified in the registry 2. Static VxDs for devices enumerated by other VxDs 3. Static VxDs specified in SYSTEM.INI Loading Base Drivers Specified in the Registry VMM32 examines the registry branch SYSTEM\CurrentControlSet\Services\VxD and enumerates all keys under this branch. (Enumerate here refers to the enumeration of registry keys, not to Plug and Play enumeration.) If it finds a value StaticVxD=, it will load that static VxD and execute its real mode initialization portion. For example: SYSTEM\CurrentControlSet\Services\VxD\V86MemoryManger Description=MS-DOS Virtual 8086 Memory Manager Manufacturer=Microsoft StaticVxD=*V86MMGR Start=0 EMMEXCLUDE=E000-EFFF SYSTEM\CurrentControlSet\Services\VxD\ConfigMG Description=Plug and Play Configuration Manager Manufacturer=Microsoft StaticVxD=*CONFIGMG Start=0 SYSTEM\CurrentControlSet\Services\VxD\IOServices Description=IO Services Driver Version 4.0 Manufacturer=Microsoft StaticVxD=*IOS Start=0 Entries exist in this section of the registry for every VxD that is not directly associated with any hardware. These drivers used to be specified under [386ENH] in SYSTEM.INI. Examples of these devices are DOSMGR, V86MMGR, Reboot, VMPoll, and BiosXlat. Device specific information can be stored in the registry under the same key as the driver. In the preceding example, the V86MemoryManager key contains the value EMMEXCLUDE=E000-EFFF, which is a setting specific to the V86MMGR VxD. Any other VxD-specific information can be grouped with the driver it is associated with in the same way. VxDs can use the VMM services _GetRegistryKey or _GetRegistryPath to discern the location from which they were loaded, and then use this information to read any associated values. Although loading VxDs from SYSTEM.INI (and the associated ReadProfileString and WriteProfileString functions) will still be supported for compatibility with older drivers and setup programs, driver writers are encouraged to use this location and load method for new VxDs and associated switch settings. Real Mode Enumeration Most driver writers will not write enumerators. However, most drivers will be loaded as the result of an enumerator identifying a hardware device. Enumerators are also responsible for configuring devices on the relevant bus. The following sections discuss some specific enumerators. Root Enumerator The root enumerator is part of Configuration Manager. This enumerator contains no special detection logic and relies on the registry to determine whether a device exists. If there is an entry in the registry, the root enumerator assumes that it exists and the appropriate drivers are loaded. This is the method by which old hardware is supported, since it is usually impossible to determine with complete accuracy and safety that a particular ISA card is installed. BIOS Enumerator The BIOS enumerator is responsible for identifying all hardware devices on the motherboard of the computer. The BIOS enumerator supports the Plug and Play BIOS API which allows all Plug and Play computers to be queried in a common manner. ISAPNP Enumerator This enumerator uses the ISA Plug and Play card detection mechanism to detect with complete accuracy and safety any ISA Plug and Play-compliant cards in the system. PCI Enumerator This enumerator uses the PCI BIOS and the PCI device configuration space to detect and configure any PCI-compliant cards in the system. PCMCIA Enumerator This enumerator uses a Socket Services driver to determine whether a PCMCIA cards is inserted in each socket in the system, and for those which are present, the tuple space of the card is read to identify which card is inserted and what resources are required. EISA Enumerator This enumerator queries the EISA CMOS to discern which EISA devices are installed and what resources they consume. This enumerator will not reconfigure EISA devices. COM Enumerator This enumerator follows the Plug & Play COM specification for identifying compliant devices attached to a serial port. LPT Enumerator This enumerator uses the IEEE P1284 specification for identifying devices attached to P1284-capable parallel ports. VxDs Loaded from [386ENH] Section of SYSTEM.INI In Windows 3.x, all VxDs are loaded from the [386ENH] section of SYSTEM.INI. Windows 95 has moved most VxD loading to the registry, in order to better encapsulate driver-specific information and to enable driver loading from automated device enumeration. However, once all drivers have been loaded from the registry, any device= lines in SYSTEM.INI will be executed unless the device specified conflicts with a device loaded from the registry. In the case of a conflict, the device specified in the registry takes precedence and the device specified in SYSTEM.INI will not be loaded. Processing Before Sys_Critical_Init Message The devnode tree is constructed after entering protected mode, and after VXDLDR.VXDs early Device_Init. (VXDLDR is very early in the load order.) The root enumerator (which is part of Configuration Manager) creates device nodes for every device it can enumerate. Any static VxD that was loaded for a given device node is then sent a system control call with the following parameters: EAX = PNP_NEW_DEVNODE EBX = DEVNODE EDX = LOAD_DLVXD_DEVLOADER At this point, most VxDs return CR_DEVLOADER_NOT_READY. When a static VxD reaches the device initialization stage, it should call the CONFIGMG_Register_DevLoader function. The system will make another PNP_NEW_DEVNODE system control call, at which point the VxD can load the device driver or enumerator. (Often, the device driver and enumerator are in the same binary file, as in the case of ISAPNP.386.) A typical driver must call CONFIGMG_Register_Device_Driver, and an enumerator must additionally call CONFIGMG_Register_Enumerator. Some VxDs will also register arbitrators at this point, using the CONFIGMG_Register_Arbitrator function. Arbitrators should be loaded at SYS_CRITICAL_INIT if they are global. Configuration Manager will then call any enumerator that has been registered to further enumerate devices. All devices that were enumerated in real mode will have been allocated a complete device node by the end of this process, and any VxD that was loaded for a particular device will have been notified through the new Plug and Play system control call. Once all device nodes have been created, Configuration Manager will assign resources to each device and call the driver entry point to inform it of its new configuration. Example Plug and Play processing early in the systems entry to protected mode might follow a series of steps like this: SYMBOL 183 \f "Symbol" Configuration Manager initializes, creates root device node. SYMBOL 183 \f "Symbol" Enumerates children, creates device node for PnP BIOS. SYMBOL 183 \f "Symbol" Notifies BIOSENUM VxD that its device node exists. SYMBOL 183 \f "Symbol" DirectedSysCtrl(BIOSENUM, PNP_NEW_DEVNODE, STATIC_DRIVER, DevNodeHandle) SYMBOL 183 \f "Symbol" BIOSENUM registers as enumerator. SYMBOL 183 \f "Symbol" Configuration Manager calls BIOSENUM to enumerate. It creates device nodes and the process continues. Dynamic Driver Loading During System Boot Many Windows 95 driver models, such as IOS and the network driver models, support dynamically loaded device drivers. These VxDs are not loaded by the MS-DOS real mode loader. In the case of IOS, some drivers are true dynamically loaded VxDs, and others are mini-port SCSI drivers that are Windows NT-binary compatible. IOS loads all drivers dynamically. The process used to load these drivers is identical to the process used to dynamically load the same drivers at run-time, except that the sequence of events that starts the load process is slightly different. Dynamically loaded drivers are required to have a device loader. A device loader is responsible for loading the drivers at the correct time and in the correct order, and for making the proper initialization calls. In the case of SCSI adapter miniport drivers this device loader is IOS. A typical registry driver section for a SCSI adapter looks something like this: Enum\ISAPNP\*ABC0507\0A35BF46 DeviceDesc=ABC SCSI Vendor ISA Adapter Class=SCSIAdapter Driver=SCSIAdapter\0000 System\CurrentControlSet\Services\Class\ScsiAdapter\0000 DevLoader=*IOS MiniPortDriver=ABC.MPD Since there is no StaticVxD=xxx line in this registry entry, the VMM32 real mode loader will do nothing when the ISAPNP enumerator identifies this device. IOS is a statically loaded base driver; it receives a Device_Init system control message. During this message, IOS calls Configuration Manager to load any drivers that have a DevLoader=IOS entry by calling CONFIGMG_Register_DevLoader with the following parameters: CM_Register_DevLoader(IOS_DDB, 0); From within this function, Configuration Manager walks the devnode tree and attempts to find any device node that has a DevLoader=IOS entry in the registry. In this example, it would find the ABC adapter. This causes Configuration Manager to call back to IOS with a system control call to load the driver. DirectedSysControl("IOS", PNP_NEW_DEVNODE, DLVXD_LOAD_DEVLOADER, LoadDevNode) IOS then examines the registry and finds the MiniPortDriver=ABC.MPT, loads the driver and any associated support drivers, initializes the adapter, and returns from the function. Driver Callback Entry Point A new callback entry point is the most significant Plug and Play work required for new device drivers. This entry point is used by Configuration Manager to assign configurations. For sample code showing this entry point, see Sample Plug and Play Driver later in this chapter. VxD Initialization Most VxDs simply call CM_Register_Device_Driver to get their configuration. The VxDs entry point must be able to respond to dynamic configuration calls, particularly CONFIG_START, CONFIG_STOP, CONFIG_TEST, and CONFIG_REMOVE. Sample Plug and Play Driver Drivers are informed about their device node through a system control call issued by Configuration Manger. /* * DRIVER.C - NewDriver Support for SAMPLE * This file processes the Driver requests. */ #include #include #include #include #include #include #include #pragma VxD_LOCKED_CODE_SEG IO_RESOURCE Res1= { {2, IOType_Range, 0, 0, 0, 0, 0}, { {0xFFFF, 1, 0x103, 0x103, 0, 0xFF, 0xFF}, {0xFFFF, 1, 0x203, 0x203, 0, 0xFF, 0xFF}, } }; IO_RESOURCE Res2= { {2, IOType_Range, 0, 0, 0, 0, 0}, { {0x0300, 6, 0x200, 0x307, 0, 3, 3}, {0x03F0, 4, 0x300, 0x313, 0, 3, 3}, } }; /***************************************************************** * * ConfigHandler - Handler of the Configuration Manager * configuration call * * Exported. * * ENTRY: Standard config handler. * EXIT: Standard Configuration Manager return value. * ****************************************************************/ CONFIGRET CM_HANDLER ConfigHandler(CONFIGFUNC cfFuncName, SUBCONFIGFUNC scfSubFuncName, DEVNODE dnToDevNode, DEVNODE dnAboutDevNode, ULONG ulFlags) { LOG_CONF lc; RES_DES rd; CONFIGRET status; switch (cfFuncName) { case CONFIG_FILTER: // Get the first filtered logical configuration. status=CM_Get_First_Log_Conf(&lc, dnAboutDevNode, FILTERED_LOG_CONF); // For all logical configuration (we stopped when // the status is not CR_SUCCESS since it can only // become CR_NO_MORE_LOG_CONF). while (status==CR_SUCCESS) { // For all resource descriptors rd=(RES_DES)lc; while (CM_Get_Next_Res_Des(&rd, rd, ResType_Mem, NULL, 0)==CR_SUCCESS) { // For all memory resource // (for instance) do some // checking (like ISA impose // <16Meg) } // Next logical configuration. status=CM_Get_Next_Log_Conf(&lc, lc, 0); } return(CR_SUCCESS); case CONFIG_START: // You may or may not treat CONFIG_START_FIRST_START // different from CONFIG_START_DYNAMIC_START. // As far as CM goes, the first time it would // have called with CONFIG_START_DYNAMIC_START; // it will call with CONFIG_START_FIRST_START // instead. return(CR_SUCCESS); case CONFIG_TEST: return(CR_SUCCESS); case CONFIG_STOP: return(CR_SUCCESS); case CONFIG_REMOVE: // deallocate per instance data. return(LeaveInstance(CR_SUCCESS)); default: return(CR_DEFAULT); } } /***************************************************************** * * NewDriver - Register a new driver for the new device node * * Exported. * * ENTRY: DevNode is the new device node that has just been created. * * EXIT: Standard Configuration Manager return value. * ****************************************************************/ CONFIGRET CM_INTERNAL NewDriver(DEVNODE DevNode) { LOG_CONF lc; RES_DES rd1, rd2; // Any failure should use LeaveInstance to unload the DLVxD if // it is the only instance. Only if it is success will we not // return with an "OR"ed CR_UNLOAD. // BUGBUG error checking CM_Add_Empty_Log_Conf(&lc, DevNode, 0, BASIC_LOG_CONF); CM_Add_Res_Des(&rd1, lc, ResType_IO, &Res1, SIZEOF_IORANGE(2), 0); CM_Add_Res_Des(&rd2, lc, ResType_IO, &Res2, SIZEOF_IORANGE(2), 0); CM_Register_Device_Driver(DevNode, ConfigHandler, 0); // Allocate per instance data return(CR_SUCCESS); } Run-Time Processing The following sections describe various run-time or dynamic events and features that may be useful to plug and play drivers. Application Time Appy Time Processing A dynamic hardware event can cause many configuration changes. For example, if the user inserts a PCMCIA card that is a SCSI interface, then I/O, IRQ, and DMA resources need to be allocated, drivers need to be loaded, and the SCSI drives need to be enumerated. Although the event that starts this process is triggered by a hardware interrupt to the PCMCIA socket driver, the remainder of the processing needs to take place when the file system can be accessed, memory can be allocated, and so on. The Windows 95 SHELL VxD has implemented a set of services that allow this processing to be deferred, to a point termed application time. Code that runs at application time is essentially a subroutine executed on behalf of a Windows application. At application time, code can be unlocked, memory can be allocated, and any call that an application can make is also valid for a VxD. All Configuration Manager events are processed at application time. When an enumerator detects the addition of hardware to the system, it calls CONFIGMG_Reenumerate_DevNode(DEVNODE_TO_BE_ENUMERATED, 0) which causes Configuration Manager to wait until application time and then call the enumerator back. Run-Time Dynamic Device Loading Plug and Play permits devices to be loaded dynamically after the system is already running. The following list shows how this process occurs: 1. An enumerator detects the addition of a device to the system and calls Configuration Manger to reenumerate its own device node, using CONFIGMG_Reenumerate_DevNode as follows: CM_Reenumerate_DevNode(DevNode, 0); 2. CONFIGMG_Reenumerate_DevNode causes Configuration Manager to call back the enumerator at application time. When called back, the enumerator detects the new hardware and constructs a device ID (for example, PCMCIA\3C08AF\0). The enumerator creates a new child device node with this ID and returns from the enumeration function. 3. Configuration Manager uses the device ID to determine which key in the registry to inspect. In this example, Configuration Manager will look in HARDWARE\ENUM\PCMCIA\3C08AF\0\DRV\, where it will find DEVLOADER=NetWrap.386. If this VxD is not already loaded, Configuration Manager dynamically loads NetWrap.386. 4. Once the device loader is available, Configuration Manager sends a system control call to the network wrapper, passing it the device node for which it is the device loader, as follows: DirectedSysCtrl(NetWrap, PNP_NEW_DEVNODE, DEVLOADER, pdnNew) 5. NetWrap registers as the enumerator for this node, and then examines the registry to find the appropriate NDIS driver to load. In our example, NetWrap would find SYSTEM\CurrentControlSet\Services\Class\PCMCIA NdisDriver=XYZ.VXD 6. Once loaded, XYZ.VXD registers as the device driver for the device node, forcing Configuration Manager to assign resources to it. Configuration Manager informs the NDIS driver of the assigned configuration, thus enabling the network adapter. Windows GUI Driver Initialization Ring 3 Windows drivers may still be loaded from SYSTEM.INI for compatibility purposes, but individual subsystems such as the display may create methods to load their drivers from the registry instead. Refer to the documentation for the particular subsystem to determine the appropriate load method. Run-Time Dynamic Events A new feature of Windows 95 is the ability of device drivers and applications to query and notify each other about changes in the state of the system, particularly changes in the system hardware. Although Windows applications have been able to broadcast messages to other Windows applications in all releases of Windows subsequent to 3.0, it was not possible for VxDs to do so, nor was it possible to query other system components before taking action. Applications can use Windows 95s new capabilities to take appropriate action for such events as the addition or removal of a device; for example, an application that is using a floppy disk can use these API elements to receive a notification if the floppy disk is removed. The SHELL_BroadcastSystemMessage function broadcasts a message to one or more of the following classes of system components: SYMBOL 183 \f "Symbol" Windows applications SYMBOL 183 \f "Symbol" Virtual device drivers (VxDs) SYMBOL 183 \f "Symbol" Installable Windows ring 3 device drivers SYMBOL 183 \f "Symbol" Network drivers The counterpart to the SHELL_BroadcastSystemMessage function that is used by Windows applications is the BroadcastSystemMessage function. Windows applications receive broadcast system messages through their normal message procedure. The message is not sent to child windows. The WM_DEVICECHANGE message identifies a change in the status of the system hardware; it can be used with SHELL_BroadcastSystemMessage to inform system components of hardware changes. WM_DEVICECHANGE includes a number of query notifications; an application can return QUERY_VETOED to a query notification to veto the specified action. Processing System Broadcasts from a VxD Virtual device drivers can send and receive system broadcast messages under Windows 95. The notification services are provided by the shell VxD. To receive system broadcast messages, VxDs must call the SHELL_HookSystemBroadcast function. Between the sending of Sys_Critial_Init and when a VxD receives the WM_STARTSESSION notification, application time events are not processed. Also, during this time, broadcasts are sent only to VxDs (since other Windows system components are not loaded). This rule also applies to the time between a successful WM_ENDSESSION notification and Sys_Critical_Exit. During these phases of system operations, VxDs must send notifications only during times when other VxDs can safely respond to them. During all other times, SHELL_BroadcastSystemMessage must only be called at application time. WM_STARTSESSION WM_STARTSESSION reserved = wParam // undefined reserved = lParam // undefined Informs VxDs that the Windows user interface component is now active and that the SHELL_CallAtAppyTime services will now work. Special Notifications for VxDs VxDs receive WM_QUERYENDSESSION and WM_ENDSESSION messages when the Windows user interface component is shut down. These notifications have the same purpose as the WM_ENDSESSION message received by Windows applications. VxDs can refuse to allow Windows to shut down during the WM_QUERYENDSESSION broadcast. For more details on the wParam values for these broadcasts, refer to the Windows software development kit (SDK). VxDs may also receive WM_STARTSESSION, a special notification that is not sent to Windows applications or drivers. New Services in the VMM32 Real Mode Loader Several new capabilities have been added to the real mode VxD loader. This section briefly discusses the services that have been added. Parameters to Real Mode Initialization New parameters to the real mode initialization portions of VxDs will be added to allow a driver to determine where in the registry it was loaded from (and therefore where to look for switch settings.) This mechanism is still under definition. Registry Access In Windows 95, several functions have been added both to the real-mode VxD loader and to the Virtual Machine Manager to allow VxDs full access to the registry during initialization and during normal run time. Many of the standard Win32 and 16-bit registry access functions are also supported. In most cases, VxDs can write to the registry in protected mode. However, VxDs cannot write to the registry during the real-mode initialization phase, nor can they gain access to the HKEY_CURRENT_USER key until following the Init_Complete phase. For more information, see Chapter 9, Registry Services. Passing a Block of Data to Protected Mode The Windows Virtual Machine Manager versions 3.1 and later provides a Loader Services entry point. LoaderServices 16:16 address is passed to a VxDs real-mode initialization routine in the ECX register to provide various services. Windows 95 (that is, VMM version 4.0 and later, which is passed to the VxDs real-mode entry point in AX) provides a new service, LDRSRV_Copy_Extended_Memory, which allocates a block of extended memory in the specified data group (init, locked, or pageable) to the size requested and initializes the block with the given data. Installation On Windows 95 The setup information contained in the .INF portion of the driver cross-references hardware IDs and drivers, so Setup can determine which piece of hardware a given driver corresponds to. Hardware devices can list compatible IDs as part of their .INF portion, or in the PNP ISA case, the hardware can return the compatibility information directly as part of the device identification sequence. (Other enumeration schemes, such as PCMCIA, may also be able to return the compatible IDs directly from hardware interrogation.) For example, if a SVGA adapter is compatible with standard VGA, that can be specified as part of the .INF file. The same is true for drivers which implement a superset of a standard driver. At installation, setup will attempt to use the best match of hardware to software driver as the default choice. Driver Setup Process Assume that an enumerator identifies a new device. If the registry entry does not exist, Configuration Manager runs the device installer and calls back to the enumerator to ask for additional information. This additional information is for the use of the device installer and can include a device description and a list of compatible device IDs. For example, an SVGA card might return the generic Windows VGA or SVGA device IDs (PNP0900 and/or PNP0901 respectively). The device installer then searches .INF files to find any driver(s) that work on this device, and copies the appropriate information to the registry. When this process is complete, Configuration Manager continues with the device node as usual. New PCMCIA Card Example If the user inserts an XYZ PCMCIA card, the tuples allow the PCMCIA enumerator to determine a device ID of PCMCIA\XYZ\0. If Configuration Manager does not find any registry entry for this card, it launches the device installer. The device installer would then ask the PCMCIA enumerator for additional information, such as compatible Device IDs. If no additional information was available, the device installer would then open all .INF files searching for matches of PCMCIA\XYZ. It might find setup information in a file named XYZ.INF. Setup may optionally ask for user confirmation of the device identification at this point. The device installer would then update the registry with the appropriate information for the card (including the name of the driver to load). The driver would be dynamically loaded, and the device would be enabled. New ISA P&P Sound Card Example At boot time the ISAPNP enumerator might detect a card with the ISAPNP\*FSC0407\28AF363 device ID. If Configuration Manager could not find an appropriate entry in the registry, it would launch the device installer after protected-mode startup. The device installer would ask ISAPNP for additional information about the new card. It might receive the following: SYMBOL 183 \f "Symbol" Description=Freds Sound Card SYMBOL 183 \f "Symbol" CompatIDs=*SBD0400 (Sound blaster) Device installer might find a match of the compatible ID with an existing Sound Blaster driver and prompt the user as follows: You have installed a new Freds Sound Card. Windows can make this device work, however if this device has an installation diskette, you should place it in drive A: The user would then put the disk supplied with the card in drive A, and choose a Use setup diskette button. The device installer might find an exact match of ID *FSC0407 in the file FREDCARD.INF and use this as the driver. The rest of the process proceeds as in New PCMCIA Card Example. Loader Services These services are provided by the real-mode VxD loader. LDRSRV_Copy_Extended_Memory VOID LDRSRV_Copy_Extended_Memory() Allocates a block of extended memory in the specified data group (init, locked, or pageable) to the size requested and initializes the block with the given data. SYMBOL 183 \f "Symbol" CY flag is clear and EAX contains the linear address of the memory block if the service is successful. CY is set if the allocation failed and no memory block is allocated AX 0006h, the function number for this service. CX Number of bytes to allocate. DX Type of data being allocated. It can be one of the following values: ValueMeaningLDRSRV_COPY_INITINIT data LDRSRV_COPY_LOCKEDLOCKED dataLDRSRV_COPY_PAGEABLEPAGEABLE data  DS:SI Address of data to be copied. This service is provided by the real-mode VxD loader. It provides a convenient way for a VxD to pass more than a single DWORD of data to their protected-mode portions. The VxD can simply create a block of extended memory and pass its linear address through the VxD reference DWORD (that is, the value of EDX on exit from real-mode initialization). Actual sizes of blocks are always rounded up to the nearest DWORD. Multiple blocks allocated by a single VxD are guaranteed to be contiguous in linear address space, but not necessarily in physical address space. PAGEABLE data may actually be allocated as LOCKED data, at the loader's discretion. Initialization (INIT) data is always locked, and is discarded after all VxD initialization phases are completed. Chapter SEQ CHAPTER \R 33 Configuration Manager About Configuration Manager The Configuration Manager is the central component of the Plug and Play architecture. Working in conjunction with other components, the Configuration Manager finds workable configurations for all devices of the computer so that each device can use its assigned IRQ number, I/O port addresses, and other resources without conflict with other devices. The Configuration Manager also helps monitor the computer for changes in the number and type of devices present and manages the reconfiguration of the devices as needed when changes take place. The Configuration Manager works in conjunction with enumerators, resource arbitrators, device loaders, and device drivers to create and maintain the configuration. It provides services and messages that these components use to carry out their configuration tasks. This chapter describes these services and messages and explains how they are used. Hardware Tree, Device Nodes, and Device Identifiers The hardware tree is a structure, in memory that is built and maintained by the Configuration Manager. The hardware tree contains configuration information for all devices in the computer and Configuration Manager uses it to keep track of the resources associated with each device, such as IRQs, IO ports and even non-sharable resources like SCSI identifiers. The hardware tree describes existing devices and resources, resource requirements, resource interdependencies, and current resource allocations. A device node is a specific entry in the hardware tree. Each device node contains a unique device identifier and a list of resource requirements. The device identifier is a string which uniquely describes the device. The string typically identifies the component that found the device, but because it is also used as a key in the registry, it must be unique within the system so that information about the device can be retrieved reliably. The requirements list identifies the type resources the device needs to successfully operate and any constraints associated with those resources. IRQs, IO ports, DMA channels and memory ranges are examples of types of resources. Constraints are often resource interdependencies; such a device requiring that it must use IRQ3 and IO port 02F8 in combination in order to operate successfully. Although a device driver or other component cannot access the hardware tree or the device nodes directly, it can retrieve a handle to any device node and carry out tasks that retrieve and set information in the device node. The Configuration Manager provides these services to carry out tasks on a device node: CONFIGMG_Create_DevNode CONFIGMG_Disable_DevNode CONFIGMG_Enable_DevNode CONFIGMG_Get_Child CONFIGMG_Get_Depth CONFIGMG_Get_Device_ID CONFIGMG_Get_Device_ID_Size CONFIGMG_Get_DevNode_Status CONFIGMG_Get_Parent CONFIGMG_Get_Sibling CONFIGMG_Locate_DevNode CONFIGMG_Move_DevNode CONFIGMG_Query_Remove_SubTree CONFIGMG_Reenumerate_DevNode CONFIGMG_Remove_SubTree CONFIGMG_Remove_Unmarked_Children CONFIGMG_Reset_Children_Marks CONFIGMG_Setup_DevNode The device nodes in the hardware tree are arranged hierarchically. This means a device node is either at the root of the hardware tree or is the child of a parent device node. A device node can have child device nodes. The other children of a device nodes parent are call siblings. The hardware tree is built each time the computer is started. Furthermore, it is completely dynamic, changing even while the computer is running if a device is removed or added to the system. Logical Configurations A logical configuration is a description of the resources required by a device to operate successfully. Any given device can have several possible logical configurations. The Configuration Manager uses the logical configurations of a device to determine how to allocate resources among competing devices. The Configuration Manager provides services that device drivers, enumerators, and other components can use to examine and create logical configurations. There are these logical configuration services: CONFIGMG_Add_Empty_Log_Conf CONFIGMG_Free_Log_Conf CONFIGMG_Query_Change_HW_Prof CONFIGMG_Get_Alloc_Log_Conf CONFIGMG_Get_First_Log_Conf CONFIGMG_Get_Next_Log_Conf CONFIGMG_ISAPNP_To_CM CONFIGMG_Read_Registry_Log_Confs Device drivers typically use the CONFIGMG_Add_Empty_Log_Conf service to create empty logical configurations in which they can fill their explicit resource requirements. Device drivers and other components use the CONFIGMG_Get_First_Log_Conf and CONFIGMG_Get_Next_Log_Conf services to check all logical configurations associated with a device node. A device driver uses the CONFIGMG_Get_Alloc_Log_Conf service to retrieve its assigned (allocated) resources. Resource Descriptors A resource descriptor describes the resources in a logical configuration. There are resource descriptors for memory, IO ports, DMA channels, and IRQs. Other resource descriptors can be created as needed to identifies other types of resources available to devices. Memory resource descriptors identify memory address ranges. The descriptor contains a MEM_DES structure that describes the memory resource and an array of MEM_RANGE structures that identify the possible memory configurations. I/O port resource descriptors identify IO port address ranges. The descriptor contains an IO_DES structure that describes the IO port resource and and array of IO_RANGE structures that identify the possible port configurations. DMA channel resource descriptors identify a set of DMA channel alternatives. The descriptor is a DMA_DES structure that identifies the DMA channels that the device can use. IRQ resource descriptors identify a set of IRQ alternatives. The descriptor is a IRQ_DES structure that identifies the IRQs the device can use and whether the IRQ can be shared. The Configuration Manager provides services that device drivers and other components can use to examine and modify resource descriptors. There are these services: CONFIGMG_Add_Res_Des CONFIGMG_Free_Res_Des CONFIGMG_Get_Next_Res_Des CONFIGMG_Get_Res_Des_Data CONFIGMG_Get_Res_Des_Data_Size CONFIGMG_Modify_Res_Des When working with IO port resource descriptors, the IOR_Alias and IOR_Decode values specify the port aliases that a device responds to. A port alias is an address that the device responds to as if it were the actual address of an IO port. Additionally, some cards will actually use additional ports for different purposes, but use a decoding scheme that makes it seem as though they were using aliases; for example, an ISA card may decode 10 bits and require port 03C0h. This card would need to specify an IOR_Alias offset of 04h and a IOR_Decode of 3 (no aliases are used as actual ports). For convenience, the alias field can be set to zero indicate no aliases are required; in this case, the decode field is ignored. If the card were to use the ports at 7C0h, 0BC0h, and 0FC0h, where these ports have different functionality, the IOR_Alias value would be the same and the IOR_Decode value would be 0Fh, indicating that bits 11 and 12 of the port address were significant. Thus, the allocation is for all of the ports (PORT[i] + (n*alias*256)) & (decode*256 | 03FFh), where n is any integer and PORT is the range specified by the IOR_nPorts, IOR_Min, and IOR_Max fields. Note that the minimum alias is 4 and the minimum decode is 3. Because of the history of the ISA bus, it is assumed that all EISA and ISA cards that use any port where PORT = n*400 + Z (where Z is a port in the range 100h - 3ffh, and N is greater than or equal to 1) will reserve port Z and treat the other port(s) as aliases. If a port that falls in this set is reserved but the driver does not reserve the "Z" address, it is assumed that the device is on a local bus (such as PCI) where the reserved port address is not presented on the ISA bus. Device Loader Services and Messages A device loader loads and manages device drivers and enumerators for a given device node. Device loaders are typically used when devices are managed by various layers of device drivers. The device loader coordinates the work of the various layers and carries out general configuration tasks that apply to all device drivers. The Configuration Manager provides services that device loaders can use to carry out their tasks. There are these services: CONFIGMG_Get_DDBs CONFIGMG_Get_Private_DWord CONFIGMG_Load_DLVxD CONFIGMG_Register_DevLoader CONFIGMG_Set_Private_DWord A device loader registers itself by using the CONFIGMG_Register_DevLoader service. This associates the device loader with the given device node. The device loader can also load an enumerator and device driver for the given device node or any child device nodes by using the CONFIGMG_Load_DLVxD service. It can also retrieve and assign private values to device nodes by using the CONFIGMG_Get_Private_DWord and CONFIGMG_Set_Private_DWord services. You can retrieve the device descriptor block for any dynamically loaded virtual device associated with a device node by using the CONFIGMG_Get_DDBs service. Enumerator Services and Messages Enumerators locate and identify Plug and Play devices and retrieve information about these devices to use to construct the hardware tree. The Configuration Manager provides services for registering enumerators as well as services enumerators can use to carry out their enumeration tasks. In particular, an enumerator can register an enumeration handler function by using the CONFIGMG_Register_Enumerator service. The Configuration Manager sends an enumeration message to this handler whenever it needs the enumerator to carry out a task. There are these enumeration services: CONFIGMG_CallBack_Enumerator CONFIGMG_Get_Bus_Info CONFIGMG_Register_Enumerator CONFIGMG_Set_Bus_Info There are these enumeration messages: CONFIG_ENUMERATE CONFIG_FILTER CONFIG_REMOVE CONFIG_START CONFIG_STOP CONFIG_TEST The enumeration handler must return CR_DEFAULT for any messages it does not not process. Enumerators are responsible for creating device identifiers for the devices they locate. Each identifier must be unique and be consistently the same on each system boot. The string must be constructed so that it can serve to identify a unique entry in the registry. The string must start with the enumerator's name followed by a backslash. For example, the ISA Plug and Play enumerator starts all device identifiers with "ISAPNP\". Device Driver Services and Messages A device driver controls and manages the device hardware. Device drivers are responsible for identifying the specific resource requirements of the given device and for setting the device to operate with the configuration assigned by the Configuration Manager. The Configuration Manager provides services and messages that a device can use to carry out its takes. In particular, a device driver can register a configuration handler function by using the CONFIGMG_Register_Device_Driver service. Once the handler is registered, the Configuration Manager sends it configuration messages whenever it needs the device driver to carry out a configuration task. There are these device driver services: CONFIGMG_CallBack_Device_Driver CONFIGMG_Get_Device_Driver_Private_DWord CONFIGMG_Register_Device_Driver CONFIGMG_Set_Device_Driver_Private_DWord There are these configuration messages: CONFIG_ENUMERATE CONFIG_FILTER CONFIG_REMOVE CONFIG_START CONFIG_STOP CONFIG_TEST The device driver must return CR_DEFAULT for any configuration messages it does not process. Resource Arbitrator Services and Messages Resource arbitrators resolve resource conflicts between devices. An arbitrator reviews a list of requirements for devices and finds the best allocation of resources to satisfy all devices. The Configuration Manager provides services and messages to support the operation of resource arbitrators. In particular, arbitrators register an arbitrator handler function with the Configuration Manager by using the CONFIGMG_Register_Arbitrator service. Once registered, this handler receives arbitration messages from the Configuration Manager whenever resolution of a conflict for the corresponding resource is needed. There are these arbitrator services: CONFIGMG_Register_Arbitrator CONFIGMG_Deregister_Arbitrator CONFIGMG_Query_Arbitrator_Free_Size CONFIGMG_Query_Arbitrator_Free_Data There are this arbitration messages: ARB_FORCE_ALLOC ARB_QUERY_FREE ARB_RELEASE_ALLOC ARB_REMOVE ARB_RETEST_ALLOC ARB_SET_ALLOC ARB_TEST_ALLOC The arbitration handler must return CR_DEFAULT for any messages it does not not process. Range Lists A range list is a sorted list of IO port or memory address ranges (in DWORD form) in which no two ranges overlap. Resource arbitrators that manage I/O and memory resources use the range list services to discover whether a given IO or memory range conflicts with any other range. These services detect attempts to create range lists containing overlaps and either fail or create merged ranges where there would have been overlaps. Each range must specify a continguous range of addresses, but the range list itself can contain multiple ranges, none of which necessarily need to be contiguous with any other range in the list. There are these range list services: CONFIGMG_Create_Range_List CONFIGMG_Add_Range CONFIGMG_Delete_Range CONFIGMG_Test_Range_Available CONFIGMG_Dup_Range_List CONFIGMG_Free_Range_List CONFIGMG_Invert_Range_List CONFIGMG_Intersect_Range_List CONFIGMG_First_Range CONFIGMG_Next_Range CONFIGMG_Dump_Range_List Registry Services Device drivers and other components can store information about a given device node in the registry as well as retrieve information about a device node stored in the registry by the Configuration Manager. There are these registry services: CONFIGMG_Get_DevNode_Key CONFIGMG_Get_DevNode_Key_Size CONFIGMG_Read_Registry_Value CONFIGMG_Write_Registry_Value Hardware Profile Services A hardware profile is a set of information that defines the hardware present in the system. Hardware profiles are typically used in docking systems in which the number and type of devices may be different with each docking station. The typical docking system has one hardware profile for each docking station and one for when it is not docked. When the system boots, docks or undocks, each enumerator reenumerates its hardware, determining what is available and creating or removing device nodes to reflect that availability. The enumerator uses the hardware-profile services to create and maintain the hardware profiles for the system. There are these services: CONFIGMG_Fail_Change_HW_Prof CONFIGMG_Get_HW_Prof_Flags CONFIGMG_Recompute_HW_Prof CONFIGMG_Set_HW_Prof CONFIGMG_Set_HW_Prof_Flags The hardware-profile flags apply to each device node and identify whether the device node should be created for a given profile. You can get and set the flags by using the CONFIGMG_Get_HW_Prof_Flags and CONFIGMG_Set_HW_Prof_Flags services. Miscellaneous Services Device drivers and other components use the miscellaneous services to carry out various support tasks or debugging. There are these services: CONFIGMG_Call_At_Appy_Time CONFIGMG_Set_Private_Problem CONFIGMG_Get_CRC_CheckSum CONFIGMG_Get_Version CONFIGMG_Lock CONFIGMG_Process_Events_Now CONFIGMG_Unlock CONFIGMG_Yield Reference This section describes the Configuration Manager services, callback functions, messages, structures, and constants. Services This section describes the Configuration Manager services. CONFIGMG_Add_Empty_Log_Conf Creates an empty logical configuration. This configuration has no resource descriptor. CONFIGRET CONFIGMG_Add_Empty_Log_Conf(PLOG_CONF plcLogConf, DEVNODE dnDevNode, PRIORITY Priority, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_PRIORITY, CR_INVALID_POINTER or CR_OUT_OF_MEMORY. Parameters plcLogConf Address that receives the handle of the logical configuration. dnDevNode Address of a device node. This address is typically retrieved by a call to CONFIGMG_Locate_DevNode or CONFIGMG_Create_DevNode. Priority Priority of the logical configuration. This parameter can be one of the following values: LCPRI_FORCECONFIG Coming from a forced config. LCPRI_BOOTCONFIG Coming from a boot config. LCPRI_HARDWIRED Like VPICD's IO range. LCPRI_DESIRED Preferable set (better performance). LCPRI_NORMAL Workable (acceptable performance). LCPRI_SUBOPTIMAL Not desired but will work (like PIO). LCPRI_RESTART Need to restart Windows. LCPRI_REBOOT Need to reboot Windows. LCPRI_POWEROFF Need to shutdown Windows. LCPRI_HARDRECONFIG Need to change a jumper. ulFlags Either BASIC_LOG_CONF or FILTERED_LOG_CONF, combined with either PRIORITY_EQUAL_FIRST or PRIORITY_EQUAL_LAST. BASIC_LOG_CONF Specifies the requirements list. FILTERED_LOG_CONF Specifies the filtered requirements list. PRIORITY_EQUAL_FIRST Same priority, new one is first. PRIORITY_EQUAL_LAST Same priority, new one is last. Comments Note: Calling CONFIGMG_Add_Empty_Log_Conf or CONFIGMG_Free_Log_Conf from within a CONFIGMG_Get_First_Log_Conf/CONFIGMG_Get_Next_Log_Conf loop may have unwelcome side effects. Drivers should end the loop before adding or freeing a logical configuration and start it again when the operation is finished. See Also CONFIGMG_Create_DevNode CONFIGMG_Free_Log_Conf CONFIGMG_Get_First_Log_Conf CONFIGMG_Get_Next_Log_Conf CONFIGMG_Locate_DevNode CONFIGMG_Add_ID Add an hardware or compatible id during CONFIG_SETUP. CONFIGRET CONFIGMG_Add_ID(DEVNODE dnDevNode, PFARCHAR pszID, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_POINTER or CR_INVALID_FLAG. Parameters dnDevNode Handle of a device node. pszID Points to a id to add. ulFlags Must be CM_ADD_ID_HARDWARE or CM_ADD_ID_COMPATIBLE. CONFIGMG_Add_Range Adds a memory range to a range list. CONFIGRET CONFIGMG_Add_Range(ULONG ulStartValue, ULONG ulEndValue, RANGE_LIST rlh, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_FLAG, CR_INVALID_RANGE, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY Parameters ulStartValue Low end of the range. ulEndValue High end of the range. rlh Handle of a range list. ulFlags Flags specifying options for memory ranges that conflict with ranges already in the list. This parameter must be one of the following values: CM_ADD_RANGE_ADDIFCONFLICT New range is merged with the ranges it conflicts with. CM_ADD_RANGE_DONOTADDIFCONFLICT Function returns CR_FAILURE if there is a conflict. See Also CONFIGMG_Delete_Range CONFIGMG_Add_Res_Des Adds a resource descriptor to a logical configuration. CONFIGRET CONFIGMG_Add_Res_Des(PRES_DES prdResDes, LOG_CONF lcLogConf, RESOURCEID ResourceID, PFARVOID ResourceData, ULONG ResourceLen, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_LOG_CONF, CR_INVALID_POINTER, CR_INVALID_RESOURCE_ID or CR_OUT_OF_MEMORY. Parameters prdResDes Address that receives a handle of the resource descriptor. lcLogConf The logical configuration to which the resource descriptor is added. ResourceID The type of the resource. This parameter can be one of the following: ResType_DMA DMA channels 0-3 resource ResType_IO Physical IO address resource ResType_IRQ IRQ 0-15 ResType_Mem Physical address resource ResourceData Address of a resource data structure. ResourceLen The size, in bytes, of the structure pointed to by ResourceData. ulFlags Must be zero. Comments The new resource descriptor is added to the beginning of the logical configuration's resource-descriptor list. This means that a loop using CONFIGMG_Get_Next_Res_Des will not reveal this resource descriptor unless the loop is started after the resource descriptor has been added. The logical configuration being modified must be either BASIC_LOG_CONF or FILTERED_LOG_CONF. Typically, BASIC_LOG_CONF is added to during device driver initialization or enumeration, whereas FILTERED_LOG_CONF is added to during a CONFIG_FILTER device-driver configuration function. See Also CONFIGMG_Free_Res_Des CONFIGMG_Call_At_Appy_Time CONFIGMG will call back the handler at appy time. CONFIGRET CONFIGMG_Call_At_Appy_Time(CMCALLBACKHANDLER Handler, ULONG ulRefData, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG. Parameters Handler is the function to be called at appy time. ulRefData is the parameter to the function to be called back at appy time. ulFlags Must be zero. Comments This function is functionally equivalent to SHELL_CallAtAppyTime, but allow CONFIGMG to know that it is appy time. This function is asynchronous (that is, callable at interrupt time), reentrant, and fast. CONFIGMG_Call_Enumerator_Function Call the enumerator function about a child devnode. CONFIGRET CONFIGMG_Call_Enumerator_Function(DEVNODE dnDevNode, ENUMFUNC efFunc, ULONG ulRefData, PFARVOID pBuffer, ULONG ulBufferSize, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_POINTER, CR_INVALID_FLAG or CR_INVALID_API. Furthermore, the enumerator may return the result CR_FAILURE. Parameters dnDevNode Handle of a device node. efFunc Is the function number. ulRefData Is a reference data (can't be a pointer). pBuffer Points to a buffer for the function. ulBufferSize Is the size of the buffer. ulFlags Must be zero. CONFIGMG_CallBack_Device_Driver Call back the device driver, once per devnode. with a CONFIGMG_Register_Device_Driver. CONFIGRET CONFIGMG_CallBack_Device_Driver(CMCONFIGHANDLER Handler, ULONG ulFlags) Parameters Handler The configuration handler that was registered in a call to the CONFIGMG_Register_Device_Driver function. ulFlags Must be zero. Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API or CR_INVALID_FLAG. Comments A device driver calls this function when it needs to be called back once per devnode. See Also CONFIGMG_Register_Device_Driver CONFIGMG_CallBack_Enumerator Call back the device driver, once per devnode. CONFIGRET CONFIGMG_CallBack_Enumerator(CMENUMHANDLER Handler, ULONG ulFlags) Parameters Handler is the routine that was register with a CONFIGMG_Register_Enumerator. ulFlags must be zero. Return Value Returns CR_SUCCESS if the function was successful. Otherwise, one of the following errors is returned: CR_INVALID_FLAG if ulFlags is not zero. CR_INVALID_API if called from ring 3. Comments An enumerator calls this function when it needs to be called back once per devnode. This function is synchronous and must not be called from within an interrupt handler. CONFIGMG_Create_DevNode Adds a device node to the hardware tree. CONFIGRET CONFIGMG_Create_DevNode(PDEVNODE pdnDevNode, DEVNODEID pDeviceID, DEVNODE dnParent, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_ALREADY_SUCH_DEVNODE, CR_INVALID_DEVICE_ID, CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_OUT_OF_MEMORY or CR_CREATE_BLOCKED. Parameters pdnDevNode Address that receives a handle to the new device node. Can be NULL. pDeviceID Device identifier. If this parameter is NULL, Configuration Manager does not attempt to find a device loader for the device. dnParent Handle of the device node that is the parent of the device node being created. ulFlags Must be zero. Comments Typically, an enumerator calls this function while it is enumerating new devices (during the CONFIG_ENUMERATE event). Configuration Manager allocates the device node and puts the device node in the sibling list of the child device node of dnParent. All fields are initialized to their default values. After this function returns successfully, the enumerator should fill in the fields it can, particularly the resource descriptors. When the enumerator returns from the event, Configuration Manager attempts to load a device driver for the new descendant of the enumerator's device node (if pDeviceID is not NULL). This function returns CR_ALREADY_SUCH_DEVNODE if there is already a device node corresponding to pDeviceID in the tree. (This error is not returned when pDeviceID is NULL, because there can be multiple NULL device identifiers. These cannot be found using CONFIGMG_Locate_DevNode, however.) When this error is returned, the DN_HAS_MARK flag is set, and pdnDevNode is updated to the handle of the preexisting device node. CONFIGMG_Create_Range_List Creates a list of memory ranges. CONFIGRET CONFIGMG_Create_Range_List(PRANGE_LIST prlh, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER or CR_OUT_OF_MEMORY. Parameters prlh Address that receives the handle of a range list. ulFlags Must be zero. See Also CONFIGMG_Test_Range_Available CONFIGMG_Delete_Range Deletes a memory range from a range list. CONFIGRET CONFIGMG_Delete_Range(ULONG ulStartValue, ULONG ulEndValue, RANGE_LIST rlh, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_FLAG, CR_INVALID_RANGE, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY. Parameters ulStartValue Low end of the range. ulEndValue High end of the range. rlh Handle of a range list. ulFlags Must be zero. See Also CONFIGMG_Add_Range Comments Doing a delete range with [0, ULONG_MAX] is special cased: it will empty the whole range and is guarantied not to run out of memory. CONFIGMG_Deregister_Arbitrator Removes a resource arbitrator. This function is rarely called. CONFIGRET CONFIGMG_Deregister_Arbitrator(REGISTERID id, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API, CR_INVALID_ARBITRATOR or CR_INVALID_FLAG. Parameters id The identifier of the resource arbitrator. This identifier must have been created by a call to the CONFIGMG_Register_Arbitrator function. ulFlags Must be zero. Comments This function deregisters an arbitrator and its resource but is not typically used for this purpose. If an arbitrator is global and registers with a NULL device node, it typically is never deregistered (for example, IO, IRQ, DMA and memory). If the arbitrator is local to a specific device node (for example, a PCMCIA socket), it is called automatically by the ARB_REMOVE arbitrator function when its device node is removed. See Also CONFIGMG_Register_Arbitrator CONFIGMG_Disable_DevNode Disables a device node. CONFIGRET CONFIGMG_Disable_DevNode(DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_NOT_DISABLEABLE, CR_INVALID_DEVNODE or CR_NOT_SYSTEM_VM. Parameters dnDevNode Handle of a device node. ulFlags Must be either CM_DISABLE_POLITE (where we ask the driver and give it a chance to stop) or CM_DISABLE_ABSOLUTE (where the driver will be stop even if it does not support stopping). Comments This function increments a counting semaphore. Any attempt to disable the device node increments the semaphore. The function return CR_NOT_DISABLEABLE if the devnode does not have the DN_DISABLEABLE flag set or failed the CONFIG_TEST/CONFIG_TEST_CAN_STOP message. See Also CONFIGMG_Enable_DevNode CONFIGMG_Dump_Range_List Dumps a range list on a debugging terminal. CONFIGRET CONFIGMG_Dump_Range_List(RANGE_LIST rlh, ULONG ulFlags) Return Value The return value for this function is undefined. Parameters rlh Handle of a range list. ulFlags Must be zero. CONFIGMG_Dup_Range_List Copies a range list. CONFIGRET CONFIGMG_Dup_Range_List(RANGE_LIST rlhOld, RANGE_LIST rlhNew, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY. Parameters rlhOld Handle of the range list to copy. rlhNew Handle of a valid range list into which rlhOld is copied. Anything contained in the rlhNew range list is removed by the copy operation. ulFlags Must be zero. CONFIGMG_Enable_DevNode Enables a device node. CONFIGRET CONFIGMG_Enable_DevNode(DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE or CR_NOT_SYSTEM_VM. Parameters dnDevNode Handle of a device node. ulFlags Must be zero. Comments This function decrements a counting semaphore. The device node is enabled only if the count has returned to zero and the device node does not have any other problem. See Also CONFIGMG_Disable_DevNode CONFIGMG_Fail_Change_Config Cancel preparation for changing the current Hardware Profile. CONFIGRET CONFIGMG_Fail_Change_Config(ULONG ulFlags) Return Value Returns CR_SUCCESS, CR_FAILURE, CR_NOT_SYSTEM_VM or CR_INVALID_FLAG. Parameters ulFlags Must be zero. Comments This function should only be called by a Plug and Play BIOS Enumerator if it makes a successful call to CONFIGMG_Query_Change_HW_Prof but later finds some other reason to cancel the docking or undocking action. See Also CONFIGMG_Recompute_HW_Prof CONFIGMG_Query_Change_HW_Prof CONFIGMG_First_Range Retrieves the first range element in a range list. CONFIGRET CONFIGMG_First_Range(RANGE_LIST rlh, PULONG pulStart, PULONG pulEnd, PRANGE_ELEMENT preElement, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_INVALID_RANGE_LIST. Parameters rlh Handle of a range list. pulStart Address that receives the starting value of the first range element. pulEnd Address that receives the ending value of the first range element. preElement Address that receives the handle of the next range element. ulFlags Must be zero. See Also CONFIGMG_Next_Range CONFIGMG_Free_Log_Conf Frees a logical configuration and all resource descriptors associated with it. CONFIGRET CONFIGMG_Free_Log_Conf(LOG_CONF lcLogConfToBeFreed, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE or CR_INVALID_LOG_CONF. Parameters lcLogConfToBeFreed Handle that was retrieved by a call to the CONFIGMG_Add_Empty_Log_Conf function. ulFlags Must be zero. Comments Note: Calling CONFIGMG_Add_Empty_Log_Conf or CONFIGMG_Free_Log_Conf from within a CONFIGMG_Get_First_Log_Conf/CONFIGMG_Get_Next_Log_Conf loop may have unwelcome side effects. Drivers should end the loop before adding or freeing a logical configuration and start it again when the operation is finished. See Also CONFIGMG_Add_Empty_Log_Conf CONFIGMG_Get_First_Log_Conf CONFIGMG_Get_Next_Log_Conf CONFIGMG_Free_Range_List Frees the specified range list and the memory allocated for it. CONFIGRET CONFIGMG_Free_Range_List(RANGE_LIST rlh, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG or CR_INVALID_RANGE_LIST. Parameters rlh Handle of a range list. ulFlags Must be zero. See Also CONFIGMG_Create_Range_List CONFIGMG_Free_Res_Des Destroys a resource descriptor. CONFIGRET CONFIGMG_Free_Res_Des(PRES_DES prdResDes, RES_DES rdResDes, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_RES_DES, CR_INVALID_DEVNODE or CR_NO_MORE_RES_DES. Parameters prdResDes Address that receives the handle of the previous resource descriptor. If rdResDes is the handle of the first resource descriptor, this address receives the handle of the logical configuration. rdResDes Handle of the resource descriptor to be destroyed. ulFlags Must be zero. Comments This function returns CR_NO_MORE_RES_DES if rdResDes specifies the last resource descriptor. See Also CONFIGMG_Add_Res_Des CONFIGMG_Get_Alloc_Log_Conf Get the allocated (or boot) resources in a nice table format. CONFIGRET CONFIGMG_Get_Alloc_Log_Conf(PCMCONFIG pccBuffer, DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, or CR_NO_MORE_LOG_CONF. Parameters pccBuffer is a pointer to a CMCONFIG struct (which can be on the stack) to be filled by this function with the currently allocated config. dnDevNode Device node that a device driver wants to know what are the allocated (or boot) resources. ulFlags must be one of CM_GET_ALLOC_CONFIG_ALLOC or CM_GET_ALLOC_CONFIG_BOOT_ALLOC. Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_POINTER, CR_INVALID_DEVNODE or CR_INVALID_FLAG. Comments This call is done when a device driver wants to easily know what its configuration is. This function is synchronous and must not be called from within an interrupt handler. CONFIGMG_Get_Bus_Info Get bus info of the devnode. CONFIGRET CONFIGMG_Get_Bus_Info(DEVNODE dnDevNode, PCMBUSTYPE pbtBusType, PFARULONG pulSizeOfInfo, PFARVOID pInfo, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE, CR_INVALID_POINTER, CR_BUFFER_SMALL. Parameters dnDevNode Handle of a device node. pbtBusType Will receive the bus type. pulSizeOfInfo Points to the dword that is originally the size of the info buffer and will return the size of the info put in the buffer (minimum of the real info size and the given value). If this points to a 0, pInfo is not touched and the real info size is put in *pulSizeOfInfo. pInfo A pointer to the bus-specific buffer to be filled. ulFlags Must be zero. Comments This function appends to the devnode some bus specific info. This function is to be used solely by the immediate parent enumerator of a devnode. See Also CONFIGMG_Get_Bus_Info CONFIGMG_Get_Child Retrieves the first child of a given device node. CONFIGRET CONFIGMG_Get_Child(PDEVNODE pdnDevNode, DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_NO_SUCH_DEVNODE. Parameters pdnDevNode Address that receives the handle of the device node. dnDevNode Handle of the parent device node. ulFlags Must be zero. Comments This function is called by any device driver that needs to walk the hardware tree. See Also CONFIGMG_Get_Parent CONFIGMG_Get_Sibling CONFIGMG_Get_CRC_CheckSum Computes a CRC for a specific buffer. CONFIGRET CONFIGMG_Get_CRC_CheckSum(PFARVOID pBuffer, ULONG ulSize, PFARULONG pulSeed, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG or CR_INVALID_POINTER. Parameters pBuffer Address of the buffer buffer to be "CRC"ed. ulSize Length of pBuffer. pulSeed As input, it is the seed which should be 0 on the first call. As output, it contains the result which can be used as seed for the next call. ulFlags Must be zero. Developer Notes For now, we just do CRC-16 bits. See Also CONFIGMG_Load_DLVxDs CONFIGMG_Get_DDBs Retrieves the device descriptor blocks (DDBs) of dynamically loadable VxDs for a devnode. CONFIGRET CONFIGMG_Get_DDBs(PPPVMMDDB pppDDB, PFARULONG pulCount, LOAD_TYPE LoadType, DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API, CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_LOAD_TYPE or CR_INVALID_POINTER. Parameters pppDDB Address of a pointer that receives the address of the DDBs table. If the pppDDB is NULL when the function returns, the VxD that controls the device node specified in the dnDevNode where not loaded via CM_Load_DLVxDsdynamically loadable VxD. Otherwise the DDBs are stored as an array at the given address. pulCount Returns the number of DDBs in the table. LoadType Type of the VxD being loaded. This parameter can be one of the values listed for the LoadType parameter in the CONFIGMG_Load_DLVxDs function. dnDevNode Device node identifying the dynamically loadable VxD. ulFlags Must be zero. See Also CONFIGMG_Load_DLVxDs CONFIGMG_Get_Depth Retrieves the depth of a device node in the hardware tree. CONFIGRET CONFIGMG_Get_Depth(PFARULONG pulDepth, DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER. Parameters pulDepth Address that receives the depth of the device node. This value is 0 to designate the root of the tree, 1 to designate a child of the root, and so on. dnDevNode Handle of a device node. ulFlags Must be zero. Comments This function can be used to optimize the handling of device nodes. For example, a device driver could determine the relative depths of two device nodes before processing only its immediate children. CONFIGMG_Get_Device_Driver_Private_DWord Retrieves the private value for a device driver in a device node. CONFIGRET CONFIGMG_Get_Device_Driver_Private_DWord(DEVNODE dnDevNode, PFARULONG pulDWord, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER. Parameters dnDevNode Handle of the device node in which the private value will be stored. pulDWord Address that receives the private value. ulFlags Must be zero. Comments This function is typically used by a device driver to retrieve information that was cached (usually a pointer to memory). The value is the same as passed when Config Manager call the device driver. See Also CONFIGMG_Set_Device_Driver_Private_DWord CONFIGMG_Get_Device_ID Retrieves the device identifier for a device node. CONFIGRET CONFIGMG_Get_Device_ID(DEVNODE dnDevNode, PFARVOID Buffer, ULONG BufferLen, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_BUFFER_SMALL, CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER. Parameters dnDevNode Handle of a device node we want the device ID of. Buffer Address of buffer that receives the device identifier. If this buffer is larger than the device identifier, the function appends a null-terminating character to the data. If it is smaller than the device identifier, the function fills it with as much of the device identifier as will fit and returns CR_BUFFER_SMALL. BufferLen The size, in bytes, of the buffer for the device identifier. ulFlags Must be zero. Comments To ensure that the buffer pointed to by the Buffer parameter is large enough to hold the entire device identifier, device drivers can call the CONFIGMG_Get_Device_ID_Size function. Example Code that retrieves a device identifier might look like the following example: CM_Get_Device_ID_Size(&size, dnDevNode, 0); if (p=malloc(size+1)) CM_Get_Device_ID(dnDevNode, p, size+1, 0); See Also CONFIGMG_Get_Device_ID_Size CONFIGMG_Get_Device_ID_Size Retrieves the size of a device identifier from a device node. CONFIGRET CONFIGMG_Get_Device_ID_Size(PFARULONG pulLen, DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER. Parameters pulLen Address that receives the length of the device identifier. This length does not include the null-terminating character. This address is filled with zeroes if there is no identifier. The length is always less than or equal MAX_DEVICE_ID_LEN. dnDevNode Handle of a device node. ulFlags Must be zero. Comments The device node's device identifier is built from the identifier of the enumerator immediately above this device in the hardware tree, this device's identifier, and this device's instance. For example, the device identifier for an Adaptec 1540c might be \isaenum\aha1540c\1. This string is used as the direct key for access into the registry. The device identifier is limited to MAX_DEVICE_ID_LEN bytes. See Also CONFIGMG_Get_Device_ID CONFIGMG_Get_DevNode_Key Retrieves the the string of registry key from a device node. CONFIGRET CONFIGMG_Get_DevNode_Key(DEVNODE dnDevNode, PFARCHAR pszSubKey, PFARVOID Buffer, ULONG BufferLen, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_BUFFER_SMALL or CR_NO_REGISTRY_HANDLE. Parameters dnDevNode Handle of a device node. pszSubKey Name of the subkey. Can be NULL if none. Buffer Address of the buffer that receives the registry key. The length is always less than or equal MAX_VMM_REG_KEY_LEN. BufferLen Size of the buffer. ulFlags Must be a combination of the following: CM_REGISTRY_HARDWARE Select the hardware branch. CM_REGISTRY_SOFTWARE Select the software branch. CM_REGISTRY_USER Use HKEY_CURRENT_USER. CM_REGISTRY_CONFIG Use HKEY_CURRENT_CONFIG. See Also CONFIGMG_Get_DevNode_Key_Size CONFIGMG_Get_DevNode_Key_Size Retrieves the size of the registry key from a device node. CONFIGRET CONFIGMG_Get_DevNode_Key_Size(PFARULONG pulLen, DEVNODE dnDevNode, PFARCHAR pszSubKey, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, or CR_NO_REGISTRY_HANDLE. Parameters pulLen Address that receives the length of the registry key. This length does not include the null-terminating character. This address is filled with zeroes if there is no identifier. The length is always less than or equal MAX_VMM_REG_KEY_LEN. dnDevNode Handle of a device node. pszSubKey Name of the subkey. Can be NULL if none. ulFlags Must be a combination of the following: CM_REGISTRY_HARDWARE Select the hardware branch. CM_REGISTRY_SOFTWARE Select the software branch. CM_REGISTRY_USER Use HKEY_CURRENT_USER. CM_REGISTRY_CONFIG Use HKEY_CURRENT_CONFIG. See Also CONFIGMG_Get_DevNode_Key CONFIGMG_Get_DevNode_Status Retrieves the status of a device node. CONFIGRET CONFIGMG_Get_DevNode_Status(PFARULONG pulStatus, PFARULONG pulProblemNumber, DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER. Parameters pulStatus Address that receives the status flags of the device node. These flags can be a combination of the following values: DN_DRIVER_LOADED CONFIGMG_Register_Device_Driver has been called for this device node. DN_ENUM_LOADED CONFIGMG_Register_Enumerator has been called for this device node. DN_HARDWARE_ENUM Enumeration generates hardware identifier. DN_HAS_MARK CONFIGMG_Create_DevNode has failed in a call for this device node. DN_HAS_PROBLEM The device installer is required to resolve conflicts. DN_LIAR Device node reported reconfiguration falsely once. DN_NEED_TO_CONFIG Device node may need reconfiguration. This flag can be changed asynchronously. DN_NEED_TO_ENUM Device node may need reenumeration. This flag can be changed asynchronously. DN_NOT_FIRST_TIME Device node has received a configuration. DN_ROOT_ENUMERATED Device node was enumerated by the root. DN_STARTED Device node is currently configured. pulProblemNumber Address that receives an identifier indicating the problem. This identifier can be one of the following: CM_PROB_BOOT_CONFIG_CONFLICT Conflict in boot configuration. CM_PROB_DEVICE_NOT_THERE Specified device does not exist. CM_PROB_DEVLOADER_FAILED Device loader failed. CM_PROB_DEVLOADER_NOT_READY Device loader is not ready. CM_PROB_DISABLED Device is disabled. CM_PROB_ENTRY_IS_WRONG_TYPE Registry value has different type. CM_PROB_FAILED_FILTER Filter failed. CM_PROB_NO_CONFIGURED No configuration for this device. CM_PROB_NORMAL_CONFLICT Configuration conflict. CM_PROB_OUT_OF_MEMORY Out of memory. CM_PROB_REGISTRY Unable to access the registry. CM_PROB_VXDLDR Failure using the VxD loader. dnDevNode Device node for which the status flags are retrieved. ulFlags Must be zero. CONFIGMG_Get_First_Log_Conf Returns a handle to the first logical configuration of the specified type in a device node. CONFIGRET CONFIGMG_Get_First_Log_Conf(PLOG_CONF plcLogConf, DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER or CR_NO_MORE_LOG_CONF. Parameters plcLogConf Address that receives the handle of the logical configuration. dnDevNode Device node for which the logical configuration is retrieved. ulFlags One of the following values: ALLOC_LOG_CONF Specifies the Alloc Element. BASIC_LOG_CONF Specifies the requirements list. BOOT_LOG_CONF Specifies the boot Alloc Element. FILTERED_LOG_CONF Specifies the filtered requirements list. Comments An initializing device driver typically requests the BASIC_LOG_CONF to verify the work of the enumerator. Sometimes the initializing driver may also check BOOT_LOG_CONF. Drivers typically check FILTERED_LOG_CONF while processing the CONFIG_FILTER device-driver configuration function. ALLOC_LOG_CONF is typically checked while processing CONFIG_DYNAMIC_START, CONFIG_DYNAMIC_STOP, CONFIG_FIRST_CONFIG and CONFIG_REMOVE. Comments Note: Calling CONFIGMG_Add_Empty_Log_Conf or CONFIGMG_Free_Log_Conf from within a CONFIGMG_Get_First_Log_Conf/CONFIGMG_Get_Next_Log_Conf loop may have unwelcome side effects. Drivers should end the loop before adding or freeing a logical configuration and start it again when the operation is finished. See Also CONFIGMG_Add_Empty_Log_Conf CONFIGMG_Free_Log_Conf CONFIGMG_Get_Next_Log_Conf CONFIGMG_Get_Hardware_Profile_Info Get inpormation about a hardware profile. CONFIGRET CONFIGMG_Get_Hardware_Profile_Info(ULONG ulIndex, PHWPROFILEINFO pHWProfileInfo, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful, CR_NO_MORE_DEVNODES if ulIndex is larger than the number of hardware profiles on the computer. Otherwise, the return value can be CR_INVALID_POINTER or CR_INVALID_FLAG. Parameters ulIndex The index of the hardware profile to examine. Hardware profiles go from 0 to the number of hardware profiles-1. A ulIndex value of 0xFFFFFFFF is the same as the index of the current hardware profile. pHWProfileInfo Structure to be filled. ulFlags Must be zero. CONFIGMG_Get_HW_Prof_Flags Get the Config-Specific Config flags for a devnode/hardware profile combination. CONFIGRET CONFIGMG_Get_HW_Prof_Flags(PCHAR szDevNodeName, ULONG ulConfig, PULONG pulValue, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER or CR_REGISTRY_ERROR. Parameters szDevNodeName The name of the devnode to query. ulConfig The hardware profile number to query. A ulConfig value of 0 indicates the current hardware profile should be queried. pulValue Points to the location to store the Config-Specific Config flags. ulFlags Must be zero. See Also CONFIGMG_Set_HW_Prof_Flags CONFIGMG_Get_Next_Log_Conf Returns a handle to the next logical configuration following the given configuration. CONFIGRET CONFIGMG_Get_Next_Log_Conf(PLOG_CONF plcLogConf, LOG_CONF lcLogConf, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_LOG_CONF, CR_INVALID_POINTER or CR_NO_MORE_LOG_CONF. Parameters plcLogConf Address receiving the handle of the next logical configuration. lcLogConf Logical configuration prior to the configuration whose handle is being retrieved. Note that the logical configurations are in priority order. Parameters ulFlags Must be zero. Comments When this function is called with a logical configuration that was obtained using the CONFIGMG_Get_First_Log_Conf function with either the ALLOC_LOG_CONF or BOOT_LOG_CONF flag it necessarily returns CR_NO_MORE_LOG_CONF. (There is only one active boot or currently allocated logical configuration.) Comments Note: Calling CONFIGMG_Add_Empty_Log_Conf or CONFIGMG_Free_Log_Conf from within a CONFIGMG_Get_First_Log_Conf/CONFIGMG_Get_Next_Log_Conf loop may have unwelcome side effects. Drivers should end the loop before adding or freeing a logical configuration and start it again when the operation is finished. See Also CONFIGMG_Add_Empty_Log_Conf CONFIGMG_Free_Log_Conf CONFIGMG_Get_First_Log_Conf CONFIGMG_Get_Next_Res_Des Retrieves the handle of the next resource descriptor in a logical configuration. CONFIGRET CONFIGMG_Get_Next_Res_Des(PRES_DES prdResDes, RES_DES rdResDes, RESOURCEID ForResource, PRESOURCEID pResourceID, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_LOG_CONF, CR_INVALID_RES_DES or CR_NO_MORE_RES_DES. Parameters prdResDes Address that receives the handle of the next resource descriptor. rdResDes Handle of the current resource descriptor or the handle of a logical configuration. (Both are 32-bit numbers; Configuration Manager can distinguish between them.) ForResource One of the resource identifiers listed in the ResourceId parameter of the CONFIGMG_Add_Res_Des function, or ResType_All. If this parameter is ResType_All, the function returns the handle of the next resource descriptor, no matter what its type. Otherwise, the function retrieves the handle of the first resource descriptor of the specified type. pResourceID Address that receives the resource type, when ForResource specifies ResType_All. (When ForResource is not ResType_All, this parameter can be NULL.) ulFlags Must be zero. See Also CONFIGMG_Get_Res_Des_Data CONFIGMG_Get_Res_Des_Data_Size CONFIGMG_Get_Parent Retrieves the handle of the parent of a device node. CONFIGRET CONFIGMG_Get_Parent(PDEVNODE pdnDevNode, DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_NO_SUCH_DEVNODE. Parameters pdnDevNode Address that receives a handle to the parent device node. dnDevNode Handle of the child device node. ulFlags Must be zero. Comments This function is called by any device driver that needs to walk the hardware tree. See Also CONFIGMG_Get_Child CONFIGMG_Get_Sibling CONFIGMG_Get_Performance_Info This API works only in MAXDEBUG. It returns or reset performance info in a buffer. CONFIGRET CONFIGMG_Get_Performance_Info(PCMPERFINFO pPerfInfo, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_FAILURE (CM_PERFORMANCE_INFO was not defined) or CR_INVALID_POINTER. Parameters pPerfInfo Address that will receive the size (in bytes) of the resource-descriptor header. ulFlags Must be one of CM_PERFORMANCE_INFO_GET_DATA CM_PERFORMANCE_INFO_RESET, CM_PERFORMANCE_INFO_START or CM_PERFORMANCE_INFO_STOP. CONFIGMG_Get_Private_DWord Retrieves the private value a device node has in another device node. CONFIGRET CONFIGMG_Get_Private_DWord(PFARULONG pulPrivate, DEVNODE dnInDevNode, DEVNODE dnForDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_INVALID_POINTER. Parameters pulPrivate Address that receives the private value. dnInDevNode Handle of the device node in which the private value will be stored. dnForDevNode Handle of the device node that will use this information. This device node must be either the same as dnInDevNode or an ancestor of dnInDevNode. ulFlags Must be zero. Comments Neither dnInDevNode nor dnForDevNode may specify the root of the hardware tree. This function is typically used by an enumerator to retrieve information that was cached in a one of their children's device nodes using the CONFIGMG_Set_Private_DWord function. The private double-word value is typically a pointer to a structure. Note that the device node specified by the dnForDevNode parameter is responsible for cleaning up when the device node is removed. See Also CONFIGMG_Set_Private_DWord CONFIGMG_Get_Res_Des_Data Copies the data from a specified resource descriptor into a buffer. CONFIGRET CONFIGMG_Get_Res_Des_Data(RES_DES rdResDes, PFARVOID Buffer, ULONG BufferLen, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_BUFFER_SMALL, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_INVALID_RES_DES. Parameters rdResDes Resource descriptor from which data is copied. Buffer Address of buffer that receives the data. B      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrtuvwxyz{|}~ufferLen Size of Buffer, in bytes. ulFlags Must be zero. Comments Typically the size of the buffer is determined by a previous call to CONFIGMG_Get_Res_Des_Data_Size. If the value given in the BufferLen parameter is too small, the data is truncated, and the function returns CR_BUFFER_SMALL. See Also CONFIGMG_Get_Res_Des_Data_Size CONFIGMG_Get_Res_Des_Data_Size Retrieves the size of a resource descriptor, not including the resource-descriptor header. CONFIGRET CONFIGMG_Get_Res_Des_Data_Size(PFARULONG pulSize, RES_DES rdResDes, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER or CR_INVALID_RES_DES. Parameters pulSize Address that receives the size, in bytes, of the resource descriptor's data. rdResDes Handle of the resource descriptor whose size is being queried. ulFlags Must be zero. See Also CONFIGMG_Get_Res_Des_Data CONFIGMG_Get_Sibling Retrieves the sibling of a device node. CONFIGRET CONFIGMG_Get_Sibling(PDEVNODE pdnDevNode, DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_NO_SUCH_DEVNODE. Parameters pdnDevNode Address that receives a handle to the sibling device node. dnDevNode Handle of a device node. ulFlags Must be zero. Comments This function can be called in a loop to retrieve all the siblings of a device node. When the function returns CR_NO_SUCH_DEVNODE, the device node has no more siblings. See Also CONFIGMG_Get_Child CONFIGMG_Get_Parent CONFIGMG_Get_Version Retrieves Configuration Manager's version number. CONFIGRET CONFIGMG_Get_Version() Return Value The high byte of the return value is the major revision number and the low byte is the minor revision number. The high word is not used. This is the only service where the result is not a CR_ something. Comments For example, version 4.0 of Configuration Manager returns 0x0400. This function currently returns 0x0400. CONFIGMG_Initialize Ensures that Configuration Manager is ready to accept function calls, by creating the root node of the hardware tree and installing and allocating the required resources. This function is typically called only by VMM and VXDLDR. No other VxD should call this function. CONFIGRET CONFIGMG_Initialize(ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Does not return otherwise. Parameters ulFlags Must be either CM_INITIALIZE_VMM (the VMM is initializing Configuration Manager prior to Sys_Critical_Init) or CM_INITIALIZE_VXDLDR (VXDLDR is ready). Comments Only internal Windows 95 components use this function. CONFIGMG_Intersect_Range_List Creates a range list from the intersection of two specified range lists. CONFIGRET CONFIGMG_Intersect_Range_List(RANGE_LIST rlhOld1, RANGE_LIST rlhOld2, RANGE_LIST rlhNew, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY. Parameters rlhOld1 Handle of a range list to be used as part of the intersection. rlhOld2 Handle of a range list to be used as part of the intersection. rlhNew Handle of a valid range list that represents the intersection of rlhOld1 and rlhOld2. Anything contained in the rlhNew range list is removed by the operation. ulFlags Must be zero. Comments If this function returns CR_OUT_OF_MEMORY, rlhNew is the handle of a valid but empty range list. See Also CONFIGMG_Merge_Range_List CONFIGMG_Invert_Range_List Creates a range list that is the inverse of a specified range list; all claimed memory ranges in the new list are specified as free in the old list, and vice-versa. CONFIGRET CONFIGMG_Invert_Range_List(RANGE_LIST rlhOld, RANGE_LIST rlhNew, ULONG ulFlags, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY. Parameters rlhOld Handle of the range list to be inverted. rlhNew Handle of a valid range list that receives the inverted copy of rlhOld. Anything contained in the rlhNew range list is removed by the operation. ulFlags Uppermost value of the inverted range list. ulFlags Must be zero. Comments For example, the inversion of {[2, 4], [6, 8]} when the ulMaxValue parameter is 15 is {[0, 1], [5, 5], [9, 15}. If this function returns CR_OUT_OF_MEMORY, rlhNew is the handle of a valid but empty range list. CONFIGMG_ISAPNP_To_CM Converts ISAPNP requirements and adds them to a specified device node. CONFIGRET CONFIGMG_ISAPNP_To_CM(PBYTE pBuffer, DEVNODE dnDevNode, ULONG ulLogDev, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_DEVNODE_HAS_REQS, CR_INVALID_DATA, CR_INVALID_DEVNODE, CR_OUT_OF_MEMORY, CR_NO_SUCH_LOG_DEV, CR_INVALID_FLAG or CR_INVALID_POINTER. Parameters pBuffer Address of a buffer that contains the ISAPNP requirement information. This information normally starts with a Plug and Play version number tag. dnDevNode Device node that receives the converted requirements. This device node must not already contain a logical configuration (requirements). ulLogDev Logical device number starting with 0. ulFlags Must be either CM_ISAPNP_ADD_RES_DES if using this API to convert resource data into a BASIC_LOG_CONF, CM_ISAPNP_ADD_BOOT_RES_DES if using this API to convert resource data into a BOOT_LOG_CONF. Otherwise it must be CM_ISAPNP_SETUP to do a setup on those values. CONFIGMG_Load_DLVxDs Loads dynamically loadable VxDs for a devnode. CONFIGRET CONFIGMG_Load_DLVxDs(DEVNODE dnDevNode, PFARCHAR FileNames, LOAD_TYPE LoadType, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_LOAD_TYPE, CR_INVALID_POINTER, CR_FAILURE, CR_OUT_OF_MEMORY, CR_NOT_SYSTEM_VM or CR_DLVXD_NOT_FOUND. Parameters dnDevNode Device node for which a device driver or enumerator should be loaded. FileNames Filenames for the dynamically loadable VxD. Note that the .386 extension is required. If no path is specified, the function searches for the files the same way OpenFile does. The files can be space or comma delimited. LoadType Type of the VxD being loaded. This parameter can be one of the following values: DLVXD_LOAD_DEVLOADER Load as a device loader. (This type is rarely used.) DLVXD_LOAD_DRIVER Load as a device driver. DLVXD_LOAD_ENUMERATOR Load as an enumerator. ulFlags Must be zero. CONFIGMG_Locate_DevNode Retrieves a pointer to the device node corresponding to a specified device identifier. CONFIGRET CONFIGMG_Locate_DevNode(PDEVNODE pdnDevNode, DEVNODEID pDeviceID, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVICE_ID, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_NO_SUCH_DEVNODE. Parameters pdnDevNode Address that receives the handle of a device node. pDeviceID Address of a null-terminated string specifying a device identifier. This string is also the name of the corresponding registry key. If this parameter is NULL, the function retrieves a handle to the device node at the root of the hardware tree. ulFlags Must be zero. CONFIGMG_Lock Prevents Configuration Manager from sending events. CONFIGRET CONFIGMG_Lock(ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG. Parameters ulFlags Must be zero. Comments This function increments a counting semaphore that prevents Configuration Manager from sending events. Since Configuration Manager processes events during the system task time but with interrupts disabled at the critical places, there is little need to bracket a linear piece of VxD code or an interrupt handler. Comments This function is asynchronous (that is, callable at interrupt time), reentrant, and fast. See Also CONFIGMG_Process_Events_Now CONFIGMG_Unlock CONFIGMG_Merge_Range_List Creates a range list from the union of two specified range lists. CONFIGRET CONFIGMG_Merge_Range_List(RANGE_LIST rlhOld1, RANGE_LIST rlhOld2, RANGE_LIST rlhNew, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_RANGE_LIST or CR_OUT_OF_MEMORY. Parameters rlhOld1 Handle of a range list to be used as part of the union. rlhOld2 Handle of a range list to be used as part of the union. rlhNew Handle of a valid range list that represents the union of rlhOld1 and rlhOld2. Anything contained in the rlhNew range list is removed by the operation. ulFlags Must be zero. Comments If this function returns CR_OUT_OF_MEMORY, rlhNew is the handle of a valid but empty range list. See Also CONFIGMG_Intersect_Range_List CONFIGMG_Modify_Res_Des Modifies a resource descriptor. CONFIGRET CONFIGMG_Modify_Res_Des(PRES_DES prdResDes, RES_DES rdResDes, RESOURCEID ResourceID, PFARVOID ResourceData, ULONG ResourceLen, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_RES_DES, CR_INVALID_DEVNODE or CR_OUT_OF_MEMORY. Parameters prdResDes Address that receives the handle of the modified resource descriptor. rdResDes Handle of the resource descriptor to be modified. Parameters ResourceID One of the resource identifiers given in the ResourceId parameter of the CONFIGMG_Add_Res_Des function, ResType_All, or ResType_None. If this parameter is a resource type, the resource descriptor changes to have this type. If it is ResType_All, the previous resource type is preserved. If it is ResType_None, the resource descriptor is ignored, because arbitrators for ResType_None always succeed. Parameters ResourceData Address of a resource data structure. Parameters ResourceLen The size, in bytes, of the new resource data structure. (The new size can be different from the size before the modifications were made.) ulFlags Must be zero. Comments This function retrieves a handle to the new resource descriptor. This may or may not be the handle of the unmodified resource descriptor. The previous resource descriptor is invalid after calling this function. See Also CONFIGMG_Add_Res_Des CONFIGMG_Move_DevNode Replace a root enumerated devnode by the valid non-root enumerated devnode. CONFIGRET CONFIGMG_Move_DevNode(DEVNODE dnFromDevNode, DEVNODE dnToDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE, CR_OUT_OF_MEMORY or CR_NOT_SYSTEM_VM. Parameters dnFromDevNode Handle of the device node that has been root enumerated. dnToDevNode Handle of the device node that is a reenumeration of a root devnode. ulFlags Must be zero. Comments This function is used by the device installer when it detects that a non-root enumerate devnode is really the same as its root enumerated counterpart. This function rename the root-enumerated devnode with the new name (so that for the current session, people using CONFIGMG_Read/Write_Registry go to the appropriate place) and mark the root enumerated devnode has having a problem. CONFIGMG_Next_Range Returns the next range element in a range list. CONFIGRET CONFIGMG_Next_Range(PRANGE_ELEMENT preElement, PULONG pulStart, PULONG pulEnd, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_INVALID_RANGE. Parameters preElement Address of the handle of a range element. If this function is successful, this parameter points to the handle of the next range element when the function returns. pulStart Address that receives the starting value of the first range. pulEnd Address that receives the ending value of the first range. ulFlags Must be zero. Comments This function returns CR_FAILURE if there are no more elements in the range list. See Also CONFIGMG_First_Range CONFIGMG_Process_Events_Now Forces event processing to occur immediately. CONFIGRET CONFIGMG_Process_Events_Now(ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG or CR_NOT_SYSTEM_VM. Parameters ulFlags Must be zero. Comments There is no reason a standard device driver would ever call this function. It is meant to localize the event processing when debugging Configuration Manager using a Windows application. The application would call CONFIGMG_Lock, any required Configuration Manager functions, CONFIGMG_Process_Events_Now, and CONFIGMG_Unlock. Note that this function overides the locking mechanism. See Also CONFIGMG_Lock CONFIGMG_Unlock CONFIGMG_Query_Arbitrator_Free_Data Returns arbitrator-specific free information. CONFIGRET CONFIGMG_Query_Arbitrator_Free_Data(PFARVOID pData, ULONG DataLen, DEVNODE dnDevNode, RESOURCEID ResourceID, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_BUFFER_SMALL, CR_FAILURE, CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_RESOURCEID or CR_NO_ARBITRATOR. Parameters pData Address of a buffer that receives the free information. This information is arbitrator specific. DataLen The size (in bytes) of the data buffer. dnDevNode Device node associated with the arbitrator. This is most meaningful for local arbitrators. (Although any device node can be used for global arbitrators, this parameter should specify the root or NULL in that case.) ResourceID One of the resource identifiers listed in the ResourceId parameter of the CONFIGMG_Add_Res_Des function. This function returns CR_INVALID_RESOURCEID if this value is ResType_All or ResType_None. ulFlags Must be zero. Comments This function succeeds even when it returns CR_BUFFER_SMALL. To avoid this error, call CONFIGMG_Query_Arbitrator_Free_Size before calling this function. See Also CONFIGMG_Add_Res_Des CONFIGMG_Query_Arbitrator_Free_Size CONFIGMG_Query_Arbitrator_Free_Size Retrieves the size of the free information the arbitrator would return in a call to the CONFIGMG_Query_Arbitrator_Free_Data function. CONFIGRET CONFIGMG_Query_Arbitrator_Free_Size(PFARULONG pulSize, DEVNODE dnDevNode, RESOURCEID ResourceID, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_RESOURCEID, CR_FAILURE or CR_NO_ARBITRATOR. Parameters pulSize Address that receives the size information. dnDevNode Device node associated with the arbitrator. This is most meaningful for local arbitrators. (Although any device node can be used for global arbitrators, this parameter should specify the root or NULL in that case.) ResourceID One of the resource identifiers listed in the ResourceId parameter of the CONFIGMG_Add_Res_Des function. This function returns CR_INVALID_RESOURCEID if this value is ResType_All or ResType_None. ulFlags Must be zero. See Also CONFIGMG_Add_Res_Des CONFIGMG_Query_Arbitrator_Free_Data CONFIGMG_Query_Change_Config Determine if it is okay to change the current Hardware Profile. CONFIGRET CONFIGMG_Query_Change_Config(ULONG ulDock, ULONG ulSerialNo, ULONG ulFlags) Return Value Returns CR_SUCCESS if it is okay to change the hardware profile, CR_FAILURE if it is not okay. Otherwise, the return value can be CR_INVALID_FLAG, CR_NOT_SYSTEM_VM or CR_REGISTRY_ERROR. Parameters ulDock The Docking Station Identifier of the dock that the computer is attempting to connect to, 0 if unknown or if this is a request to undock. ulSerialNo The Docking Station Serial Number of the dock that the computer is attempting to connect to, 0 if unknown or if this is a request to undock. ulFlags Must be one of the following: CM_HW_PROF_UNDOCK The computer is attempting to undock. CM_HW_PROF_DOCK The computer is attempting to dock to an unidentified dock. CM_HW_PROF_DOCK_KNOWN The computer is attempting to dock to a known dock, which is identified by the ulDock and ulSerialNo paramters. Comments This function should only be called by a Plug and Play BIOS Enumerator. This function leaves some Root enumerated devnodes in an inactive state. After calling this function either CONFIGMG_Recompute_HW_Prof or CM_Fail_Change_HW_Prof must be called to return the Root enumerated devnodes to a normal state. See Also CONFIGMG_Recompute_HW_Prof CONFIGMG_Fail_Change_HW_Prof CONFIGMG_Query_Remove_SubTree Checks whether a device node and its progeny can be removed. CONFIGRET CONFIGMG_Query_Remove_SubTree(DEVNODE dnAncestor, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_REMOVE_VETOED, or CR_NOT_SYSTEM_VM. Parameters dnAncestor The root of the subtree whose removal is being queried. ulFlags Must be zero. Example If the hardware can only detect removal, the enumerator should call CONFIGMG_Remove_SubTree; this is problematic, because it does not give applications the opportunity to close their files. If the hardware has an indication that the user wants to remove it (that is, if it is software-eject capable), the enumerator should follow the steps shown in this example: if (CM_Query_Remove_Subtree(dnDevNode, 0)==CR_SUCCESS) CM_Remove_SubTree(dnDevNode, 0); See Also CONFIGMG_Remove_Subtree CONFIGMG_Read_Registry_Log_Confs Retrieves logigal configuarations from the registry. CONFIGRET CONFIGMG_Read_Registry_Log_Confs(DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_OUT_OF_MEMORY, CR_INVALID_DATA, or CR_REGITRY_ERROR. Parameters dnDevNode Handle of a device node. ulFlags Must be zero. Comments This API is for the root enumerator, MCA and EISA bus driver. Instead of hardwarely detect the possible logical configurations, those enumerators rely on this API to read logical configurations from the hardware LogConfig subkey into the BASIC_LOG_CONF list. CONFIGMG_Read_Registry_Value Retrieves a value in the registry. CONFIGRET CONFIGMG_Read_Registry_Value(DEVNODE dnDevNode, PFARCHAR pszSubKey, PFARCHAR pszValueName, ULONG ulExpectedType, PFARVOID Buffer, PFARULONG pulLength, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_NO_SUCH_VALUE, CR_WRONG_TYPE, CR_REGITRY_ERROR or CR_BUFFER_SMALL. Parameters dnDevNode Handle of a device node. The devnode can have a NULL device ID, but in this case, CR_NO_SUCH_VALUE is returned. pszSubKey Name of the subkey. Can be NULL if none. pszValueName Name of the value. ulExpectedType Either REG_SZ if a string is wanted or REG_BINARY if a binary value is wanted. Buffer Address of the buffer that receives the registry data. This can be NULL if you just want to get the size of the value. pulLength The length of the buffer (both input and output). ulFlags Must be a combination of the following: CM_REGISTRY_HARDWARE Select the hardware branch. CM_REGISTRY_SOFTWARE Select the software branch. CM_REGISTRY_USER Use HKEY_CURRENT_USER. CM_REGISTRY_CONFIG Use HKEY_CURRENT_CONFIG. See Also CONFIGMG_Write_Registry_Value CONFIGMG_Recompute_HW_Prof Calculate the current Hardware Profile based on the Docking Station Identifier and the Docking Station Serial ID. CONFIGRET CONFIGMG_Recompute_HW_Prof(ULONG ulDock, ULONG ulSerialNo, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_FAILURE, CR_NOT_SYSTEM_VM or CR_REGISTRY_ERROR. Parameters ulDock The Docking Station Identifier if the computer is docked, 0 if the computer is undocked. ulSerialNo The Docking Station Serial Number if the computer is docked, 0 if the computer is undocked. ulFlags Must be one of the following: CM_HW_PROF_UNDOCK The computer is undocked. CM_HW_PROF_DOCK The computer is docked. Comments This function should only be called by a Plug and Play BIOS Enumerator, after a successful dock change. See Also CONFIGMG_Set_HW_Prof CONFIGMG_Fail_Change_HW_Prof CONFIGMG_Reenumerate_DevNode Causes the enumerator of the specified device node to receive the CONFIG_ENUMERATE enumerator function. CONFIGRET CONFIGMG_Reenumerate_DevNode(DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG. There is no checking of a valid devnode until later. Parameters dnDevNode The device node whose enumerator will be called. ulFlags Must be zero. Comments This function is asynchronous (that is, callable at interrupt time), reentrant, and fast. CONFIGMG_Register_Arbitrator Registers a resource arbitrator. CONFIGRET CONFIGMG_Register_Arbitrator(PREGISTERID pRid, RESOURCEID id, CMARBHANDLER Handler, ULONG ulDWordToBePassed, DEVNODE dnArbitratorNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API, CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER, CR_INVALID_RESOURCEID, CR_INVALID_ARBITRATOR or CR_OUT_OF_MEMORY. Parameters pRid Address that receives the registration identifier of the resource arbitrator. id The unique resource number as given or defined by Microsoft Corporation. Handler Arbitrator entry point. This is the routine that will handle all arbitrator functions. This parameter cannot be NULL. Parameters ulDWordToBePassed The value that is passed when calling the arbitrator. Parameters dnArbitratorNode Handle of the device node that owns this resource. This value is important for local arbitrators, but it can be NULL for a global arbitrator. This value is passed when calling the arbitrator. ulFlags Specifies whether the resource is global. If it is ARB_LOCAL, the resource is local to only the children of dnArbitratorNode. Otherwise, it is ARB_GLOBAL. Comments This function returns CR_INVALID_RESOURCEID if the ResType_Ignored_Bit set in the device identifier. See Also CONFIGMG_Deregister_Arbitrator CONFIGMG_Register_Device_Driver Registers a configuration handler for a device node. CONFIGRET CONFIGMG_Register_Device_Driver(DEVNODE dnDevNode, CMCONFIGHANDLER Handler, ULONG ulRefData, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_NOT_SYSTEM_VM. Parameters dnDevNode Handle of a device node. This handle must have been created by a call to the CONFIGMG_Locate_DevNode or CONFIGMG_Create_DevNode function. Handler Device-driver entry point. This is the routine that will handle all device-driver configuration functions. This parameter can be NULL if the device driver does not need to monitor configuration events. ulRefData Data that will be passed back to the Handler. ulFlags Must be either CM_REGISTER_DEVICE_DRIVER_STATIC or a combination of CM_REGISTER_DEVICE_DRIVER_DISABLEABLE and/or CM_REGISTER_DEVICE_DRIVER_REMOVABLE. Comments This function must be called by any Plug and Play device that owns a device node. It should be called only when the initializing device driver is ready to start handling the device. Note that this API can be called from ring 3 but the handler needs to be NULL in that case. See Also CONFIGMG_Create_DevNode CONFIGMG_Locate_DevNode CONFIGMG_Register_DevLoader Specifies that a static VxD is ready to be a device loader. CONFIGRET CONFIGMG_Register_DevLoader(PVMMDDB pDDB, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API or CR_INVALID_FLAG. Parameters pDDB The static VxD which is ready to be a device loader. ulFlags Must be zero. Comments If the DDB parameter is NULL or not valid, the function returns CR_SUCCESS but takes no action. Also, any PNP_NEW_DEVNODE will necessarily occur after this function returns (ie, on the next appy time). CONFIGMG_Register_Enumerator Registers the enumerator handler for a device node. CONFIGRET CONFIGMG_Register_Enumerator(DEVNODE dnDevNode, CMENUMHANDLER Handler, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API, CR_INVALID_DEVNODE or CR_INVALID_FLAG. Parameters dnDevNode Handle of a device node. This handle must have been created by a call to the CONFIGMG_Locate_DevNode or CONFIGMG_Create_DevNode function. Handler Enumerator entry point. This is the routine that will handle all enumerator calls. If this parameter is NULL, no enumerator is loaded. ulFlags CM_REGISTER_ENUMERATOR_HARDWARE iff the enumerator does hardware detection (ie know for sure the device is there or not. Otherwise, must be CM_REGISTER_ENUMERATOR_SOFWARE. Comments This function must be called whenever a device driver needs to be the enumerator for a device. This function should be called near the end of the initialization of an enumerator. The Handler parameter is NULL when the device cannot be enumerated (as with VPICD, for example). See Also CONFIGMG_Create_DevNode CONFIGMG_Locate_DevNode CONFIGMG_Register_Enumerator_Function Register a handler to handle enumerator specific functions. CONFIGRET CONFIGMG_Register_Enumerator_Function(DEVNODE dnDevNode, CMENUMFUNCTION Handler, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_API or CR_INVALID_FLAG. Parameters dnDevNode Handle of a device node. Handler The callback address. ulFlags Must be zero. CONFIGMG_Remove_SubTree Removes a device node and its children. CONFIGRET CONFIGMG_Remove_SubTree(DEVNODE dnAncestor, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG or CR_NOT_SYSTEM_VM. Parameters dnAncestor Handle of the device node that is being removed. ulFlags Must be zero. Comments Configuration Manager notifies each device node in the subtree of the dnAncestor parameter of its imminent termination and then, if possible, frees the device nodes. If a PCMCIA SCSI card were removed, for example, the PCMCIA driver would use this function to remove the entire subtree from the hardware tree. See Also CONFIGMG_Query_Remove_SubTree CONFIGMG_Remove_Unmarked_Children Removes any children of a device node for which the DN_HAS_MARK flag is cleared. CONFIGRET CONFIGMG_Remove_Unmarked_Children(DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_NOT_SYSTEM_VM or CR_INVALID_FLAG. Parameters dnDevNode Device node that is the parent of the device nodes which are removed if their DN_HAS_MARK flag is cleared. ulFlags Must be zero. See Also CONFIGMG_Reset_Children_Marks CONFIGMG_Reset_Children_Marks Resets the DN_HAS_MARK flag in the children of a specified device node. CONFIGRET CONFIGMG_Reset_Children_Marks(DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE or CR_INVALID_FLAG. Parameters dnDevNode Device node that is the parent of the device nodes whose DN_HAS_MARK flags are reset. ulFlags Must be zero. See Also CONFIGMG_Remove_Unmarked_Children CONFIGMG_Run_Detection Ask CONFIGMG to spawn the detection DLL and run it. CONFIGRET CONFIGMG_Run_Detection(ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG. Parameters ulFlags Must be zero. Comments This API will be used by devloader that detects a legacy card has been inserted. CONFIGMG_Set_Bus_Info Set bus info in the devnode. CONFIGRET CONFIGMG_Set_Bus_Info(DEVNODE dnDevNode, CMBUSTYPE btBusType, ULONG ulSizeOfInfo, PFARVOID pInfo, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE, CR_INVALID_POINTER, CR_OUT_OF_MEMORY. Parameters dnDevNode Handle of a device node. btBusType The bus valud (one of BusType*). ulSizeOfInfo The size of the info buffer pointed by pInfo. pInfo A pointer to the bus-specific info. ulFlags Must be zero. Comments This function appends to the devnode some bus specific info. This function is to be used solely by the immediate parent enumerator of a devnode. See Also CONFIGMG_Get_Bus_Info CONFIGMG_Set_Device_Driver_Private_DWord Retrieves the private value for a device driver in a device node. CONFIGRET CONFIGMG_Set_Device_Driver_Private_DWord(DEVNODE dnDevNode, PFARULONG pulDWord, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE or CR_INVALID_FLAG. Parameters dnDevNode Handle of the device node in which the private value will be stored. pulDWord Address that receives the private value. ulFlags Must be zero. Comments This function is typically used by a device driver to set information in this devnode cached (usually a pointer to memory). Note that the initial value is set by the parameter on the CONFIGMG_Register_Device_Driver (the value is zero before that call). See Also CONFIGMG_Get_Device_Driver_Private_DWord CONFIGMG_Set_HW_Prof Set the current Hardware Profile. CONFIGRET CONFIGMG_Set_HW_Prof(ULONG ulConfig, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG CR_FAILURE, CR_NOT_SYSTEM_VM or CR_REGISTRY_ERROR. Parameters ulConfig The current hardware profile number. ulFlags Must be zero. Comments This function updates the HKEY_CURRENT_CONFIG predefined key in the registry, broadcasts a DBT_CONFIGCHANGED message, and reenumerates the Root devnode. It should only be called by the configuration manager and the control panel. See Also CONFIGMG_Recompute_HW_Prof CONFIGMG_Set_HW_Prof_Flags Set the Config-Specific Config flags for a devnode/hardware profile combination. CONFIGRET CONFIGMG_Set_HW_Prof_Flags(PCHAR szDevNodeName, ULONG ulConfig, ULONG ulValue, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_NOT_SYSTEM_VM, CR_INVALID_POINTER or CR_REGISTRY_ERROR. Parameters szDevNodeName The name of the devnode to modify. ulConfig The hardware profile number to modify. A ulConfig value of 0 indicates the current hardware profile should be modified. ulValue The new CSConfigFlags value. It may contain the following flags: CSCONFIGFLAG_DISABLE Disable the devnode in this hardware profile. CSCONFIGFLAG_DO_NOT_CREATE Do not allow this devnode to be created in this hardware profile. ulFlags Must be zero. Comments If the CONFIGFLAG_DO_NOT_CREATE bit is set for an existing devnode in the current hardware profile, it will be removed. If the CSCONFIGFLAG_DO_NOT_CREATE bit is cleared in the current hardware profile, the entire hardware tree will be reenumerated, so that the devnode's parent has the chance to create the devnode if necessary. See Also CONFIGMG_Set_HW_Prof_Flags CONFIGMG_Set_Private_DWord Sets the private value a device node has in another device node. CONFIGRET CONFIGMG_Set_Private_DWord(DEVNODE dnInDevNode, DEVNODE dnForDevNode, ULONG ulValue, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE or CR_INVALID_FLAG. Parameters dnInDevNode Handle of the device node in which the private value will be stored. dnForDevNode Handle of the device node that will use this information. This device node must be either the same as dnInDevNode or an ancestor of dnInDevNode. ulValue The private value to be stored. is the value to store. ulFlags Must be zero. Comments Neither dnInDevNode nor dnForDevNode may specify the root of the hardware tree. This function is typically used by an enumerator to set information that will be retrieved using the CONFIGMG_Get_Private_DWord function. The private double-word value is typically a pointer to a structure. The device node specified by the dnForDevNode parameter is responsible for cleaning up when the device node is removed. See Also CONFIGMG_Get_Private_DWord CONFIGMG_Set_Private_Problem Make CONFIGMG call the Private API with that devnode and the reference data. CONFIGRET CONFIGMG_Set_Private_Problem(DEVNODE dnDevNode, ULONG ulRefData, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE or CR_INVALID_FLAG. Parameters dnDevNode Handle of a device node. ulRefData Reference data to pass to the class installer. ulFlags Must be zero. Comments This API does not disable the devnode. CONFIGMG_Setup_DevNode Reenables and configures a specified device node, or ask the enumerator to download information. CONFIGRET CONFIGMG_Setup_DevNode(DEVNODE dnDevNode, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG, CR_INVALID_DEVNODE, CR_NOT_SYSTEM_VM, CR_OUT_OF_MEMORY or CR_FAILURE. Parameters dnDevNode Device node which may be reconfigured. Parameters ulFlags Must be either CM_SETUP_DEVNODE_READY (for reenabling a devnode that had a problem) or CM_SETUP_DOWNLOAD (to ask the enumerator to download information). CONFIGMG_Sort_NodeList Sorts a list of nodes that has been passed to the handler of to a resource arbitrator. CONFIGRET CONFIGMG_Sort_NodeList(NODELIST_HEADER nlhNodeListHeader, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_API, CR_INVALID_FLAG or CR_INVALID_NODELIST. Parameters nlhNodeListHeader Address of a NODELISTHEADER_S structure containing the elements to sort. ulFlags Must be zero. Comments This function is normally used by an arbitrator to sort the nodelist it is given during a call to the arbitrator's handler. Normally, an arbitrator sorts the nodelist by increasing ease of configuration; for example, an element that had only one possible IRQ would come before an element with 2 possible IRQs, and so on. The arbitrator must first do a linear scan of the nodelist initializing nl_ulSortDWord (the lower the value, the more at the begining the element will be). CONFIGMG_Test_Range_Available Checks a memory range against a range list to ensure that no conflicts exist. CONFIGRET CONFIGMG_Test_Range_Available(ULONG ulStartValue, ULONG ulEndValue, RANGE_LIST rlh, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_FAILURE, CR_INVALID_FLAG, CR_INVALID_RANGE or CR_INVALID_RANGE_LIST. Parameters ulStartValue Low end of the range. ulEndValue High end of the range. rlh Handle of a range list. ulFlags Must be zero. CONFIGMG_Unlock Reenables Configuration Manager events after a call to the CONFIGMG_Lock function. CONFIGRET CONFIGMG_Unlock(ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_FLAG. Parameters ulFlags Must be zero. Comments This function decrements the counting semaphore that prevents Configuration Manager from sending events. If the count is zero, Configuration Manager begins sending events again. This function is asynchronous (that is, callable at interrupt time), reentrant, and fast. See Also CONFIGMG_Lock CONFIGMG_Process_Events_Now CONFIGMG_Write_Registry_Value Sets a value in the registry. CONFIGRET CONFIGMG_Write_Registry_Value(DEVNODE dnDevNode, PFARCHAR pszSubKey, PFARCHAR pszValueName, ULONG ulType, PFARVOID Buffer, ULONG ulLength, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INVALID_DEVNODE, CR_INVALID_FLAG, CR_INVALID_POINTER or CR_REGITRY_ERROR. Parameters dnDevNode Handle of a device node. The devnode cannot have a NULL device ID. pszSubKey Name of the subkey. Can be NULL if none. pszValueName Name of the value. ulType Either REG_SZ if a string is to be written or REG_BINARY if a binary value is to be written. Buffer Address of the buffer that contains the registry data to write. ulLength The length of the buffer. ulFlags Must be a combination of the following: CM_REGISTRY_HARDWARE Select the hardware branch. CM_REGISTRY_SOFTWARE Select the software branch CM_REGISTRY_USER Use HKEY_CURRENT_USER. CM_REGISTRY_CONFIG Use HKEY_CURRENT_CONFIG. See Also CONFIGMG_Read_Registry_Value CONFIGMG_Yield Waits a specified number of microseconds. CONFIGRET CONFIGMG_Yield(ULONG ulMicroseconds, ULONG ulFlags) Return Value Returns CR_SUCCESS if the function is successful. Otherwise, the return value can be CR_INTERRUPTS_DISABLED or CR_INVALID_FLAG. Parameters ulMicroseconds The number of microseconds to wait. This value cannot be larger than 60000000L (60 seconds). ulFlags Flags controlling the resumption of execution. This parameter can be one of the following: CM_YIELD_RESUME_EXEC Enable software simulation of interrupts. CM_YIELD_NO_RESUME_EXEC Ensures no other VxD gets control (other than hardware interrupts). Comments A device driver calls this function during any configuration-handler function in which the adapter needs a delay. For example, some PCMCIA IO cards require a delay of several seconds before being configured or reconfigured to a specified IO space. Callback Functions This section describes the Configuration Manager functions. ArbitrationHandler CONFIGRET ArbitrationHandler(ARBFUNC afcFunc, ULONG ulRefData, DEVNODE dnDevNode, NODELIST_HEADER pnlhNodeListHeader); An arbitrator-supplied function that processes arbitration messages for a device node. symbol 183 \f "Symbol" Returns CR_SUCCESS if successful, or one of the error values given in Constants later in this chapter. afcFunc Arbitration message. Can be one of these values: ARB_TEST_ALLOCCheck if requested allocation works.ARB_RETEST_ALLOCCheck if previous allocation works.ARB_SET_ALLOCSet the tested allocation.ARB_RELEASE_ALLOCRelease the tested allocation.ARB_QUERY_FREEReturn free resource.ARB_REMOVEDevice node is gone.ARB_FORCE_ALLOCForce previous TEST_ALLOC ulRefData 32-bit reference data value. This is the 32-bit value specified in the call to the CONFIGMG_Register_Arbitrator service when the handler was registered. dnDevNode Handle of the device node associated with this arbitrator. pnlhNodeListHeader Address of a NODELIST_HEADER structure that contains information about the logical configurations of all devices to be be configured. ConfigHandler CONFIGRET ConfigHandler(CONFIGFUNC cfFunc, SUBCONFIGFUNC scfSubFunc, DEVNODE dnDevNode, DWORD dwRefData, ULONG ulFlags); A driver-supplied function that processes configuration messages for a device node. symbol 183 \f "Symbol" Returns CR_SUCCESS if successful, or one of the error values given in Constants later in this chapter. cfFunc Function identifier. Can be one of these values: CONFIG_APMAPM functions.CONFIG_CALLBACKDevnode is being called back.CONFIG_ENUMERATEDevnode must enumerated.CONFIG_FILTERAncestors must filter requirements.CONFIG_PREREMOVEDevnode must stop using config.CONFIG_PREREMOVE2Devnode must stop using config.CONFIG_READYThe devnode has been setup.CONFIG_REMOVEDevnode must stop using config.CONFIG_SETUPDevnode should download driver.CONFIG_SHUTDOWNWe are shutting down.CONFIG_STARTDevnode dynamic initialization.CONFIG_STOPDevnode must stop using config.CONFIG_TESTCan devnode change state now.CONFIG_TEST_FAILEDContinue as before after a TEST.CONFIG_TEST_SUCCEEDEDPrepare for the STOP/REMOVE.CONFIG_VERIFY_DEVICEInsure the legacy card is there. scfSubFunc Subfunction identifier. dnDevNode Handle of the device node to process messages for. dwRefData 32-bit reference data value. This is the 32-bit value passed to the CONFIGMG_Register_Device_Driver service when the handler was registered. ulFlags Reserved; must be 0. EnumerationHandler CONFIGRET EnumerationHandler(CONFIGFUNC cfFunc, SUBCONFIGFUNC scfSubFunc, DEVNODE dnToDevNode, DEVNODE dnAboutDevNode, ULONG ulFlags); An enumerator-supplied function that processes enumeration messages for a device node. symbol 183 \f "Symbol" Returns CR_SUCCESS if successful, or one of the error values given in Constants later in this chapter. cfFunc Function identifier. Can be one of these values: CONFIG_APMAPM functions.CONFIG_CALLBACKDevnode is being called back.CONFIG_ENUMERATEDevnode must enumerated.CONFIG_FILTERAncestors must filter requirements.CONFIG_PREREMOVEDevnode must stop using config.CONFIG_PREREMOVE2Devnode must stop using config.CONFIG_READYThe devnode has been setup.CONFIG_REMOVEDevnode must stop using config.CONFIG_SETUPDevnode should download driver.CONFIG_SHUTDOWNWe are shutting down.CONFIG_STARTDevnode dynamic initialization.CONFIG_STOPDevnode must stop using config.CONFIG_TESTCan devnode change state now.CONFIG_TEST_FAILEDContinue as before after a TEST.CONFIG_TEST_SUCCEEDEDPrepare for the STOP/REMOVE.CONFIG_VERIFY_DEVICEInsure the legacy card is there. scfSubFunc Subfunction identifier. dnToDevNode Handle of the device node to process messages for. dnAboutDevNode Handle of the device node to which processing applies. This is typically a child of the device node specified by dnToDevNode. ulFlags Reserved; must be 0. Messages This section describes the Configuration Manager messages. ARB_TEST_ALLOC Sent to direct the arbitrator to test the given resource allocations. The arbitrator should attempt to satisfy all allocation requests contained in the node list for the resource. Depending on the result, the Configuration Manager subsequently sends either a ARB_SET_ALLOC or ARB_RELEASE_ALLOC message. SYMBOL 183 \f "Symbol" Returns CR_SUCCESS if allocation requests are satisfied, CR_FAILURE if not, or CR_OUT_OF_MEMORY if not enough memory to complete the test. Generally, the arbitrator sorts the list according to most likely successful allocation order, makes a copy of the current allocation structure(s), releases all resources currently allocated to device nodes on the list, then attempts to satisfy allocation requests by passing through the entire list. The arbitrator tries all possible combinations of allocations and saves the successful allocations in both the node list for the device and the copy of the allocation data structure. ARB_RETEST_ALLOC Sent to direct the arbitrator to retest the given resource allocations. The arbitrator attempts to satisfy all allocation requests contained in the node list for the resource. Depending on the result, the Configuration Manager subsequently sends either a ARB_SET_ALLOC or ARB_RELEASE_ALLOC message. SYMBOL 183 \f "Symbol" Returns CR_SUCCESS if successful allocation, CR_FAILURE if unsuccessful allocation, or CR_OUT_OF_MEMORY if not enough memory. The arbitrator starts with the result of a previous ARB_TEST_ALLOC message. Without sorting the node list, the arbitrator makes a copy of the current allocation structure(s), releases all resources currently allocated to device nodes on the list, then attempts to satisfy the allocations from the previous ARB_TEST_ALLOC message. The arbitrator saves the successful allocations in the allocation data structure. ARB_FORCE_ALLOC Sent to direct the arbitrator to retest, without failure, the given resource allocations. The arbitrator must satisfy all allocation requests contained in the node list for the resource. The Configuration Manager subsequently sends either a ARB_SET_ALLOC or ARB_RELEASE_ALLOC message. SYMBOL 183 \f "Symbol" Returns CR_SUCCESS or CR_OUT_OF_MEMORY if not enough memory to complete the test. The arbitrator starts with the result of a previous ARB_TEST_ALLOC message. Without sorting the node list, the arbitrator makes a copy of the current allocation structure(s), releases all resources currently allocated to device nodes on the list, then attempts to satisfy the allocations from the previous ARB_TEST_ALLOC message. The arbitrator saves the successful allocations in the allocation data structure. ARB_SET_ALLOC Sent to direct the arbitrator to make a test allocation the real allocation. The arbitrator makes the copy of the allocation data structure the current valid allocation. SYMBOL 183 \f "Symbol" Returns CR_SUCCESS. ARB_RELEASE_ALLOC Sent to direct the arbitrator to clean up after a failed test allocation. The arbitrator should free all allocations made during the previous ARB_TEST_ALLOC message. SYMBOL 183 \f "Symbol" Returns CR_SUCCESS. ARB_QUERY_FREE Sent to request information about free resources for a logical configuration. The arbitrator should return resource-specific data on the free element. SYMBOL 183 \f "Symbol" Returns CR_SUCCESS if successful, CR_FAILURE if the request makes no sense, or CR_OUT_OF_MEMORY if not enough memory. pnlhNodeListHeader Address of an arbitfree_s structure. ARB_REMOVE Sent when the device node associated with the arbitration handler is being removed. The arbitrator should carry out appropriate clean up. SYMBOL 183 \f "Symbol" Returns CR_SUCCESS. CONFIG_APM Sent to notify a driver of a power management event. The driver should determine the type of event and take appropriate action. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. On a request for permission, return CR_SUCCESS to grant permission, CR_FAILURE to deny it. scfSubFunc APM subfunction number. Can be one of these values: CONFIG_APM_TEST_STANDBYRequest for permission to change to standby operation. CONFIG_APM_TEST_SUSPENDRequest for permission to change to suspend operation. CONFIG_APM_TEST_STANDBY_FAILEDStandby request denied.CONFIG_APM_TEST_SUSPEND_FAILEDSuspend request denied.CONFIG_APM_TEST_STANDBY_SUCCEEDEDStandby request granted.CONFIG_APM_TEST_SUSPEND_SUCCEEDEDSuspend request granted.CONFIG_APM_RESUME_STANDBYStandby operation resuming.CONFIG_APM_RESUME_SUSPENDSuspend operation resuming.CONFIG_APM_RESUME_CRITICALCritical operation resuming. In standby operation, all devices remain generally responsive although in a lower power state. In suspend operation, you should assume that power and state of the device may be lost. CONFIG_CALLBACK Sent to a driver in a response to a request to be called back. The driver can carry out appropriate tasks. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. CONFIG_ENUMERATE Sent to direct a driver to enumerate its immediate children. This message is sent in response to the insertion or removal of a device. An enumerator should create a device node for each child by using the CONFIGMG_Create_DevNode service or remove children by using the CONFIGMG_Remove_SubTree service as appropriate. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. The enumerator should add logical configurations for each newly created device node. CONFIG_FILTER Sent to direct a driver to process a new device or changes to the configuration. Enumerators should retrieve the filtered logical configuration for the indicated device node and modify the requirements as needed. For example, the PCMCIA driver removes unsupported IRQs and pre-allocates IO port and memory ranges. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. Initially, the filtered requirements are identical to the basic requirements. An enumerator may alter the requirements of its own device node as well those of the indicated device node. When a device driver processes this message, it should look only at the filtered requirements list only. Use the CONFIGMG_Get_First_Log_Conf or CONFIGMG_Get_Alloc_Log_Conf to retrieve the filtered logical configuration (FILTERED_LOG_CONF) for this device node. CONFIG_PREREMOVE Sent to direct the driver to stop using its allocated configuration. This message is intended to give the driver the chance to prepare for the removal of its device. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. CONFIG_PREREMOVE2 Sent to direct the driver to stop using its allocated configuration. This message is intended to give the driver the chance to prepare for the removal of its device. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. CONFIG_READY Sent to notify the driver that the associated device node has been set up. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. CONFIG_REMOVE Sent to notify the driver that the associated device node is being removed from the hardware tree. The driver should deallocate any instance data for the device node and take whatever other measures are necessary to stop using the device node, the associated hardware, and the allocated configuration. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. scfSubFunc Subfunction number. Can be one of these values: CONFIG_REMOVE_DYNAMICRemoves a dynamically-loaded driver.CONFIG_REMOVE_SHUTDOWNRemoves a driver as part of system shutdown. This message is not always preceded by the CONFIG_TEST_CAN_REMOVE message. Use the CONFIGMG_Get_First_Log_Conf or CONFIGMG_Get_Alloc_Log_Conf to retrieve the allocated logical configuration (ALLOC_LOG_CONF) for this device node. CONFIG_SETUP Sent to notify the driver that the device node has been setup. The driver should load additional drivers if possible. For example, the driver could load appropriate drivers from device ROM, such as for ISA_RTR, PCI and PCMCIA device. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. CONFIG_SHUTDOWN Sent when the system is shutting down. The driver should free resources and shutdown its device. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. CONFIG_START Sent when a configuration has been allocated for the device node. The driver can retrieve the allocated configuration and begin to use it. CONFIG_START_DYNAMIC_STARTStarting dynamically-loaded driver.CONFIG_START_FIRST_STARTStarting system for the first time. Use the CONFIGMG_Get_First_Log_Conf or CONFIGMG_Get_Alloc_Log_Conf to retrieve the allocated logical configuration (ALLOC_LOG_CONF) for this device node. CONFIG_STOP Sent to direct the driver to stop using its current allocated configuration. The driver should stop using the resources in its allocated configuration until it receives a subsequent CONFIG_START message. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. scfSubFunc Subfunction number. Can be one of these values: CONFIG_STOP_DYNAMIC_STOPDirects the driver to stop using the allocated configuration.CONFIG_STOP_CHILD_FAILED_STARTDriver for child device node failed to start.CONFIG_STOP_HAS_PROBLEMDriver has a driver-specific problem. Use the CONFIGMG_Get_First_Log_Conf or CONFIGMG_Get_Alloc_Log_Conf to retrieve the allocated logical configuration (ALLOC_LOG_CONF) for this device node. CONFIG_TEST Sent to request permission to invalidate the assigned configuration or remove the given device node. The driver should not grant permission if it cannot stop using its current configuration or is not prepared for the device to be removed from the system. SYMBOL 183 \f "Symbol" Return CR_SUCCESS to grant permission, CR_FAILURE otherwise. scfSubFunc Subfunction number. Can be one of these values: CONFIG_TEST_CAN_STOPRequest for permission to invalidate the configuration currently assigned to the driver. CONFIG_TEST_CAN_REMOVERequest for permission to remove the given device node.  CONFIG_TEST_FAILED Sent to notify driver that the previous CONFIG_TEST message was canceled by a driver. The driver should continue operation as before receiving the CONFIG_TEST message. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. CONFIG_TEST_SUCCEEDED Sent to notify driver that the previous CONFIG_TEST message succeeded. This gives the driver an opportunity to prepare for the subsequent CONFIG_STOP or CONFIG_REMOVE message. SYMBOL 183 \f "Symbol" Return CR_SUCCESS. CONFIG_VERIFY_DEVICE Sent to verify that the given legacy card is present. SYMBOL 183 \f "Symbol" Return CR_SUCCESS if the card is present, CR_DEVICE_NOT_THERE otherwise. Structures This section describes the structures used with Configuration Manager services. arbitfree_s struct arbitfree_s { PVOID *af_PointerToInfo; // the arbitrator info ULONG af_SizeOfInfo; // size of the info }; Contains information about a free element. CMCONFIG struct Config_Buff_s { WORD wNumMemWindows; // Num memory windows DWORD dMemBase[MAX_MEM_REGISTERS]; // memory window base DWORD dMemLength[MAX_MEM_REGISTERS]; // memory window length WORD wMemAttrib[MAX_MEM_REGISTERS]; // memory window attrib WORD wNumIOPorts; // num IO ports WORD wIOPortBase[MAX_IO_PORTS]; // IO port base WORD wIOPortLength[MAX_IO_PORTS]; // IO port length WORD wNumIRQs; // num IRQ info BYTE bIRQRegisters[MAX_IRQS]; // IRQ list BYTE bIRQAttrib[MAX_IRQS]; // IRQ attrib list WORD wNumDMAs; // num DMA channels BYTE bDMALst[MAX_DMA_CHANNELS]; // DMA list WORD wDMAAttrib[MAX_DMA_CHANNELS]; // DMA Attrib list BYTE bReserved1[3]; // reserved }; typedef struct Config_Buff_s CMCONFIG; Contains information about an allocated configuration. CMPERFINFO struct cm_performance_info_s { CMTIME ctBoot; CMTIME ctAPI[NUM_CM_SERVICES]; CMTIME ctRing3; CMTIME ctProcessTree; CMTIME ctAssignResources; CMTIME ctSort; CMTIME ctRegistry; CMTIME ctVxDLdr; CMTIME ctNewDevNode; CMTIME ctSendMessage; CMTIME ctShell; CMTIME ctConfigMessage[NUM_CONFIG_COMMANDS]; CMTIME ctArbTime[ResType_Max+1][NUM_ARB_COMMANDS]; DWORD dwStackSize; DWORD dwMaxProcessTreePasses; }; typedef struct cm_performance_info_s CMPERFINFO; typedef CMPERFINFO CMFAR *PCMPERFINFO; Contains performance information that may be used for debugging. CMTIME struct cmtime_s { DWORD dwAPICount; VMMTIME vtAPITime; }; typedef struct cmtime_s CMTIME; typedef CMTIME *PCMTIME; Contains time information used for performance monitoring. DMA_DES struct DMA_Des_s { BYTE DD_Flags; // channel width; see below BYTE DD_Alloc_Chan; // allocated channel number BYTE DD_Req_Mask; // mask of requested channels; see below BYTE DD_Reserved; // reserved; do not use }; typedef struct DMA_Des_s DMA_DES; Contains information about DMA descriptors. DD_Flags Channel width flags. Can be one of these values: fDD_BYTE8-bit channelfDD_WORD16-bit channelfDD_DWORD32-bit channel DD_Req_Mask Mask of requested DMA channels. Bit 0 is set to request channel 0, bit 1 to request channel 1, and so on. More than one bit is set to indicate alternative channel allocations. DMA_RESOURCE struct DMA_Resource_s { DMA_DES DMA_Header; }; typedef struct DMA_Resource_s DMA_RESOURCE; Contains information about a DMA resource. IO_DES struct IO_Des_s { WORD IOD_Count; // count of IO_RANGE structures WORD IOD_Type; // size of IO_RANGE structures WORD IOD_Alloc_Base; // allocated base port address WORD IOD_Alloc_End; // allocated end port address WORD IOD_DesFlags; // descriptor flags BYTE IOD_Alloc_Alias; // allocated port aliases BYTE IOD_Alloc_Decode; // allocated alias decode key }; typedef struct IO_Des_s IO_DES; Contains information about the I/O descriptors. The full descriptor consists of this structure and an array of IO_RANGE structures. IOD_Count Number of IO_RANGE structures in this resource descriptor. IOD_Type Size, in bytes, of each IO_RANGE structure in this resource descriptor. IOD_Alloc_Base Allocated base port address. IOD_Alloc_End Allocated end port address. IO_RANGE struct IO_Range_s { WORD IOR_Align; // mask for base alignment WORD IOR_nPorts; // number of ports WORD IOR_Min; // min port address WORD IOR_Max; // max port address WORD IOR_RangeFlags; // flags BYTE IOR_Alias; // alias offset BYTE IOR_Decode; // alias decode key }; typedef struct IO_Range_s IO_RANGE; Contains information about a range of I/O port addresses. IO_RESOURCE struct IO_Resource_s { IO_DES IO_Header; IO_RANGE IO_Data[]; }; typedef struct IO_Resource_s IO_RESOURCE; Contains information about an IO resource. IRQ_DES struct IRQ_Des_s { WORD IRQD_Flags; // flags; see below WORD IRQD_Alloc_Num; // allocated IRQ number WORD IRQD_Req_Mask; // mask for requested IRQs WORD IRQD_Alloc_Mask; // allocated IRQ mask }; typedef struct IRQ_Des_s IRQ_DES; Contains information about the IRQ descriptors. IRQD_Flags Flags. Can be fIRQD_Share to indicate IRQ can be shared. IRQ_RESOURCE struct IRQ_Resource_s { IRQ_DES IRQ_Header; }; typedef struct IRQ_Resource_s IRQ_RESOURCE; Contains information about an IRQ resource. MEM_DES struct Mem_Des_s { WORD MD_Count; // count of MEM_RANGE structures WORD MD_Type; // size of MEM_RANGE structures ULONG MD_Alloc_Base; // allocated start address ULONG MD_Alloc_End; // allocated end address WORD MD_Flags; // descriptor flags WORD MD_Reserved; // reserved; do not use }; typedef struct Mem_Des_s MEM_DES; Contains information about a memory descriptor. The full descriptor consists of this structure and an array of MEM_RANGE structures. MD_Count Number of MEM_RANGE structures in this resource descriptor. MD_Type Size, in bytes, of each MEM_RANGE structure in this resource descriptor. MEM_RANGE struct Mem_Range_s { ULONG MR_Align; // mask for base alignment ULONG MR_nBytes; // count of bytes ULONG MR_Min; // min Address ULONG MR_Max; // max Address WORD MR_Flags; // flags WORD MR_Reserved; // reserved; do not use }; typedef struct Mem_Range_s MEM_RANGE; Contains information about a range of memory addresses. MEM_RESOURCE struct MEM_Resource_s { MEM_DES MEM_Header; MEM_RANGE MEM_Data[]; }; typedef struct MEM_Resource_s MEM_RESOURCE; Contains information about a memory resource. NODELIST struct nodelist_s { struct nodelist_s *nl_Next; // next node element struct nodelist_s *nl_Previous; // previous node element struct devnode_s *nl_ItsDevNode; // device node represented struct Log_Conf *nl_Test_Req; // test resource alloc request ULONG nl_ulSortDWord; // sort order }; Contains information about an element in a node list. Although additional members can be appended to this structure, the first three members must not be changed. NODELIST_HEADER struct nodelistheader_s { struct nodelist_s *nlh_Head; // First node element struct nodelist_s *nlh_Tail; // Last node element }; Contains information about the elements in a node list. VMMTIME struct vmmtime_s { DWORD vmmtime_lo; DWORD vmmtime_hi; }; typedef struct vmmtime_s VMMTIME; typedef VMMTIME *PVMMTIME; Contains time information used for performance montoring. Constants This section describes constants used with Configuration Manager services. Configuration Manager Return Values Configuration Manager functions return a CONFIGRET value. CONFIGRET is defined as either 16- or 32-bit, depending on the compiler option; 16-bit code returns a 16-bit value and 32-bit code returns a 32-bit value. Configuration Manager functions return CR_SUCCESS when they are successful. Otherwise, they return one of the following values: ValueMeaningCR_ALREADY_SUCH_DEVNODESpecified device node already existsCR_BUFFER_SMALLThe operation succeeded, but the specified buffer was too smallCR_CREATE_BLOCKEDFlags specifies that the devnode should not be createdCR_DEFAULTReturn the default resultCR_DEVICE_NOT_THEREDriver could not find deviceCR_DEVLOADER_NOT_READYDevice loader was not readyCR_DEVNODE_HAS_REQSDevice node already has requirementsCR_DLVXD_NOT_FOUNDDynamically loadable VxD was not foundCR_FAILUREFailure (Arbitrator/Enumerator)CR_INTERRUPTS_DISABLEDInterrupts were disabledCR_INVALID_APIThe function cannot be called from ring 3CR_INVALID_ARBITRATORArbitrator's registration identifier is invalid or there is already such a global arbitratorCR_INVALID_DATAISA data is invalidCR_INVALID_DEVICE_IDLength of device identifier is greater than MAX_DEVICE_ID_LENCR_INVALID_DEVNODEDevice node is invalidCR_INVALID_FLAGFlags parameter is invalidCR_INVALID_LOAD_TYPELoad type is greater than MAX_DLVXD_LOAD_TYPECR_INVALID_LOG_CONFLogical configuration is invalidCR_INVALID_NODELISTNodelist header is invalidCR_INVALID_POINTERSpecified pointer is invalidCR_INVALID_PRIORITYPriority number>MAX_LCPRICR_INVALID_RANGEEnd range less than start rangeCR_INVALID_RANGE_LISTRange list not validCR_INVALID_RES_DESResource descriptor is invalidCR_INVALID_RESOURCEIDThe resource identifier is ResType_AllCR_NEED_RESTARTThe config handler could not dynamically start the device, but will be able too the next bootCR_NO_ARBITRATORResource has no arbitratorCR_NO_MORE_HW_PROFILESNo more hardware profilesCR_NO_MORE_LOG_CONFNo more logical configurationsCR_NO_MORE_RES_DESNo more resource descriptorsCR_NO_REGISTRY_HANDLEOperation will not produce registry entryCR_NO_SUCH_DEVNODEDevice node could not be locatedCR_NO_SUCH_LOGICAL_DEVLogical device not found in ISAPNP conversionCR_NO_SUCH_VALUERegistry value does not existCR_NOT_DISABLEABLEThat devnode cannot be disable right nowCR_NOT_SYSTEM_VMThe service must be coming from the system VMCR_OUT_OF_MEMORYOut of memoryCR_REGISTRY_ERRORRegistry failedCR_REMOVE_VETOEDThe hardware tree should not be removedCR_WRONG_TYPERegistry value is of other type Chapter SEQ CHAPTER \R 44 Plug and Play and PCMCIA About Plug and Play PCMCIA This document describes the architecture of PCMCIA in Windows 95 and its interaction with the Plug and Play environment. It addresses the three major aspects of PCMCIA: PC cards, device drivers for those cards, and PCMCIA system software. The Plug and Play framework enables tighter integration and better support of the dynamic nature of the PCMCIA interface. In this framework, a PCMCIA adapter will be controlled by the PCMCIA bus enumerator (PCCARD.386). PCCARD incorporates the Card Services functions as well as the PCMCIA bus enumeration and configuration functions. The primary goal of PCMCIA in Windows 95 is to configure PC cards so that any Plug and Play device driver can be used to control the device, without any special provisions for PCMCIA. Another goal of the system is to support PCMCIA 2.x Card Services Clients and Drivers and to provide an environment for 32-bit protected mode Card Services clients, which may be required to support PC cards and their drivers. The tighter integration of PCMCIA with the operating system eliminates the need for the guesswork which Card Services otherwise uses to find which resources are available in a given system. The PCMCIA enumerator also enables automatic device installation via the Windows Device Installer. Since configuration management is actually done by Configuration Manager, resources are allocated and reclaimed dynamically. This enables the easy addition of static devices and support for new scenarios such as hot or warm docking. The PCMCIA bus enumerator uses the information tuples described in this document to identify the card, load the correct device driver, and indicate all the possible configurations to Configuration Manager. Configuration Manager dynamically assigns a valid configuration based on this information. To support true Plug and Play functionality, PC cards must fully support the identification and configuration tuples described in this document. Device drivers must be modified to support the Windows 95 dynamic loading mechanism and the Plug and Play configuration functions. Since Windows 95 Plug and Play seamlessly configures devices in the system, it enables card vendors to write a single driver for the ISA, EISA, PCI and PCMCIA implementations of a given I/O card. Protected mode Card Services clients will be supported in Windows 95 as well, but will not have the same level of flexibility as Windows 95 Plug and Play drivers. This document describes three different types of PC card drivers which will be supported in Windows 95. The following diagram illustrates how Card Services is integrated into the Windows 95 Plug and Play framework. Card Services is incorporated with the PCMCIA bus enumerator in the PCCARD module. This module interacts with Configuration Manager and the registry when a card is inserted or removed.  PC Card Tuples To support a PC card as a typical Plug and Play device, the card must contain tuples that identify the card and define how it should be configured. Preferred Tuples A device in the Windows 95 Plug and Play system can be configured only when the system can create a unique identifier for the device. This identifier is used to locate device-specific information in an INF file for installation purposes and in the registry for initialization and configuration purposes. The registry and the INF files contain information about the drivers that are needed for the device and may also contain configuration information or even previous settings for the device. Each PC card must contain the information required to create this unique device ID. This is done through the use of tuples on the card. The following table lists the preferred tuples used by PCCARD to create a device ID for a PC card. TupleCommentsLevel 1 Version/ Product Information Product Information String Product Name Product Number Other Manufacturer InformationManufacturer IDCard manufacturer ID code - Defines manufacturer for this card.DeviceDevice size and type are used by Card Services to configure the socket interface.ConfigurationIndicates last configuration entry in the configuration entry table for configurable cards. Indicates location of configuration registers.Configuration EntryConfiguration requirements should be specified for I/O space, interrupts, memory, and so on. These tuples have the following codes and ID values: TupleTuple CodeTuple IDLevel 1 Version/ Product Information CISTPL_VERS_115HManufacturer IDCISTPL_MANFID20HDeviceCISTPL_DEVICE01HConfigurationCISTPL_CONFIG1AHConfiguration EntryCISTPL_CFTABLE_ENTRY1BH The device ID string is of the form: PCMCIA\Manufacturer-Product-CRC16. The Manufacturer and Product portions are derived from from the Level 1 Version tuple with non-printable characters removed and spaces converted to underscores. The 16-bit CRC is created from the DEVICE, VERS_1, CONFIG, CFTABLE_ENTRY, and MANFID tuples. The PCMCIA device ID string is one of the outputs from the included utility DTPL.EXE. Refer to the DTPL section for more information about this utility. Device Configuration Tuples Each device is configured based on a set of logical configurations. These are the possible configurations that can be used by the device. A logical configuration must be determined for a PC card that a device ID has been created for and this configuration must be passed to Configuration Manager. The configuration information for a PC card is derived from the Configuration and Configuration Table Entry tuples. The order of the Configuration Table Entry tuples specifies the preference for each configuration. To support devices that do not have valid (or correct) configuration tuples, the registry may contain overriding logical configurations for the device. This overriding configuration is located using the device ID and may be set up based on information in the INF file when the device is first installed. PCMCIA Device Drivers Device driver writers have three possible implementation schemes for device drivers supporting PCMCIA cards. They can write a standard protected mode Plug and Play driver, they can rely on standard Windows 95 drivers for certain devices, or they can write a 32-bit protected mode Card Services client. Device driver writers can still add Card Services calls to their Plug and Play drivers, but these drivers will not be bus-independent. The choice depends on several factors, including the completeness of the Card Information Structure (CIS) on the PC card, whether the driver needs memory services, and whether the driver is expected to support the same type of hardware on another bus (that is, whether it is a bus-insensitive driver). Generally, you should write standard Plug and Play device drivers for your PC Card. For LAN cards, write NDIS 3.x-compliant drivers. For SCSI cards, write miniport drivers. For modems, use the VCOMM driver and include the appropriate AT command strings in the INF file for the Windows 95 Remote Network Access (RNA) software. Standard Plug and Play Device Driver A Plug and Play device driver may be any driver that follows the Plug and Play architecture. These drivers handle dynamic configuration and removal. They receive their configuration from Configuration Manager and have no direct interaction with the PCMCIA components. Therefore, they may be run as the device drivers for a PC card without any knowledge of the card existing in a PCMCIA bus. These are the preferred drivers for PCMCIA devices. Once Plug and Play assigns IRQ, memory and I/O, access and operation of the card will be done using the assigned resources. This approach is recommended if the device driver does not require the Card Services functions. All resource allocation for the driver will be done by Configuration Manager, based on the table of required resources supplied by the device. The actual configuration of the card will be done by Config Manager through the PCMCIA bus enumerator after the resources have been allocated. This will allow the same device driver to support ISA/EISA/PCI and PCMCIA implementations of the same device. Note that this approach cannot be used for PC cards which do not contain the tuples required to identify the PC card and allow a device ID to be created. Cards with invalid or missing configuration tuples can still benefit through the CIS override mechanism, whereby the INF file lists the correct logical configuration possibilities for the device. See the section on Windows INF files for further information on the override mechanism. A device driver that supports a card that uses the correct tuples (as defined in PC Card Tuples earlier in this chapter) but needs to access the Card Services memory functions should choose a mixed approach: it can be both a Plug and Play and a Card Services device driver. The structure of the driver is the same, except that it calls Card Services functions when necessary. If the driver needs a client handle, it may register with Card Services as a Card Services client.The card would still be automatically configured at insertion time by the PCMCIA bus enumerator, but any access to the PC cards tuples or memory window manipulation would be performed by the driver calling Card Services functions. Details on writing a standard Plug and Play device driver are found in other sections of the Device Driver Kit (DDK). Note that existing driver architectures such as NDIS3 for network adapters, and NT miniports for SCSI devices are already Plug & Play, as the underlying subsystems handle the PnP requirements for their client drivers. Generic Windows 95 Device Driver Certain devices, such as modems and disk drives, are automatically supported by Windows 95. Note that in the case of modems, Windows provides generic drivers but it is recommended that manufacturers provide specific INFs for their modems with the appropriate AT commands. If the configuration information on the PC card is complete, the PCMCIA bus enumerator will initialize the device and Configuration Manager will pass the configuration information to one of these drivers. For example, if the PC card is an IDE drive, Configuration Manager may assign I/O port 1F0h and IRQ 14 (representing the primary IDE controller) and will pass this information to the Windows 95 I/O sub-system (IOS). Specialized functions on the cards may be implemented using mini drivers (refer to other sections in the Windows 95 DDK for more information). Device classes that do not have standard configurations (for example, network or SCSI adapters) are not automatically supported by Windows 95 the drivers must be supplied by the hardware manufacturer. Card Services Client Device Driver Several different types of device drivers are Card Services clients. Any 32-bit protect mode device driver that uses Card Services 2.x will work under Windows 95. However, without some changes, resource allocation may not be optimized, and the device driver does not participate in any resource balancing. Because the device driver makes the requests for resources and configuring the card, this may be the only option to support cards with an incomplete card information structure (CIS). For cards with complete CIS information, these drivers can still benefit from an optimized initial resource allocation. Upon card insertion, the PCMCIA bus enumerator reads the card's CIS to determine the card's resource requirements. If the PCMCIA bus enumerator is successful (that is, if the CIS is complete), it builds the resource request list on behalf of the client driver. This enables the Configuration Manager to find a working resource allocation. Once the Card Services portion of the PCCARD module is told what resources were allocated, it simply filters the client drivers resource requests until it requests the correct preallocated resources. Memory Technology Driver Memory technology drivers enable memory card vendors to support cards featuring new memory technologies. These drivers use the Card Services 2.x MTD functions. PCMCIA System Software The Windows 95 support of PCMCIA provides the Card Services 2.x level of functionality. This is integrated with the Windows 95 Plug and Play architecture so that Configuration Manager provides the resource allocation instead of the Card Services module. This is done by adding a PCMCIA bus enumerator to Card Services and changing Card Services to accept configurations from Configuration Manager instead of tracking the resources itself. This implementation provides support for existing PCMCIA Card Services clients as well as new Plug and Play drivers on Windows 95. The following diagram is an expanded illustration of the architecture of PCMCIA in Windows 95.  Card Services The Card Services component is a protected mode VxD module that is linked with the PCMCIA bus enumerator. It provides a protected mode PCMCIA Card Services 2.x interface for protected mode Card Services clients. Card Services passes the event notification from Socket Services to the PCMCIA bus enumerator, provides information from the PC cards to the PCMCIA bus enumerator, and sets up the configuration for PC cards in the adapter sockets. Interface for VxDs This section describes the Card Services binding for VxD clients. The calling mechanism is the VxD service interface any VxDs requiring access to Card Services must include PCCARD.INC. This include file contains the PCCARD service-access table that allows the client VxD to use the VxDCall macro to call Card Services. The VxD Card Services interface is not available during system initialization. Clients should register with Card Services while processing the Init_Complete message. Clients registering at this point still have the opportunity to abort loading if Card Services is not present. MASM version 6.x is required for the structure definitions in the Card Services interface. Card Services API Elements PCCARD.386 offers two services: PCCARD_Get_Version and PCCARD_Card_Services. Access to all Card Services is through the PCCARD_Card_Services service. As with all VxD services, clients should call PCCARD_Get_Version to ensure that PCCARD is loaded before attempting to call PCCARD_Card_Services. Card Services Argument Binding Parameters are passed in registers following the recommended binding in the PCMCIA Standards manual for 0:32 protected mode clients: RegisterDescription[AL]Function[DX]Handle[ESI]Pointer (32 bit offset)[CX]ArgLength[EBX]ArgPointer (32 bit offset)[AX]Status[CF]Reset to zero when request was successful, set to one when request has failed. All calls and returns are near. All entry registers are preserved unless the same register is used for a return value. The following table gives the arguments for callback handlers: RegisterDescription[AL]Function[CX]Socket[DX]Info[DI]First word of RegisterClient argument packet ClientData field[ESI]Third and fourth word of RegisterClient argument packet ClientData field[EBP]MTD request[EBX]Buffer[BX]Misc. (when no buffer is specified)[AX]Status on return to Card Services[CF]Returned reset to zero when the callback completed successfully, set to one if Status is not SUCCESS. Card Services RegisterClient Function The following table gives the register_client argument packet ClientData field: OffsetDescription016 bit data determined by client216 bit reserved (reset to zero)432 bit offset determined by client For detailed information on the other functions, see the PCMCIA Standards manual. Socket Services The Socket Services component is a protected mode VxD module that manages the PCMCIA adapter hardware. It is the driver that controls the specific PCMCIA hardware components. It provides a protected mode PCMCIA Socket Services 2.x interface for use by Card Services. A Socket Services driver must be implemented for each separate PCMCIA controller that could be used. The Socket Services driver registers with Card Services using the add_socket_services function. The PCCARD module contains the device loader for the Socket Services driver. Windows 95 will provide Socket Services drivers for the Intel 82365 controller and the DataBook controller. Contact Microsoft Hardware Vendor Support for information on writing Windows 95 compatible Socket Services drivers for other controllers. PCMCIA Hardware-Tree When the PCMCIA bus enumerator is called at its enumeration entry point, it will create a subtree that represents everything subordinate to the PCMCIA adapter. The following diagram shows the location and possible representation of a PCMCIA hardware tree:  The PCMCIA bus enumerator handles two levels of device nodes: the adapter device node and the card device node. The adapter device node contains the configuration information for the PCMCIA adapter. The card device node contains the configuration information for the PC card in the adapter's socket. These device nodes are created through the sequence of operations discussed in the following sections. The Enumeration Process When the system starts, a bus enumerator for a bus device node (such as the system board BIOS) will enumerate its bus and detect the PCMCIA adapter. The bus enumerator will create an adapter device node for the adapter and add a logical configuration for the adapter at its current configured I/O address. Configuration Manager will load the device loader, based on information in the registry. The device loader for the adapter is contained in the PCMCIA bus enumerator - along with the Card Services component. The device loader is called at its PNP_NEW_DEVNODE control entry point. The device loader loads the Socket Services driver for the adapter device node, based on the Driver= entry in the registry for the adapter device node. The device loader registers an enumerator for the adapter device node. Configuration Manager calls the Socket Services driver to filter the logical configuration for the adapter. The Socket Services driver will then be called by Configuration Manager to configure the adapters IRQ, I/O, and a memory window. Configuration Manager then calls the bus enumerator for the adapter device node to enumerate the devices on the PCMCIA bus. The bus enumerator enumerates each PC card in the sockets on the adapter. A device ID for each PC card is generated from the tuples on the card. The bus enumerator creates the device nodes for the cards in the sockets. Logical configurations will be created based on the configuration tuples on the PC card. If a card does not have configuration tuples, an empty logical configuration is added for the card. Overriding configurations may be defined in the registry to handle this case, or the driver for the card may define the logical configuration during the call to the CONFIG_FILTER configuration handler function. For this to happen, a valid Manufacturer ID tuple must exist on the card. Setup on First Insertion The registry is set up when the device is first installed and recognized by the bus enumerator. This is initiated by Configuration Manager when a device node is created for which a device ID is not contained in the registry. If the device has not been previously configured, Configuration Manager calls the Device Manager to set up the registry for the device. The Device Manager will look up the Device ID entry in the appropriate device information (.INF) file and the resource information in the drivers which already exist in the default driver directory. If a default driver is found, its configuration information is copied to the registry and the driver is loaded. If no driver is found the user will be prompted to initiate an installation process. When the Device Manager has completed the setup of the registry, the Configuration Manager will complete the setup of the device node for the device. If an overriding logical configuration exists in the registry it will be used for the device, and the logical configuration that was defined by the PCMCIA bus enumerator will be discarded. Configuration Process Configuration Manager will load the device loader for the card based on information in the registry. The device loader may be a Plug and Play device loader, or, to support Card Services clients, the PCMCIA bus enumerator may be the device loader. If the PCMCIA bus enumerator is the device loader, the driver will be a Card Services client, the device node will be handled specially, and a default device driver will be registered for the card by the device loader. Configuration Manager calls the CONFIG_FILTER function in the adapter driver where it filters the PC card configurations so that they can be mapped by the adapter for the socket. Any logical configurations that cannot be supported by the adapter will be removed from the filtered logical configuration list. Finally, when the configuration has been determined by Configuration Manager, the CONFIG_START function will be called and the PCMCIA bus enumerator will map the IRQ, I/O, and memory windows for the PC card by calling the Card Services module. Card Services configures the adapter to support the defined configuration and sets the configuration index in the cards registers. Overriding Logical Configurations To allow support for PnP cards that have invalid logical configs defined on the card, overriding logical configs are supported. These overriding logical configs are defined in the INF file for the device and transfered to the registry when the device is installed. When an overriding logical config is defined for a device, the config manager will replace the logical configs created by the enumerator with the overriding config defined in the registry. Refer to the Device Installation section for detailed information about the general case of overriding configurations. The logical config created by the PCMCIA Bus Enumerator is an extended version of the normal logical config defined by the configuration manager. This logical config contains an additional DWORD flags value on the end of the I/O and IRQ resource descriptor, an additional DWORD flags value and DWORD card address value on the end of the memory resource desciptor, and an ignored resource descriptor which contains the REQUEST_CONFIG_PKT structure. The extension to the I/O Range is a dword flags value. A single flag bit is defined (0x40), when set indicates the I/O ports are 16-bit I/O ports, otherwise they are 8-bit ports. The extension to the IRQ List is a dword flags value. A single flag bit is defined IRQI_LEVEL (0x20), when set indicates the IRQ is level triggered. Currently, this bit must be set for the card to be configured. The extension to the Memory Range is a dword flags value followed by a dword card offset. The flags value must be set to either WDWA_ATTRIB_MEM (0x02), or WDWA_16BIT (0x08). When it is set to WDWA_ATTRIB_MEM it indicates the memory window is in attribute memory. When it is set to WDWA_16BIT it indicates the memory window is in common memory. The card offset is the offset on the PC card for the memory window to be mapped. PCMCIA PC Cards require an additional resource type. This resource is defined as type 0x897C. The data in the resource is the same as the PCMCIA Card Services RequestConfiguration argument structure (REQUEST_CONFIG_PKT). The Socket field in this structure does not need to be filled in. The following is an example of the overriding logical config that may be defined for PCMCIA Cards in the INF file. [SAMPLEOVERRIDE] HKR,Override,0000,HEX, \ ; 00,04,00,00, \ ; CONFIGMG_VERSION 00,00,00,00, \ ; PRIORITY ; ; I/O Resource Descriptor ; 24,00,00,00, \ ; Total length of I/O Resource Descriptor 02,00,00,00, \ ; ResType_IO = 0x00000002 01,00, \ ; IOD_Count; 0C,00, \ ; IOD_Type; // IOType_Range = 0x000C 00,00, \ ; IOD_Alloc_Base; 00,00, \ ; IOD_Alloc_End; 00,00, \ ; IOD_DesFlags; 00, \ ; IOD_Alloc_Alias; 00, \ ; IOD_Alloc_Decode; F0,FF, \ ; IOR_Align; // Mask for base alignment 10,00, \ ; IOR_nPorts; // Number of ports 00,00, \ ; IOR_Min; // Min port address FF,FF, \ ; IOR_Max; // Max port address 00,00, \ ; IOR_RangeFlags; // Flags 00, \ ; IOR_Alias; // Alias offset 00, \ ; IOR_Decode; // Address specified 40,00,00,00, \ ; PCCARD flags, 0x40 = 16-bit port ; ; Memory Resource Descriptor ; 34,00,00,00, \ ; Total length of Memory Descriptor 01,00,00,00, \ ; ResType_Mem = 0x00000001 01,00, \ ; MD_Count; 14,00, \ ; MD_Type; // MType_Range = 0x0014 00,00,00,00, \ ; MD_Alloc_Base; 00,00,00,00, \ ; MD_Alloc_End; 00,00, \ ; MD_Flags; 00,00, \ ; MD_Reserved; 00,F0,FF,FF, \ ; MR_Align; // Mask for base alignment 00,10,00,00, \ ; MR_nBytes; // Count of bytes 00,00,00,00, \ ; MR_Min; // Min Address FF,FF,FF,FF, \ ; MR_Max; // Max Address 00,00, \ ; MR_Flags; // Flags 00,00, \ ; MR_Reserved; 02,00,00,00, \ ; PCCARD flags, 0x02 = attribute mem, or ; 0x08 = 16-bit common mem 00,10,00,00, \ ; Memory card address ; ; IRQ Resource Descriptor ; 14,00,00,00, \ ; Total length of IRQ Resource Descriptor 04,00,00,00, \ ; ResType_IRQ = 0x00000004 00,00, \ ; IRQD_Flags; 00,00, \ ; IRQD_Alloc_Num; // Allocated IRQ number FF,FF, \ ; IRQD_Req_Mask; // Mask of possible IRQs 00,00, \ ; IRQD_Reserved; 20,00,00,00, \ ; PCCARD flags, 0x20 = Level mode ints ; ; REQUEST_CONFIG_PKT Descriptor ; 19,00,00,00, \ ; Length of REQUEST_CONFIG_PKT Descriptor 7C,89,00,00, \ ; ResType_Ignored_Bit+PCCARD_DEVICE_ID= 0x897C 00,00, \ ; Socket; 02,00, \ ; Attributes; 32, \ ; Vcc; 00, \ ; Vpp1; 00, \ ; Vpp2; 02, \ ; IntType; 00,02,00,00, \ ; ConfigBase; 00, \ ; Status; 00, \ ; Pin; 00, \ ; Copy; 01, \ ; ConfigIndex; 0F, \ ; Present; ; 00,00,00,00 ; TERMINATOR Display Tuple Utility (DTPL.EXE) DTPL.EXE is a tool designed for interpreting the tuples on a PC Card. This tool is intended to help you design or verify CIS for use with Microsoft's PCMCIA support in Windows. DTPL runs in realmode on MS-DOS using realmode Card Services and Socket Services implementations. It is intended to be run on PC Cards that have not been configured by a card services client, or enabler. Therefore card services clients and PC Card enablers should not be loaded or active when using this tool. This tool displays information derived from the tuples on the PC Card. This includes the PnP Device ID, the PnP Logical Configurations, and a display of each tuple on the card. The tool has the following syntax: DTPL [-f filename] [-i] [-l] [-r] [-t] [socket#] -f filename Defines a filename to take the tuple input from instead of calling CS. -i Displays the PNP Device ID for the PC Card. -l Displays the PNP logical configurations for the PC Card. -r Displays raw tuple data bytes, formatted for input file. -t Displays all of the tuples on the PC Card. socket# An optional socket to display, otherwise all sockets will be displayed. The -f option allows the tuple input to be taken from a file. This allows tuples to be interpreted with out the need for a realmode Card Services driver and also allows tuples to be tested before they are placed on a PC Card. The tuples in this file must be defined in an ASCII HEX format. Each hex value must have two digits, the parser for this is very simple. Comments may be placed in the tuple file using a semicolon (;). For example the following tuple is a config entry tuple for a comm port. ; This is a COM1 port 1B 11 ; Config entry and link values. E0 01 1D 48 D5 02 1D FC 14 A0 60 F8 03 07 30 3C 00 The optional socket# is ignored when the -f option is used and the socket for the tuples will be set to 0xFF. The -i option displays the PnP Device ID for the PC Card.The PnP Device ID is the ID that will be generated by the PCMCIA Bus Enumerator for the device and used by the Plug and Play system. This ID should be used when generating the .INF file for a device. The device ID is created from the manufacturer name string, the product name string, and a 16-bit CRC of a set of tuples. The ID is created by concatinating the PCMCIA prefix, the manufacturer name string, the product name string, and a 16-bit CRC. The Device ID has the following format: PCMCIA\manuf_name-prod_name-crc The manuf_name and prod_name are obtained from the CISTPL_VERS_1 tuple. If the CISTPL_VERS_1 tuple is not available or the manufacturer name is NULL, the string "UNKNOWN_MANUFACTURER" will be included in its place. The CRC will be created from the following tuple data: CISTPL_DEVICE, CISTPL_VERS_1, CISTPL_CONFIG, CISTPL_CFTABLE_ENTRY, CISTPL_MANFID. Only the first two strings in the CISTPL_VERS_1 tuple, the manufacturer and product name strings, are included in the CRC. This is because serial numbers are occasionally placed in the additional strings of this tuple. These serial numbers would cause the CRC to be different for each card even though they are the same. The total length of the device ID string is limited to 128 characters, including the null terminator. The manufacturer and product name will be truncated to maintain this length restriction in the ID string. The characters in the manufacturer and product name strings that are greater than or equal to a space (0x20) or less than (0x7F) will be copied into the name string. Any other characters outside this range will be skipped. This makes it easier to include these characters in the .INF files for the device. Spaces and commas in the device ID will be converted to underscores (_). The -l option displays the PnP Logical Configurations for the PC Card. The PnP Logical Configurations are generated by the PCMCIA Bus Enumerator from the Config and Config Entry tuples. The display of these configurations is intended to provide some feedback on the interpretation of the configuration tuples on the PC Card. The logical configuration will be used by the Plug and Play Configuration Manager to determine the configuration for the PC Card. The information displayed includes I/O, IRQ, and Memory resource data, along with the contents of a Card Services RequestConfiguration argument structure. The -r option displays each tuple as its raw data bytes. This is in a format that can be easily edited and feed back to the DTPL tool as an input file using the -f option. Note that any strings that are not data bytes must be commented out with a semicolon (;) or removed from the input file. The -t option displays each tuple in a more readable format. Many of the tuples are interpreted and displayed in an expanded form. For example this is done for the configuration entry tuples which are difficult to understand without such expansion. Following the expanded information for each tuple is a dump of the tuple data bytes in an ASCII HEX format followed by an ASCII dump of each byte in the tuple. Non-printable bytes are diplayed as a period (.) in the ASCII dump. Tuples that are not expanded are displayed in an ASCII HEX format only. Chapter SEQ CHAPTER \R 55 Plug and Play Installation About Class and Device Installers Class and device installers are dynamic-link libraries that work in conjunction with the Device Manager to install, configure, and remove devices or classes of devices in the system. Windows 95 provides a set of default installers that the Device Manager can use to install devices belonging to the default classes. Additionally the Device Manager supports a set of default device installation functions that can be used on a device of any class. If your device or class of device has features that are not supported by the default installers, you can create a new installer for your device or class and direct Device Manager to use the installer whenever the user installs your device or class. This chapter describes class and device installers and explains how create and register new installers for use by the Device Manager. Classes and Installers Windows 95 has a large number of subsystems to control various classes of devices. Classes identify logical device types such as display, keyboard, and network. Because each subsystem has a different driver architecture, different user options, and different compatibility constraints, it is impossible to have a single utility support installation of all possible devices. Instead, each class is responsible for providing its own installer. A single installer can support installation of both the class and individual devices. However, this depends on the class and in some cases separate device installers are used. Typically, the installer is combined with the control panel applet (.CPL) for the given class, although this is not a requirement. Whether the installer is combined with the applet or is a separate dynamic-link library, the Device Manager controls and directs the action of the installer. The Device Manager, itself a control panel applet, is responsible for displaying dialog boxes to the user to prompt for information about adding and modifying device drivers. It is also responsible for installing any drivers for any devices enumerated by the configuration manager. The Device Manager relies on the class and device installers to display the appropriate dialog boxes or carry out appropriate installation tasks. Although the Device Manager gives the installer full control of the installation process, in most cases, the installer simply directs the Device Manager to complete the task for it. The installer can insert additional configuration dialogs, hardware detection, and other features into the process as is appropriate for the class. Default Classes and Class Installers Windows 95 defines a set of default device classes and provides corresponding class installers for these classes. The Device Manager uses the default installers to install devices belonging to the default classes. There are these default classes: AdapterDefault device installPrinterMSPRINT.DLLCDROM Default device installDisk DrivesDefault device installSound video and game controllers mmci.cplDefault device installKeyboardDefault device installSystem Devicessysclass.dllMulti Functions CardsDefault device installModemModem.CplMonitorDefault device installDisplay adaptersSetupX.DllFloppy disk controllersDefault device installHard disk controllersDefault device installMouseSetupX.DllPorts (COM & LPT)Default device installNetwork adaptersnetdi.dllPCMCIA SocketPCCard.dllSCSI controllersDefault device installUnknown Hardwaresysdm.cpl If your device belongs to a default class but the default installer does not provide the installation support you need for your device, you can create your own installer and direct the Device Manager to use that installer whenever the user installs a device of that class. By default, the Device Manager adds any new classes to the system if the given INF specifies a [ClassInstall] section, and the class has not been previoulsy installed. You can specify the Class installer for this new class in this section of the INF file, and the Device Manager will load and call this installer when appropriate. Installer Function Every installer exports an installer function named ClassInstall. The Device Manager dynamically links to and calls this function whenever it needs the installer to carry out a specific installation task. ClassInstall receives two arguments: an integer that identifies the installation task to carry out, and the address of a DEVICE_INFO structure that contains information about the device to install. The function either carries out the requested task, using the information in the structure, or directs the Device Manager to carry out the task for it. To direct the Device Manager to carry out the task, the function must return the ERR_DI_DO_DEFAULT value. The Device Manager has default actions for each request. If the function carries out its own tasks, it must return the value OK to notify the Device Manager that the task completed successfully. If an error occurs while carrying out a task, the function must return one of the RETERR values given in Constants later in this chapter. Installation Requests The Device Manager sends requests to the installer whenever it needs the installer to carry out installation tasks, such as determining whether to install a detected device, selecting a device to install, and installing a selected device. A DIF_SELECTDEVICE request directs the installer to choose a driver for a new device or a new driver for an existing device. The installer either makes the selection, prompts the user to make the selection, or directs the Device Manager to prompt the user (the default action). A DIF_INSTALLDEVICE request directs the installer to install the given driver. The installer either installs the driver or directs the Device Manager to do it (the default action). In some cases, an installer may carry out pre-processing, such as copying support drivers and prompting for user input, before requesting the default action. A DIF_PROPERTIES request directs the installer to display the properties sheet for the selected device. The Device Manager send this request when the user presses the Properties... button. The installer can display the property sheet or direct the Device Manager to display the default property sheet (the default action). The Device Manager sends a DIF_REMOVE request to direct the installer to remove the given device. The installer typically removes the corresponding registry entries for the device. A DIF_FIRSTTIMESETUP request directs the installer to carry out any class-specific installation tasks that need to be complete during initial installation of the operating system. The Device Manager sends this request only when the user installs Windows 95 for the first time. A DIF_CALCDISKSPACE request directs the installer to calculate the disk space requirements for installing a driver for the given device. By default action, the Device Manager calculates the disk requirements based on the contents of the INF file. A DIF_DESTROYPRIVATEDATA request directs the installer to free any memory or resources it has allocated and stored in the private data portion of the DEVICE_INFO structure. The Device Manager sends this function just before destroying the structure. The Device Manager provides a set of requests (DIF_SELECTCLASSDRIVERS, DIF_VALIDATECLASSDRIVERS, AND DIF_INSTALLCLASSDRIVERS) that an installer can use to install a multiple set of drivers instead of a single driver. For example, a network installer may process these requests so that it can install the many different layers of drivers needed to support a network. An installer should process these requests only if it intends to carry out the complete installation on its own. The DIF_SELECTCLASSDRIVERS request directs the installer to select the driver or drivers to install for the given class; DIF_VALIDATECLASSDRIVERS directs the installer to validate all settings for the given devices; and DIF_INSTALLCLASSDRIVERS directs the installer to install the selected and validated drivers. The default action for these requests is to do nothing. Device Installation Functions Installers can use the device installation functions, provided by the SetupX dynamic-link library, to carry out installation tasks. The device installation functions allow installers to search INF files for compatible drivers, display driver choices to the user through selection dialogs, and perform the actual driver installation. Nearly all the device installation function rely on the information in the DEVICE_INFO structure to carry out the request tasks. You can create a linked list of these structures for the devices in the given class by using the DiGetClassDevs function. This function fills each structure with information about the individual devices. You can also create a single copy of a structure by using the DiCreateDeviceInfo function. This function lets you explicitly define the content of the structure and is useful for adding devices to the list that the DiGetClassDevs function may not have found. You can free all DEVICE_INFO structures in a list by using the DiDestroyDeviceInfoList function. This function also frees any compatible device and class device lists that may have been added to the structure. You can generate a list of selections from which the installer or the user can choose the drivers or device to install by using the DiBuildCompatDrvList and DiBuildClassDeviceList functions. DiBuildCompatDrvList creates a list of compatible drivers and DiBuildClassDeviceList creates a list of all devices of a given class. These functions create linked lists of DRIVER_NODE structures that contain information about the drivers and devices the function located in a search of all the INF files on a given path. Once you have a list of compatible drivers or devices, you can prompt the user to select from the list by using the DiSelectDevice function. This function displays a dialog box to that contains information about each device in the linked list of structures. You can install a selected driver by using the DiInstallDevice function. This function uses information in the given INF file to create any new registry entries required for the device, set the configuration of the device hardware, and copy the driver files to the appropriate directories. An installer may need to examine and set values under the registry key for a device that is about to be installed. You can open the hardware or driver key for a device by using the DiOpenRegKey function. You can install a new class of device in the registry by using the DiInstallClass function. This function requires an INF file that contains a valid [ClassInstall] section. Some device installation functions are intended to be used by system and may not be useful for ordinary installers. You can call the installer for a given class by using the DiCallClassInstaller function. This function is useful if a device installer needs support from the corresponding class installer to complete installation. The function uses the class name to locate, load, and call the appropriate class installer. You can remove a device entry from the registry by using the DiRemoveDevice function. Installer Registration The Device Manager requires that you register your class or device installers by adding Installer and Icon entries to the registry for the given class. The system maintains a System\CurrentControlSet\Services\Class branch under HKEY_LOCAL_MACHINE for information about each class. The value of the key contains the localized description of the class. The Installer and Icon entries have this form: Installer=installer-DLL-name[,Installer Entry Point] Icon=index [, icon-DLL-name] The Device Manager uses the icon to represent your installer to the user. If you fail to register include a Installer entry, the Device Manager takes the default actions in all cases. Enumerated Devices When an enumerator detects a new device, it relies on the Configuration Manager and Device Manager to locate the installer for the given device and install the appropriate drivers. Typically, the Device Manager generates a list of compatible drivers for the device and sends a DIF_SELECTDEVICE, followed by a DIF_INSTALLDEVICE request to the installer. If the Device Manager is in silent mode, it may send a DIF_INSTALLDEVICE request only. Reference This section describes the functions and structures that support the device installer. Functions This section describes the functions that support the device installer. DiBuildClassDrvList Builds a list of all drivers for a specificed class of devices. RETERR DiBuildClassDrvList(LPDEVICE_INFO lpdi) Return Value Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. If the return is OK, the lpdi->lpClassDrvList field will point to a list of supported drivers for the class. If there are no class drivers, this pointer will be NULL. Parameters lpdi Pointer to the device for which a class driver list should be built. Comments The lpdi->szClassName field should be filled in with the class name to be used when building the class driver list. If this field is not filled in, DiBuildClassDrvList will build a list of drivers for all classes. Note this API will build a full DRIVER_NODE struct for each driver in the class. Building full DRIVER_NODES requires memory overhead for each DRIVER_NODE and is slow, especially if the list of drivers is large. DiBuildClassDrvListFromOldInf Builds a class driver list from an old (Windows 3.1) style INF file. RETERR DiBuildClassDrvListFromOldInf(LPDEVICE_INFO lpdi, LPCSTR lpszSection, OLDINFPROC lpfnOldInfProc, LPARAM lParam) Return Value Returns OK. Parameters lpdi Pointer to a device info struct for a device that is being installed. lpszSection The install section in the old INF to be converted lpfnOldInfProc Callback function to fill in content of INF file. lParam Reference data passed to the callback proc. Comments The atDriverPath field of the lpdi must be set to a valid OEM INF file, which is type INF_TEXT. This function will generate an approprate Windows 95 INF header, and then call the supplied callback proc to convert the specified section into Win95 specific data. After the new INF is generated, this function will build a class driver list much like the DiBuildClassDrvList API does. DiBuildClassInfoList This API will build a list of CLASS_INFO structs. There will be one CLASS_INFO struct added to the list for each installed class in the user's system. RETERR DiBuildClassInfoList(LPLPCLASS_INFO lplpci) Return Value This function returns OK if the list is build successfully. Parameters lplpci A buffer to receive a pointer to a list of CLASS_INFO structs. Comments This function will return OK, even if the list is empty. The call must change the content of the passed in buffer to determine if the list is empty. If the value NoUseClass is present in the class's registry branch, the class will automatically be excluded from the list. This behavior cannot be overriden. See Also DiBuildClassInfoListEx DiDestroyClassInfoList DiBuildClassInfoListEx This API will build a list of CLASS_INFO structs. RETERR DiBuildClassInfoListEx(LPLPCLASS_INFO lplpci, DWORD dwFlags) Return Value This function returns OK if the list is build successfully. Parameters lplpci A buffer to receive a pointer to a list of CLASS_INFO structs. dwFlags Flags used to control exclusion of classes from the list. The following flags are defined: DIBCI_NOINSTALLCLASS Exclude a class if it has the value NoInstallClass present in its registry branch. DIBCI_NODISPLAYCLASS Exclude a class if it has the value NoDisplayClass present in its registry branch. Comments This API is similiar to DiBuildClassInfoList, except it allows more control over what classes will be included in the list. See Also DiBuildClassInfoList DiDestroyClassInfoList DiBuildCompatDrvList Builds a Compatible Driver list for a specificed device. RETERR DiBuildCompatDrvList(LPDEVICE_INFO lpdi) Return Value Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. If the return is OK, the lpdi->lpCompatDrvList field will point to a list of compatible drivers. If there are no compatible drivers, this pointer will be NULL. Parameters lpdi Pointer to the device for which a compatible driver list should be built. Comments The device specificed must have a harware registry key (i.e. an entry in HKLM\ENUM), and should have either, or both, a REGSTR_VAL_HARDWAREID and REGSTR_VAL_COMPATIBLEIDS value. The values should contain comma delimited lists of device ID's. Note the device ID's cannot contain comma's themselves. See Also DiBuildCompatDrvList DiCallClassInstaller Call the appropriate class installer with the specifed installer function. RETERR DiCallClassInstaller(DI_FUNCTIONS diFctn, LPDEVICE_INFO lpdi) Return Value Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. Parameters diFctn Class installer function to call. This can be one of the following: DIF_SELECTDEVICE Select a driver to be installed for the device. DIF_INSTALLDEVICE Install the driver for the device. DIF_PROPERTIES Display a properties dialog for the device. DIF_REMOVE Remove the device. DIF_FIRSTTIMESETUP Perform first time setup initialization. This message is sent during the first boot of Windows 95 and contains only class information. DIF_SELECTCLASSDRIVERS Select drivers for all devices of the class specified by the lpdi. DIF_VALIDATECLASSDRIVERS Ensure all devices of the class specified by the lpdi are ready to be installed. DIF_INSTALLCLASSDRIVERS Install drivers for all devices of the class specified by the lpdi. DIF_CALCDISKSPACE Compute the amount of disk space required by drivers for the device. DIF_DESTROYPRIVATEDATA Destroy any private date referenced by the lpdi->dwClassInstallReserved. DIF_MOVEDEVICE The device is being moved to a new location in HKLM\ENUM. DIF_DETECT Detect any devices of class specificed by the lpdi. DIF_INSTALLWIZARD Add any pages necessary to the New Device Wizard for the class specified by the lpdi. DIF_DESTROYWIZARDDATA Destroy any private data allocated due to a DIF_INSTALLWIZARD message. DIF_PROPERTYCHANGE The device's properties are changing. The device is being enabled, disabled, or has had a resource change. DIF_DETECTVERIFY The class installer should verify any devices it previously detected. Non verified devices should be removed. DIF_INSTALLDEVICEFILES The class installer should only install the driver files for the selected device. lpdi Pointer to a DEVICE_INFO struct for the device who's class installer is to be called. Comments This function will attempt to load and call the class installer for the class listed in the lpdi->szClassName field. If there is no class installer, or the class installer returns ERR_DI_DO_DEFAULT, then this function will call a default procedure for the specified class installer function. DiChangeState This API is used to change the state of an installed device. It is the default handler for the DIF_PROPERTYCHANGE class installer message. RETERR DiChangeState(LPDEVICE_INFO lpdi, DWORD dwStateChange, DWORD dwFlags, LPARAM lParam) Return Value This function returns OK if that are files that need to be copied. ERR_DI_NOFILECOPY will be returned if no files need to be copied. Parameters lpdi Device Info for device who's properties are being changed. dwStateChange Flag indicating which state is being changed. DICS_ENABLE The device is being enabled. DICS_DISABLE The device is being disabled. DICS_PROPCHANGE The properties of the device have changed, i.e. it is getting a new resource assignement. DICS_START The device is being started. If the device also disabled it will be enabled as well. DICS_STOP The device is being stoped. dwFlags Flags specific to the action specified by dwChangeState. DICS_FLAG_GLOBAL The action should be applied globally to all configurations. DICS_FLAG_CONFIGSPECIFIC The action should be applied ony to the configuration specified by lParam. lParam If dwFlags has the DICS_FLAG_CONFIGSPECIFIC bit set then this param contains the configuration number which the changes should be applied to. Specifying 0 indicates that the current config should be used. DiCreateDeviceInfo Creates a DEVICE_INFO struct and initializes it with specified information. RETERR DiCreateDeviceInfo(LPLPDEVICE_INFO lplpdi, LPCSTR lpszDescription, DWORD dnDevnode, HKEY hkey, LPCSTR lpszRegsubkey, LPCSTR lpszClassName, HWND hwndParent) Return Value Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. Parameters lplpdi Pointer to a pointer to a DEVICE_INFO struct. This pointer receives the pointer to the allocated DEVICE_INFO struct created by this function. lpszDescription If non-null, the description of the device. dnDevnode If non-zero, the the value of the devnode of the device. hkey The registry HKEY which the lpszRegsubkey is located in. This is usually HKEY_LOCAL_MACHINE. lpszRegsubkey If non-null, the registry subkey string where the hardware information of the device is stored. This subkey is relative to the hkey above. lpszClassName If non-null, the class name of the device. hwndParent If non-null, the window handle of the top level window use for any U/I related to installing the device. Comments The DEVICE_INFO struct is allocated zero-init in SETUPX's private heap, and so must be destroyed using DiDestroyDeviceInfoList See Also DiDestroyDeviceInfoList DiDeleteDevRegKey This API will delete one or both to the registry keys for the sepecified device. RETERR DiDeleteDevRegKey(LPDEVICE_INFO lpdi, int iFlags) Return Value OK if the registry key(s) are deleted Parameters lpdi A device info struct for del device that is being removed. iFlags Flags indicating which registry key(s) to remove. DIREG_DEV Delete the hardware registry key for the device. This is a key that exists in the \ENUM\ROOT branch. DIREG_DRV Delete the software, or Driver, registry key for the device. This is a key that is in the HKLM\System\CurrentControlSet\Services\Class registry subkey. DIREG_BOTH Delete both registry keys for the device. DiDestroyClassInfoList This API will delete a single, or list of, CLASS_INFO struct(s). RETERR DiDestroyClassInfoList(LPCLASS_INFO lpci) Return Value This function returns OK. Parameters lpci A pointer to a single or list of CLASS_INFO struct(s). Comments This function will free any memory associated with the passed in lpci. This function will free any DEVICE_INFO structs also associated with this CLASS_INFO. See Also DiBuildClassInfoList DiBuildClassInfoListEx DiDestroyDeviceInfoList Destroys a list of DEVICE_INFO structures. RETERR DiDestroyDeviceInfoList(LPDEVICE_INFO lpdi) Return Value Returns OK. Parameters lpdi Pinter to a list of DEVICE_INFO structs. Comments The list can contain only 1 struct. This function will free any compatible and/or class driver lists created using the lpdi(s) as well. Any class installer DLL's or property providor DLL's associated with the lpdi(s) list be freed also. See Also DiCreateDeviceInfo DiGetClassDevs DiGetClassDevsEx DiGetClassDevs Returns a list of DEVICE_INFO structs for all of the installed devices of a specified class. RETERR DiGetClassDevs(LPLPDEVICE_INFO lplpdi, LPCSTR lpszClassName, HWND hwndParent, int iFlags) Return Value Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. Parameters lplpdi Pointer to a pointer to a DEVICE_INFO struct. This pointer receives the pointer to the beginning of the list of DEVICE_INFO structs created by this function. lpszClassName If non-null, the class name to use when creating the list of devices. hwndParent If non-null, the window handle of the top level window use for any U/I using the resulting DEVICE_INFO structs. iFlags Control options for building the device list. DIGCF_PRESENT Return only devices which are present. This flag is only valid if Config Manager is running and has created devnodes for the installed devices. DIGCF_ALLCLASSES Return a list of installed devices for all classes. If set, this flags will cause lpszClassName to be ignored. DIGCF_PROFILE Return only devices which are present in the current configuration. Comments This function build a list of device that have been previsouly installed. This function uses the HKLM\ENUM branch of the registry to build its list. See Also DiGetClassDevsEx DiGetClassDevsEx Returns a list of DEVICE_INFO structs for all of the installed devices of a specified class. RETERR DiGetClassDevsEx(LPLPDEVICE_INFO lplpdi, LPCSTR lpszClassName, LPSTR lpszEnumerator, HWND hwndParent, int iFlags) Return Value Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. Parameters lplpdi Pointer to a pointer to a DEVICE_INFO struct. This pointer receives the pointer to the beginning of the list of DEVICE_INFO structs created by this function. lpszClassName If non-null, the class name to use when creating the list of devices. lpszEnumerator If specified this API will retrieve devices created by the specified enumerator. If NULL then this functions works like DiGetClassDevs. For example. this parameter could specify ROOT, and only device in the ENUM\ROOT branch would be returned. hwndParent If non-null, the window handle of the top level window use for any U/I using the resulting DEVICE_INFO structs. iFlags Control options for building the device list. DIGCF_PRESENT Return only devices which are present. This flag is only valid if Config Manager is running and has created devnodes for the installed devices. DIGCF_ALLCLASSES Return a list of installed devices for all classes. If set, this flags will cause lpszClassName to be ignored. DIGCF_PROFILE Return only devices which are present in the current configuration. Comments This function build a list of device that have been previsouly installed. This function uses the HKLM\ENUM branch of the registry to build its list. See Also DiGetClassDevs DiInstallClass Install the [ClassInstall] section of the specificed INF. RETERR DiInstallClass(LPCSTR lpszInfFileName, DWORD dwFlags) Return Value Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. Parameters lpszInfFileName The name of the INF file containing a [ClassInstall] section. dwFlags Flags to control the geninstall operation. DI_NOVCP This flag should be specificed if a VCP queue is allready opened. DI_NOBROWSE This flag should be specificed if no file browsing should be allowed in the event a copy operation cannot find a specificed file. Comments This API is generally called the the Device Manager when it installs a device of a new class. DiInstallDevice Install the device specified by lpdi. RETERR DiInstallDevice(LPDEVICE_INFO lpdi) Return Value Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. lpdi->Flags will be set to indicate if the system needs to be rebooted or restarted for the device to be started. Parameters lpdi Pointer to a DEVICE_INFO struct for the device being installed. If lpdi->lpSelectedDriver is NULL this function will install a NULL driver for the device, otherwise it installs the driver specificed in the driver node. Comments This API is the default handler for the DIF_INSTALLDEVICE class installer function. This API will install a device by GenInstalling the install section specificed by the lpid->lpSelectedDriver DRIVER_NODE. If Config Manager is running, this API will attempt to dynamically start the device. DiOpenClassRegKey Open the class registry key, and optionally a specific class's subkey. RETERR DiOpenClassRegKey(LPHKEY lphk, LPCSTR lpszClassName) Return Value Returns OK if successful, otherwise an ERR_DI_xxx error code will be returned. Parameters lphk Buffer to receive the opened registry key. lpszClassName The name of a specific class. If non NULL the specificed class's subkey will be opened are retured if it exists. If this parameter is NULL, the registry key of the class branch (HKLM\System\CurrentControlSet\Services\Class) will be returned. DiOpenDevRegKey This API will open either of the registry keys associated with a device. RETERR DiOpenDevRegKey(LPDEVICE_INFO lpdi, LPHKEY lphk, int iFlags) Return Value OK. Parameters lpdi A device info struct for device who's registry key is being opened. lphk Buffer to receive the opened registry key. iFlags Flags indicating which type of regkey to create. DIREG_DEV Open the hardware registry key for the device. This is a key that exists in the \ENUM\ROOT branch. DIREG_DRV Open the software, or Driver, registry key for the device. This is a key that is in the HKLM\System\CurrentControlSet\Services\Class registry subkey. Comments Note that it is the callers responsibility to close the returned registry key when it is finished with it. DiRemoveDevice Removes a device from the computer RETERR DiRemoveDevice(LPDEVICE_INFO lpdi) Return Value Returns OK. Parameters lpdi Pointer to a DEVICE_INFO struct for the device to be removed. Comments This function will remove the the device from the system, deleting both of its registry keys, and dynamically stoping the device if it has a Devnode. If the device cannot be dynamically stoped, then flags will be set in the lpdi->Flags field that will eventually cause the user to be prompted to shut the system down. The removal is either global to all configurations, or specific to one configuration depending on the content of the lpdi->lpClassInstallParams field. DiSelectDevice This is the default handle for the DIF_SELECTDEVICE class installer message. RETERR DiSelectDevice(LPDEVICE_INFO lpdi) Return Value OK if a driver is selected successfully, otherwise one of the ERR_DI_ error codes will be returned Parameters lpdi A device info struct for the device that is having a driver selected. Comments This routine will handle the UI for allowing a user to select a driver for the device defined by the passed in lpdi. By using the Flags field of the lpdi struct, the caller can specify special handling of the UI, such as allowing selecting from OEM disks. Structures This section describes the functions that support the device installer. DEVICE_INFO This is the basic data structure for most Device installation APIs. A DEVICE_INFO represents a device that is being installed on the system, or an installed device that is being modified in some way. typedef struct { UINT cbSize; struct _DEVICE_INFO FAR *lpNextDi; char szDescription[LINE_LEN]; DWORD dnDevnode; HKEY hRegKey; char szRegSubkey[MAX_DEVNODE_ID_LEN]; char szClassName[MAX_CLASS_NAME_LEN]; DWORD Flags; HWND hwndParent; LPDRIVER_NODE lpCompatDrvList; LPDRIVER_NODE lpClassDrvList; LPDRIVER_NODE lpSelectedDriver; ATOM atDriverPath; ATOM atTempInfFile; HINSTANCE hinstClassInstaller; HINSTANCE hinstClassPropProvidor; HINSTANCE hinstDevicePropProvidor; HINSTANCE hinstBasicPropProvidor; FARPROC fpClassInstaller; FARPROC fpClassEnumPropPages; FARPROC fpDeviceEnumPropPages; FARPROC fpEnumBasicProperties; DWORD dwSetupReserved; DWORD dwClassInstallReserved; GENCALLBACKPROC gicpGenInstallCallBack; LPARAM gicplParam; UINT InfType; HINSTANCE hinstPrivateProblemHandler; FARPROC fpPrivateProblemHandler; LPARAM lpClassInstallParams; struct _DEVICE_INFO FAR *lpdiChildList; DWORD dwFlagsEx; LPDRIVER_INFO lpCompatDrvInfoList; LPDRIVER_INFO lpClassDrvInfoList; } DEVICE_INFO; Members cbSize Size of the DEVICE_INFO struct. *lpNextDi Pointer to the next DEVICE_INFO struct in a linked list. szDescription[LINE_LEN] Buffer containing the description of the device. dnDevnode If set, this contains the address of the DevNode associated with the device. hRegKey An opened registry key that contains the device's registry subkey. This is usually HKEY_LOCAL_MACHINE. szRegSubkey[MAX_DEVNODE_ID_LEN] Buffer containing the device's hardware registry subkey. This is key is rooted in hRegKey, and is ususally some place in the \ENUM branch. szClassName[MAX_CLASS_NAME_LEN] Buffer containing the device's class name. Flags Flags for controlling installation and U/I functions. Some flags can be set prior to calling device installer APIs, and other are set automatically during the processing of some APIs. DI_SHOWOEM Set if OEM disk support should be allowed DI_SHOWCOMPAT Will be set if only a compatible driver list is being displayed by DiSelectDevice. DI_SHOWCLASS Will be set if only a Class driver list is is being displayed by DiSelectDevice. DI_SHOWALL Will be set if both a compatible driver list and a class driver list are being shown by DiSelectDevice. DI_NOVCP Set if no VCP (Virtual Copy Procedure) is desired during DiInstallDevice. DI_DIDCOMPAT Will be set if DiBuildCompatDrvList has been done, and lpCompatDrvList points to this device's compatible driver list. DI_DIDCLASS Will be set if DiBuildClassDrvList has been done, and lpClassDrvList points to this device's class driver list. DI_AUTOASSIGNRES Unused. DI_NEEDRESTART Will be set if the device requires a restart of Windows after installation or a state change. DI_NEEDREBOOT Will be set if the device requires a reboot of the machine after installation or a state change. DI_NOBROWSE Set to diable browsing when selecting an OEM disk path. DI_MULTMFGS Will be set if a class driver list, or class info list contains multiple manufactures. DI_DISABLED Unused. DI_GENERALPAGE_ADDED Set by a property page provider if a general properties page has been added to the device's property sheet. DI_RESOURCEPAGE_ADDED Set by a property page provider if a resource properties page has been added to the device's property sheet. DI_PROPERTIES_CHANGE Set if a device's properties have been changed and require an update of the Device Manager's U/I. DI_INF_IS_SORTED Set if the INF containing drivers for this device is in sorted order. DI_ENUMSINGLEINF Set if DiBuildCompatDrvList and DiBuildlassDrvList should only search the INF file specificed by atDriverPath. DI_DONOTCALLCONFIGMG Set if the configuration manager should not be called during DiInstallDevice. DI_INSTALLDISABLED Set if the device should be installed in a disabled state by default. DI_CLASSONLY Set if this DEVICE_INFO struct contains only a class name. DI_CLASSINSTALLPARAMS Set if the lpClassIntallParams field points to a class install parameter block. DI_NODI_DEFAULTACTION Set if DiCallClassInstaller should not perform any default action if the class installer return ERR_DI_DO_DEFAULT, or there is not class installer. DI_QUIETINSTALL Set if device install API should be as silent as possible using default choices whereever possible. DI_NOFILECOPY Set if DiInstallDevice should skip file copying. DI_FORCECOPY Set if DiInstallDevice should always copy file, even if they are present on the system. DI_DRIVERPAGE_ADDED Set by a property page provider if a driver properties page has been added to the device's property sheet. DI_USECI_SELECTSTRINGS Set if class installer provided strings should be used during DiSelectDevice. DI_OVERRIDE_INFFLAGS Unused. DI_PROPS_NOCHANGEUSAGE Set if there should be no Enable/Disable capability on the device's general property page. DI_NOSELECTICONS Set if no small icons should be used during DiSelectDevice. DI_NOWRITE_IDS Set if DiInstallDevice should not write the device's hardware and compatible IDs to the registry. hwndParent Window handle that will own U/I dialogs related to this device. lpCompatDrvList Pointer to a linked list of DRIVER_NODES representing the compatible drivers for this device. lpClassDrvList Pointer to a linked list of DRIVER_NODES representing all drivers of this device's class. lpSelectedDriver Pointer to a single DRIVER_NODE that has been selected as the driver for this device. atDriverPath Global ATOM containing the path to this device's INF file. This is set only of the driver came from an OEM INF file. This will be 0 if the INF is a standard Windows INF file. atTempInfFile Global ATOM containing the name of a temporary INF file for this device's drivers. This is set if the drivers came from an old style INF file and have been converted. hinstClassInstaller Class installer module instance. hinstClassPropProvidor Class Property Providor module instance. hinstDevicePropProvidor Device Property Providor module instance. hinstBasicPropProvidor Basic Property Providor module instance. fpClassInstaller Procedure address of class install function. fpClassEnumPropPages Procedure address of the Class property provider page enumeration function. fpDeviceEnumPropPages Procedure address of the Device property provider page enumeration function. fpEnumBasicProperties Procedure address of the Basic device property provider page enumeration function. dwSetupReserved Reserved for use by Setup. dwClassInstallReserved Reserved for use by Class Installers. gicpGenInstallCallBack Procedure address of a GenInstall call back function. This would be set if the class installer wanted to handle GenInstall callbacks during DiInstallDevice. gicplParam lParam for the GenInstall Callback. InfType The type of INF file being used. This will be INFTYPE_TEXT or INFTYPE_EXECUTABLE. hinstPrivateProblemHandler Module handle for the device's private problem procedure. fpPrivateProblemHandler Procedure address of the device's private problem handler. lpClassInstallParams Pointer to a class install parameter block. Class installer parameters are specific to the class install functions. *lpdiChildList Pointer to a linked list of DRIVER_INFO structs representing children of this device. dwFlagsEx Additional control flags. DI_FLAGSEX_USEOLDINFSEARCH Set if INF Search functions should not use indexed searching. DI_FLAGSEX_AUTOSELECTRANK0 Set if DiSelectDevice should automatically select rank 0 match drivers. DI_FLAGSEX_CI_FAILED Will be set internally if there was a failure to load or call a class installer. DI_FLAGSEX_FILTERCLASSES If set, DiBuildClassDrvList will check for Class inclusion filters. This means devices will not be included in the list, if their class is marked as a NoInstallClass class. DI_FLAGSEX_SETFAILEDINSTALL If set, then if DiInstallDevice installs a NULL driver, it will also set the FAILEDINSTALL config flag DI_FLAGSEX_DEVICECHANGE If set, the device manager will rebuild its tree of devices after the device property sheet is closed. DI_FLAGSEX_ALWAYSWRITEIDS If set, and the flag, DI_NOWRITE_ID is clear (i.e., that flag takes higher precedence) then always write Hardware and Compat ids, even if they already exist DI_FLAGSEX_ALLOWEXCLUDEDDRVS If set, DiSelectDevice will display drivers that have the Exlude From Select state lpCompatDrvInfoList Pointer to a linked list of DRIVER_INFO structs that are compatible with this device. lpClassDrvInfoList Pointer to a linked list of DRIVER_INFO structs representing all drivers for this device's class. DRIVER_INFO This structure contains the information necessary to present the user with a select device dialog. typedef struct { WORD cbSize; struct _DRIVER_INFO FAR *lpNextInfo; LPSTR lpszDescription; LPSTR lpszMfgName; LPSTR lpszProviderName; WORD Rank; DWORD dwFlags; LPARAM lpReserved; DWORD dwPrivateData; } DRIVER_INFO; Members cbSize Size of this structure in bytes. *lpNextInfo Pointer to the next DRIVER_INFO struct in a linked list. lpszDescription Pointer to the description of the device being supported by this driver. lpszMfgName Pointer to the name of the manufacture of this driver. lpszProviderName Pointer to provider of this driver if the lpdi->Flags has the DI_MULTMFGS flag set. Rank The Rank match of this driver. Ranks go from 0 to n, where 0 is the most compatible. dwFlags Flags that control the use of this driver node. These are the same as the flags defined for a DRIVER_NODE. DNF_DUPDESC This driver has the same device description from by more than one provider. DNF_OLDDRIVER Driver node specifies old/current driver DNF_EXCLUDEFROMLIST If set, this driver node will not be displayed in any driver select dialogs. DNF_NODRIVER Set if we want to install no driver, e.g. no mouse.drv DNF_CONVERTEDLPINFO Set if this Driver Node was converted from an Info Node. Setting this flag will cause the cleanup functions to explicitly delete it. lpReserved Reserved for use by the Device Installer. dwPrivateData Reserved for use by the Device Installer. DRIVER_NODE This strucure represents a driver which can be installed for a specific device. typedef struct { struct _DRIVER_NODE FAR* lpNextDN; UINT Rank; UINT InfType; unsigned InfDate; LPSTR lpszDescription; LPSTR lpszSectionName; ATOM atInfFileName; ATOM atMfgName; ATOM atProviderName; DWORD Flags; DWORD dwPrivateData; LPSTR lpszDrvDescription; LPSTR lpszHardwareID; LPSTR lpszCompatIDs; } DRIVER_NODE; Members lpNextDN Pointer to the next driver node in a list. Rank The Rank match of this driver. Ranks go from 0 to n, where 0 is the most compatible. InfType Type of INF this driver cam from. This will be either INFTYPE_TEXT or INFTYPE_EXECUTABLE InfDate DOS date stamp of the INF file. lpszDescription Pointer to a the descriptrion of the device being supported by this driver. lpszSectionName Pointer to the name of INF install section for this driver. atInfFileName Global ATOM containing the name of the INF file. atMfgName Global ATOM containing the name of this driver's manufacture. atProviderName Global ATOM containing the name of this driver's provider. Flags Flags that control functions using this DRIVER_NODE DNF_DUPDESC This driver has the same device description from by more than one provider. DNF_OLDDRIVER Driver node specifies old/current driver DNF_EXCLUDEFROMLIST If set, this driver node will not be displayed in any driver select dialogs. DNF_NODRIVER Set if we want to install no driver e.g no mouse drv dwPrivateData Reserved lpszDrvDescription Pointer to a driver description. lpszHardwareID Pointer to a list of Plug-and-Play hardware IDs for this driver. lpszCompatIDs Pointer to a list of Plug-and-Play compatible IDs for this driver. ENABLECLASS_PARAMS DIF_ENABLECLASS class install parameters typedef struct { UINT cbSize; LPSTR szClass; WORD wEnableMsg; } ENABLECLASS_PARAMS; Members cbSize Size of the ENABLECLASS_PARAMS struct. szClass The class that is being enabled. wEnableMsg Specifies the stage of enabling. Can be one of: Constants ENABLECLASS_QUERY The class is about to be enabled. Return ERR_DI_DO_DEFAULT to allow the class to be enabled, or ERR_DI_FAIL_QUERY to prevent the class from being enabled. ENABLECLASS_SUCCESS The enabling of the class has succeeded, return ERR_DI_DO_DEFAULT. ENABLECLASS_FAILURE The enabling of the class has failed, return ERR_DI_DO_DEFAULT. INSTALLWIZARDDATA DIF_INSTALLWIZARD class install parameters. This struct is used by class installers to extend the operation of the hardware installation wizard by adding custom pages. typedef struct { UINT cbSize; LPDEVICE_INFO lpdiOriginal; LPDEVICE_INFO lpdiSelected; DWORD dwFlags; LPVOID lpConfigData; WORD wAnalyzeResult; HPROPSHEETPAGE hpsDynamicPages[MAX_INSTALLWIZARD_DYNAPAGES]; WORD wNumDynaPages; DWORD dwDynaWizFlags; DWORD dwPrivateFlags; LPARAM lpPrivateData; LPSTR lpExtraRunDllParams; HWND hwndWizardDlg; } INSTALLWIZARDDATA; Members cbSize Size of the INSTALLWIZARDDATA struct. lpdiOriginal Pointer to the Original DEVICE_INFO struct at the start of the manual installation. lpdiSelected Pointer to the current DEVICE_INFO struct that is being manually selected. dwFlags Flags that control the operation of the hardware installation wizard. There are currently none defined. lpConfigData Pointer to configuration data for analysis to determine if the selected device can be installed with no conflicts. wAnalyzeResult Results of analysis to determine if the device can be installed with no problems. The following values are defined: ANALYZE_FACTDEF_OK The device can be installed using its factory default settings. ANALYZE_STDCFG_OK The device can be installed using a configuration specified in one if its basic logical configurations. The user will probably have to set jumpers or switches on the hardware to match the settings determined by the install wizard. ANALYZE_CONFLICT The device cannot be installed without causing a conflict with another device. ANALYZE_NORESOURCES The device does not require any resources, so it can be installed witth no conflicts. ANALYZE_ERROR There was an error during analysis. ANALYZE_PNP_DEV The device has a least one softsettable logical configurations, allowing it to be automatically configured. Additionally the device will be enumerated by one of the standard bus enumerators, so it does not require manual installation, except to pre-copy driver files. hpsDynamicPages[MAX_INSTALLWIZARD_DYNAPAGES] An array of property sheet page handles. The class installer would use this array to create custom wizard pages, and insert their handles into this array. wNumDynaPages The number of pages inserted into the hpsDynamicPages array. dwDynaWizFlags Flags that control the behavior of the installation wizard whtn dynamic pages have been added. DYNAWIZ_FLAG_PAGESADDED Will be set by the install wizard if the class installer adds custom pages. DYNAWIZ_FLAG_INSTALLDET_NEXT If set, the install wizard will allow going forward from the detected devices page, otherwise finish will be the default option for the detected devices page. DYNAWIZ_FLAG_INSTALLDET_PREV If set, the install wizard will allow going back from the detected devices page. DYNAWIZ_FLAG_ANALYZE_HANDLECONFLICT If set, the class installer will handle the case where the selected device cannot be installed because of a conflict. dwPrivateFlags Flags that may be defined and used by the class installer. lpPrivateData Pointer to private reference data defined and set by the class installer. lpExtraRunDllParams Pointer to a string containing extra parameters passed to the hardware install rundll function. hwndWizardDlg Window handle of the install wizard top level window. MOVEDEV_PARAMS DIF_MOVEDEVICE class install parameters typedef struct { UINT cbSize; LPDEVICE_INFO lpdiOldDev; } MOVEDEV_PARAMS; Members cbSize Size of the MOVDEV_PARAMS struct. lpdiOldDev Pointer to the device that is being moved. PROPCHANGE_PARAMS DIF_PROPCHANGE class install parameters typedef struct { UINT cbSize; DWORD dwStateChange; DWORD dwFlags; DWORD dwConfigID; } PROPCHANGE_PARAMS; Members cbSize Size of the PROPCHANGE_PARAMS struct. dwStateChange State change action. See DiChangeState for details. dwFlags Flags specific to the type of state change. dwConfigID Configuration ID for config specific changes. See Also DiChangeState REMOVEDEVICE_PARAMS DIF_REMOVE class install parameters typedef struct { UINT cbSize; DWORD dwFlags; DWORD dwConfigID; } REMOVEDEVICE_PARAMS; Members cbSize Size of the REMOVEDEVICE_PARAMS struct. dwFlags Flags indicating the type of removal to perform. DI_REMOVEDEVICE_GLOBAL The device will be removed globally. DI_REMOVEDEVICE_CONFIGSPECIFIC The device will be removed from only the specified configuration. dwConfigID If DI_REMOVEDEVICE_CONFIGSPECIFIC is set, then this is the configuration the device will be removed from. 0 means the current config. SELECTDEVICE_PARAMS DIF_SELECTDEVICE class install parameters typedef struct { UINT cbSize; char szTitle[MAX_TITLE_LEN]; char szInstructions[MAX_INSTRUCTION_LEN]; char szListLabel[MAX_LABEL_LEN]; } SELECTDEVICE_PARAMS; Members cbSize Size of the SELECTDEVICE_PARAMS struct. szTitle[MAX_TITLE_LEN] Buffer containing a class installer provided title for the Select Device dialogs. szInstructions[MAX_INSTRUCTION_LEN] Buffer containing class installer provided Select Device instructions. szListLabel[MAX_LABEL_LEN] Buffer containing a lable of the Select Device list of drivers. Constants This section describes the constants used to support device installation. Error Values typedef enum { ERR_DI_INVALID_DEVICE_ID, ERR_DI_INVALID_COMPATIBLE_DEVICE_LIST, ERR_DI_REG_API, ERR_DI_LOW_MEM, ERR_DI_BAD_DEV_INFO, ERR_DI_INVALID_CLASS_INSTALLER, ERR_DI_DO_DEFAULT, ERR_DI_USER_CANCEL, ERR_DI_NOFILECOPY, ERR_DI_BAD_CLASS_INFO, ERR_DI_BAD_INF, ERR_DI_BAD_MOVEDEV_PARAMS, ERR_DI_NO_INF, ERR_DI_BAD_PROPCHANGE_PARAMS, ERR_DI_BAD_SELECTDEVICE_PARAMS, ERR_DI_BAD_REMOVEDEVICE_PARAMS, ERR_DI_BAD_ENABLECLASS_PARAMS, ERR_DI_FAIL_QUERY, ERR_DI_API_ERROR, ERR_DI_BAD_PATH } _ERR_DEVICE_INSTALL; Members ERR_DI_INVALID_DEVICE_ID Incorrectly formed device ID. ERR_DI_INVALID_COMPATIBLE_DEVICE_LIST Invalid compatible device list. ERR_DI_REG_API Error returned by one of the registry API. ERR_DI_LOW_MEM Insufficient memory to complete. ERR_DI_BAD_DEV_INFO A passed in DEVICE_INFO struct is invalid. ERR_DI_INVALID_CLASS_INSTALLER The class installer is listed incorrecrly in the registry, or points to an invalid class installer. ERR_DI_DO_DEFAULT Do the default action for the requested operation. ERR_DI_USER_CANCEL The user cancelled the operation. ERR_DI_NOFILECOPY No need to copy files (in install). ERR_DI_BAD_CLASS_INFO A passed in CLASS_INFO struct is invalid. ERR_DI_BAD_INF An invalid INF file was encountered. ERR_DI_BAD_MOVEDEV_PARAMS A passed in MOVEDEVICE_PARAMS struct was invalid. ERR_DI_NO_INF No INF found on supplied OEM path. ERR_DI_BAD_PROPCHANGE_PARAMS A passed in PROPCHANGE_PARMS struct was invalid. ERR_DI_BAD_SELECTDEVICE_PARAMS A passed in SELECTEDEVICE_PARAMS struct was invalid. ERR_DI_BAD_REMOVEDEVICE_PARAMS A passed in REMOVEDEVICE_PARAMS struct was invalid. ERR_DI_BAD_ENABLECLASS_PARAMS       !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnoprstuvwxyz{|}~A passed in ENABLECLASS_PARAMS struct was invalid. ERR_DI_FAIL_QUERY The queried action should not take place. ERR_DI_API_ERROR One of the Device installation APIs was called incorrectly or with invalid parameters. ERR_DI_BAD_PATH An OEM path was specified incorrectly Dynamic Hardware Install Wizard Constants Constants that are used when adding custom pages to the hardware install wizard. Constants MAX_INSTALLWIZARD_DYNAPAGES The maximum number of dynamic hardware installation wizard pages that can be added by a class installer. IDD_DYNAWIZ_FIRSTPAGE Resource ID for the first page that the install wizard will go to after adding the class installer pages. IDD_DYNAWIZ_SELECT_PREVPAGE Resource ID for the page that the Select Device page will go back to. IDD_DYNAWIZ_SELECT_NEXTPAGE Resource ID for the page that the Select Device page will go forward to. IDD_DYNAWIZ_ANALYZE_PREVPAGE Resource ID for the page that the Analyze page will go back to. This will only be used in the event that there is a problem (e.g. a conflict), and the user selects Back from the analyze page. IDD_DYNAWIZ_ANALYZE_NEXTPAGE Resource ID for the page that the Analyze page will go to if it continues forward. The wAnalyzeResult in the INSTALLWIZARDDATA struct will contain the analysis results. IDD_DYNAWIZ_INSTALLDETECTED_PREVPAGE Resource ID for that page that the Install detected devices page will go back to. IDD_DYNAWIZ_INSTALLDETECTED_NEXTPAGE Resource ID for the page that the Install detected devices page will go forward to. IDD_DYNAWIZ_INSTALLDETECTED_NODEVS Resource ID for the page that the Install detected devices page will go to in the event that no devices are detected. IDD_DYNAWIZ_SELECTDEV_PAGE Resource ID of the hardware install wizard's select device page. This ID can be used to go directly to the hardware install wizard's select device page. IDD_DYNAWIZ_ANALYZEDEV_PAGE Resource ID of the hardware install wizard's device analysis page. This ID can be use to go directly to the hardware install wizard's analysis page. IDD_DYNAWIZ_INSTALLDETECTEDDEVS_PAGE Resource ID of the hardware install wizard's install detected devices page. This ID can be use to go directly to the hardware install wizard's install detected devices page. IDD_DYNAWIZ_SELECTCLASS_PAGE Resource ID of the hardware install wizard's select class page. This ID can be use to go directly to the hardware install wizard's select class page. Chapter SEQ CHAPTER \R 66 Device Information Files About INF Files and the INF File Editor Device information files (INF) files contribute to the goal of providing customers and developers with an easier way to install hardware devices. The information in an INF file brings together one or more devices, device drivers, and the operating systems installation procedure to ensure an easy and complete hardware setup and installation. If you are providing plug and play or non-plug and play hardware for Windows 95 computers, you must create an INF file that enables your device to be installed and to work in the Windows 95 environment. The Windows 95 DDK contains a tool, Infedit, that enables you to build an INF file by responding to the Infedit user interface. The topic Getting Started Using Infedit later in this chapter contains the requirements for a sample INF file, XSCSI.INF, and walks through the process of using Infedit to turn those requirements into a working INF file. For more information about how Windows 95 uses INF files, use the Programs command from the Windows 95 Start menu to open the Windows 95 DDK and then select the Plug and Play Reference. Use the Find tab on the displayed property sheet to find instances of the word INF in the Plug and Play topics. Limits of the INF File Editor Note that several classes of devices -- namely printers and network adapters -- have INF file extensions specific to those devices which are not described in this chapter. For a description of the printer INF extensions, see the topic Router and Local Print Provider in the Windows 95 DDK help reference for the print spooler and printer drivers. For a description of the network INF extensions, see the topic Network Driver Installer in the Windows 95 DDK help reference for networks. There are also some special cases of INF files, such as INF files for multifunction boards, that require you to add items to the INF file you create with Infedit. Introducing INF Files In order to become immediately productive with Infedit, it helps to have a model of the parts of an INF file in mind. Infedit builds an INF file one section and one item at a time. An INF file is made up of a set of named sections. To be used by the operating system installer, a section must contain one or more items. Each section begins with the section name enclosed in square brackets. In this way, INF files are similar to Windows INI files. There can be any number of sections in an INF file, but there are only about two dozen types of sections that can be in an INF file, and about eight of these types of sections appear far more often than other types in INF files. Each type of section has a particular purpose; for example, to copy files or to add entries to the registry. Each of the items in a section contributes to that sections purpose and the syntax of each type of item that can be used in a particular type of section reflects that. Three sections from a sample INF file are shown below, so you can more easily visualize an INF file being made up of sections and each section being made up of one or more items. The section named SourceDisksNames contains one item, the section named SourceDisksFiles contains two items, and the section named Strings contains three items. [SourceDisksNames] 1=CX2590 Windows 95 Installation Disk,Instd1,0000-0000 [SourceDisksFiles] CX2590.MPD=1 SRSutil.exe=1 [Strings] String1="Corporation X" String2="Corporation X" String3="CX2590 SCSI Adapter" Introducing the INF Editor The easiest way to create an INF file is to run the INF Editor, Infedit. After the Windows95 DDK is installed, Infedit can be found in the directory %DDKROOT%\BIN. You can use Infedit to either build an INF file from scratch or edit an existing INF file for the same class of device as your device. After Windows 95 is installed on a computer, a large number of INF files can be found in the directory %WINROOT%\INF. When you first start using Infedit, it is instructive to use Infedit to open some of these INF file and browse their contents using the Infedit user interface. After opening and browsing several INF files, you will be quite familiar with the Infedit user interface and may have gotten some ideas for your INF file by example. Look for INF files of the same device class as your device and open and browse them. You may be able to edit one of them instead of building your INF file from scratch. Following is a list of the hardware class names that are built into Windows 95: CD-ROM Controllers Display Adapters Floppy disk controllers Hard disk controllers Keyboard Memory Technology Drivers (MTDs) Modem Mouse Multi-function adapters Network adapters Other devices PCMCIA sockets Ports (COM & LPT) Printer SCSI Controllers Sound, video and game controllers System devices When you run Infedit to create a new INF file, select New from the Infedit File menu. Infedit presents a screen that enables you to build and name INF file sections, and to fill each of those sections with one or more items: On the left side of the screen, Infedit maintains a graphic representation of the current structure and content of your INF file. The folders represent all the types of INF file sections you can create and are containers for sub folders that represent the sections. The section sub folders, in turn, are containers for items. On the right side of the screen is an edit area where you compose items. Each item has a name and a value. In general, when you double-click on a section subfolder on the left of the screen, the items currently in that subfolder are displayed in the edit area on the right. Double-click on an item name displayed in the edit area to display a dialog box that enables you to change the value of the item. See the topic Reference for detailed information items that can be put into each of the INF file sections you can build with Infedit. (The Reference section is organized by INF file section type.) Note that if you need to build a section in your INF file that is not explicitly shown as a folder in the Infedit user interface, you can use the Miscellaneous Sections folder in the Infedit user interface to build those type of sections. An example of such a section is the HW section, which is only used in INF files for multifunction devices. Types of INF File Sections All the types of sections that can be in an INF file and the purpose of each type of section is listed in the following table. Type of INF File SectionPurposeCommentINF file header.The standard header for all INF files.The INF file header items are contained in the folder labelled in the illustration above. The syntax and meaning of the INF file header items is defined in the Reference topic under the section name Version.ClassInstall sectionInstalls a new class for a device in the Class section of the registry on a Windows 95 machine.Disk Names sectionIdentifies and names the disk(s) that are the source of files that are copied to the hard disk during installation. Also names the files that are on each of the installation disk(s).The syntax and meaning of items that are contained in a Disk Names section are documented in the Reference topic under the topics SourceDisksNames section and SourceDisksFiles section.ManufacturerIdentifies the manufacturer of one or more devices defined in the INF file, describes the device(s), and identifies the Install section that contains the script for installing each device.Install sectionsIdentifies the other sections in the INF file that describe the resource requirements of a device and which add entries to the registry, copy files, etc.CopyFiles sectionsNames the files copied from the source disk(s) to the destination directories during device installation.Infedit puts the destination directory information into a DestinationDirs section.Rename Files sectionsNames the files to be renamed when they are copied from the source disk(s) to the destination directories during device installation. Also gives the new filenames on the destination directories.Infedit puts the destination directory information into a DestinationDirs section.DelFiles sectionsNames the files to be deleted from destination directories during device installation.Used, for example, to delete obsolete versions of device drivers. Infedit puts the destination directory information into a DestinationDirs section.Add Registry sectionsAdds subkeys or value names to the registry, optionally setting values.Delete Registry sectionsDeletes subkeys or value names from the registry.Log Config sectionsDefines device configuration details such as IRQs, memory address ranges, I/O address ranges, and/or DMA channels.Update Autoexec.bat sectionsManipulates lines in the AUTOEXEC.BAT file.Update Config.sys sectionsManipulates lines in the CONFIG.SYS file.Ini File to Registry sectionsMoves lines or sections from an INI file to the registry, creating or replacing an entry under a specific key in the registry.Update Ini File sectionsReplaces, adds, and deletes entries in an INI file.Update Ini Fields sectionsReplaces, adds, and deletes fields in the value of a given entry in an INI file.Strings sectionDefines one or more names that represent a string of displayable characters.HW sectionA special case of an Install section. The only type of section that allows entries to be made to the Hardware branch of the registry.Build an HW section using the Miscellaneous Sections folder of the Infedit user interface. See the Reference section for the items that appear in an HW section and their syntax.NoResDup sectionProvides a method for the installing devices that use no resources.If needed, can be built as part of a Device subsection of a Manufacturer section.PosDup sectionProvides a method for identifying devices that may appear to be separate devices but are in fact the same device.If needed, can be built as part of a Device subsection of a Manufacturer section. Getting Started Using Infedit This topic illustrates the use of Infedit by starting with a list of Windows 95 installation and operating requirements for a fictitious hardware device (a SCSI adapter) and then showing how to use Infedit to build an INF file that meets these requirements. A listing of the completed INF file produced by Infedit is shown at the end of the section. After the Windows 95 DDK is installed, you can run Infedit from the Windows 95 Run dialog. Infedit is installed in the directory %DDKROOT%\BIN. To build a new INF file, select the New option from the File menu. The opening screen is displayed, which shows all the types of INF file sections you can build with Infedit. To get started on a new INF file, build the Manufacturer section first. Once you have put a Company Name item into the Manufacturer section, you can save the INF file and reopen it at any time to build the other sections. This chapter shows how to build an INF file for a SCSI adapter made by Corporation X. To put a Company Name item with the value Corporation X into the Manufacturer section, do the following with Infedit: 1. Right-click on the Manufacturer folder to display a popup menu. 2. From the popup menu, select the New Manufacturer option. A New Manufacturer sub folder is displayed. 3. Double-click on the new sub folder to get an opportunity to edit the Company Name item. On the right side of the screen, in the Item column of the edit area, the item name Company Name appears. 4. Double-click on the item Company Name and an Edit String dialog will be displayed that enables you to enter Corporation X as the value for the New Company item. Once you have put the Company Name item into the Manufacturer section, you can save and name the INF file using the Save As option from the File menu. The example INF file discussed in this chapter is named XSCSI.INF. The operations shown above that are used to navigate the Infedit interface in the process of putting the Company Name item into the New Manufacturer subfolder are used to put other types of items into other types of sub folders. Each subfolder represents an INF file section. The general operations used repeatedly in the Infedit user interface are: SYMBOL 183 \f "Symbol" Right-click on a folder or sub folder to display a popup menu that enables you to operate on the folder or sub folder. SYMBOL 183 \f "Symbol" Double-click on a user interface object to get a chance to edit it. The Infedit interface also presents a screen area dedicated to editing item values. This screen area is organized as two columns. The left-most column lists the names of all the items that can be in the section you are editing. The right-most column lists the current value of each item. Double-click on an item name to display the edit dialog you need to change the current value of the item. Note that once you have built the Manufacturer section of the INF file, you can build the rest of the sections in almost any sequence. You do not have to completely finish building a section before you start on another one, either. The following example will show the INF file sections being built in a particular sequence, but that is not the only sequence that can be used. Sample INF File Requirements When you build the first version of an INF file for your device, the operating characteristics of the device are well known -- even if you are building the INF file to test a hardware prototype on a Windows 95 machine. For example. consider a fictitious piece of hardware, a SCSI Host Adapter which is built by Corporation X. The name of the device is the CX2590 SCSI Adapter and its Windows 95 device ID is *CX2590. There are no compatible device IDs for this device. All this information can be put into the INF file in a Manufacturer section. The board has the following resource requirements: SYMBOL 183 \f "Symbol" Four contiguous IO ports based at 180H, 190H, 1A0h or 1B0h. SYMBOL 183 \f "Symbol" One exclusive IRQ chosen from 4,5,9,10,11. SYMBOL 183 \f "Symbol" One DMA channel, although the board will work without one. All of this resource requirements information can be put into the INF file in one or more Log Config-type sections. Use the Infedit Log Config Sections folder to do this. Corporation X is providing two files to support the device on one installation diskette: SYMBOL 183 \f "Symbol" A SCSI miniport driver with the filename CX2590.MPD, which must be copied from a device installation diskette to the directory %WINROOT%\SYSTEM\IOSUBSYS on the Windows 95 computer. SYMBOL 183 \f "Symbol" A utility program with the filename SRSUTIL.EXE, which must be copied from a device installation diskette to the BIN sub directory of the Windows 95 computer boot directory. The BIN sub directory of the computer boot directory is the default subdirectory for this installation process. SYMBOL 183 \f "Symbol" Both CX2590.MPD and SRSUTIL.EXE fit on one installation diskette. The descriptive name of a device installation diskette is CX2590 Windows 95 Installation Disk (this is the name of the installation diskette that is displayed to the user during the device installation procedure). The installation diskette label is Instd1 and there is no serial number on the installation diskette. All of the filename information and the source and destination information for copying the files can put into the INF file in one or more CopyFiles-type sections. Use the Infedit CopyFiles folder to do this. Two entries must be made under the HKR key of the registry: SYMBOL 183 \f "Symbol" An entry that specifies the device loader the CX2590; for a block device like a SCSI adapter the device loader is the I/O Supervisor (IOS). SYMBOL 183 \f "Symbol" An entry that specifies the filename of the minport driver for the device; in this example, that is the file named CX2590.MPD. The information that causes these two registry entries to be made at installation time can all be put into the INF file in one or more Add Registry-type sections. Use the Infedit Add Registry Sections folder to do this. Building the Sample INF File This topic walks through the process of using Infedit to build each of the INF file sections necessary to satisfy the requirements listed in Sample INF File Requirements earlier in this chapter. The procedures used to build several types of INF file sections with Infedit are shown. SYMBOL 183 \f "Symbol" To see an example of building a Manufacturer section, see Completing the Manufacturer Section later in this chapter. SYMBOL 183 \f "Symbol" To see an example of building a Logical Configuration section, which specifies the resource requirements of a device such as IRQs and I/O addresses, see Specifying Resource Requirements later in this chapter. SYMBOL 183 \f "Symbol" To see an example of building an Add Registry section, see Adding Registry Entries later in this chapter. SYMBOL 183 \f "Symbol" To see an example of building a Copy Files section, see Copying Files later in this chapter. SYMBOL 183 \f "Symbol" To see an example of editing an INF file header section, see Completing the INF File Header Section later in this chapter. SYMBOL 183 \f "Symbol" To see information about adding strings to a Strings section, see Adding Strings to the Strings Section later in this chapter. Completing the Manufacturer Section The first step in creating a Manufacturer section, creating a Company Name item, is described in the topic Getting Started Using Infedit earlier in this chapter. Besides the company name of the device manufacturer, device description information goes into the Manufacturer section. To add these device description items: 1. Right-click on the company name sub folder (labeled Corporation X in this example) and select the New Device option from the popup menu. This creates a device description sub folder. 2. Double-click the device description sub folder to display the items you can edit in this sub folder. You can edit up to six items in the device description sub folder. As stated in the topic Sample INF File Requirements earlier in this chapter, the descriptive name of the device is the CX2590 SCSI Adapter, the Windows 95 device ID (also called the hardware ID) is *CX2590, and there are no compatible device IDs. To put these values into the appropriate INF file items, double-click in turn on the Item names Device Description, Hardware ID, and Compat ID(s) in the edit area of the Infedit screen. Double-clicking on each item name displays the String Edit dialogs that enable you to put these values into the INF file. You can also name the INF file install section for the CX2590 at this time, even though you havent built the install section yet. Each install section in an INF file contains the script for copying files, adding registry entries, etc. during installation of a device. The name of the install section, which you have an opportunity to enter now, is up to you but a self-documenting name has the form device.Install. For example, in this case, name the install section CX2590.Install. When you enter an install section name value in the device description subfolder, Infedit automatically creates a subfolder under the Install Sections folder named, for example in this case, CX2590.Install (the name you entered). After this is done, the edit display will look like this: The Exclude from Select and Copy Files Only items are not used in this example. For more information about these items, see the Reference section Manufacturer topic, where Control Flags are discussed. Note that there can be more than one device description sub folder in a Manufacturer folder, even though this sample INF file has only one. The only constraint on the device description sub folders you use in an INF file is that all the devices described must be of the same device class. For example, in this sample INF file, there could be device description folders for other SCSI Adapter devices. Specifying Resource Requirements The resource requirements and constraints of the CX2590 are listed below: SYMBOL 183 \f "Symbol" Four contiguous IO ports based at 180H, 190H, 1A0h or 1B0h. SYMBOL 183 \f "Symbol" One exclusive IRQ chosen from 4,5,9,10,11. SYMBOL 183 \f "Symbol" One DMA channel, although the board will work without one. Use Infedit to put this logical configuration information into the Log Config Sections folder: 1. Right-click on the Log Config Sections folder and then select the New Logical Configuration Section option from the popup menu to create a new subfolder under the Log Config folder. 2. Double-click on the new subfolder to display the items you can edit. You are given the opportunity to edit two items: Section Name and Priority. SYMBOL 183 \f "Symbol" Double-click on the item name Section Name in the edit area to display an Edit String dialog. You can name the new logical configuration section anything; for this example the section name CX2590_DMA was entered into the dialog box. SYMBOL 183 \f "Symbol" Since it is normal to run the CX2590 with a DMA channel (although it will run without one), the Priority item should be set to NORMAL. This may already be set as the default Priority value. If not, double-click on the Priority label of the Item column in the Infedit interface edit area and use the dropdown list in the dialog box. For more information about the meaning of each of the priority options in the dropdown list, see the Log Config Sections topic in the Reference section. To enter the I/O port, IRQ, and DMA channel requirements, right-click on the subfolder you just named (in this example, that subfolder is named CX2590_DMA). At this point, the relevant part of the Infedit screen will look like this, with the popup menu: Adding the I/O Description Item The I/O port requirements for the CX2590 are four contiguous I/O ports based at I/O addresses 180H, 190H, 1A0h and 1B0h. To add the I/O port requirements for the CX2590: 1. Select the Add I/O Descriptor option from the popup menu to add an I/O descriptor subfolder. 2. If you double-click on the new subfolder in order to edit items, the edit area on the right side of the Infedit screen does not give you an opportunity to edit any items. This indicates that there is another popup menu available, so right-click in the new subfolder to display the popup. The popup menu gives you two options for edit displays: Add Type 1 I/O Range and Add Type 2 I/O Range. These are just two different ways of entering the same information, but for some I/O port requirements (such as the ones used in this example), the Type 2 form is quicker to use. See the Log Config Sections topic in References for details about the two different ways of expressing I/O port requirements. To continue with the example, after you select the Add Type 2 I/O Range option an Input/Output Range 0 subfolder is created. Double-click on the new subfolder to display the items you can edit in the edit area. Since the I/O port requirements for the CX2590 are four contiguous I/O ports based at I/O addresses 180H, 190H, 1A0h and 1B0h you can double-click on each of the items in the edit display, except Alias Offset and Attributes, and use the Edit String dialogs to produce an edit display that looks like the screen shown below. When you enter a value into the Edit String dialog, you do not need to enter the entire hexadecimal expression. For example, when you enter the value for the Size item, just enter 4 instead of 0x0004. Note that when you double-click the Attributes item, no Edit String dialog box is displayed. That is because the Attributes item is reserved for future use. Adding the IRQ Description Item The IRQ requirements for the CX2590 are one exclusive IRQ chosen from IRQ 4, 5, 9, 10, or 11. To add the IRQ requirements to the XSCSI.INF file for the CX2590: 1. Right-click on the CX2590_DMA subfolder under the Log Config Sections folder and select the Add IRQ Descriptor option. This will create an IRQ Descriptor subfolder. 2. Double-click on the new subfolder. An array of IRQs and Yes/No values appears in the edit area. Double-click on individual IRQ item names to set IRQs 4, 5, 9, 10, and 11 to Yes and all other IRQs to No. When you are done, the IRQ array in the edit area will look like this: Item Value IRQ Sharable No IRQ 0 No IRQ 1 No IRQ 2 No IRQ 3 No IRQ 4 Yes IRQ 5 Yes IRQ 6 No IRQ 7 No IRQ 8 No IRQ 9 Yes IRQ 10 Yes IRQ 11 Yes IRQ 12 No IRQ 13 No IRQ 14 No IRQ 15 No Adding the DMA Description Item The CX2590 requires one DMA channel for NORMAL operation. The CX2590 can use either DMA channel 0, 1, 2, or 3 and the DMA bus width is eight bits. To add the DMA requirements to the XSCSI.INF file for the CX2590: 1. Right-click on the CX2590_DMA subfolder under the Log Config Sections folder and select the Add DMA Descriptor option. This will create an DMA Descriptor subfolder. 2. Double-click on the new subfolder. An array of DMAs and Yes/No values appears in the edit area. Double-click on individual DMA item names to set DMA channels 0, 1, 2, and 3 to Yes and all other DMAs to No. In this example, there is no need to change the default DMA bus width of 8 bits. When you are done, the DMA array will look like this: Item Value DMA Bus Width 8 bits DMA 0 Yes DMA 1 Yes DMA 2 Yes DMA 3 Yes DMA 4 No DMA 5 No DMA 6 No DMA 7 No Note that given the requirements in this example, adding this DMA descriptor to the INF file does not satisfy all the DMA requirements for this example. The DMA requirements are: One DMA channel, although the board will work without one. In order to meet the requirement the board will work without one, you will have to add another logical configuration section to the INF file, with priority set to SUBOPTIMAL and with no DMA item. The method for doing this is shown in the next section. Adding a Suboptimal Logical Configuration Section To add a second logical configuration section to the INF file XSCSI.INF 1. Right-click on the Log Config Sections folder and select the New Logical Configuration Section option from the popup menu. A new subfolder will be displayed with no section name (the displayed section name will be
. 2. Double-click on the new folder to display the items you can edit. You are given the opportunity to edit two items: Section Name and Priority. SYMBOL 183 \f "Symbol" Double-click on the item name Section Name in the edit area to display an Edit String dialog. You can name the new logical configuration section anything; for this example the self-documenting section name CX2590_NoDMA was entered in the dialog box. SYMBOL 183 \f "Symbol" Since the board will run without a DMA channel, but sub optimally relative to when it runs with a DMA channel, set the Priority item value to SUBOPTIMAL. Double-click on the Priority item label in the edit area and select the value SUBOPTIMAL from the dropdown list in the Edit List dialog box. To enter the IO port and IRQ requirements, right-click on the subfolder you just named and follow the same procedures as shown in the earlier topics Adding the I/O Description Item and Adding the IRQ Description Item. Note that you will not add a DMA description item to this logical configuration section because it describes the device configuration where the device is running sub optimally, without a DMA channel. Adding the Logical Configuration Sections to the Install Section For the logical configuration sections you have built (named CX2590_DMA and CX2590_NoDMA) to be recognized by the operating system installer, the names of the two sections have to be added to the Install section. To do this 1. Double-click on the Install sections subfolder named CX2590.Install. A list of all the types of sections that can be referred to in an Install section will be displayed in the edit area on the right side of the screen. 2. Since you want to add logical configuration names to the install section, double-click the Log Config item in the edit box list. The Edit Section List dialog is displayed with the a list section names displayed in the Available Sections list box on the left-hand side of the dialog. 3. Highlight the names of both logical configuration sections, CX2590_DMA and CX2590_NoDMA, and select the Add> button to move both section names to the Included Sections list on the right of the dialog. Then click the OK button. At this point, the edit display looks like this: This display reflects that the two logical configuration sections have been put into the INF file and added to the install section script. Other types of sections have to be built to complete the INF file requirements stated in Sample INF File Requirements. Entries have to added to the registry and device driver files have to be copied from a device installation diskette to the appropriate sub directories on the hard drive. Adding Registry Entries For a block device such as the CX2590 SCSI adapter, SYMBOL 183 \f "Symbol" The Windows I/O Supervisor (IOS) must be specified as the device loader in a registry entry. SYMBOL 183 \f "Symbol" A registry entry must be made that holds the name of the block device miniport driver, which in this example is named CX2590.MCD. Creating the AddReg-type Section for the DevLoader To put a new AddRef-type section into the INF file that makes one of these registry entries at the time the CX2590 adapter is installed, you can use Infedit in the following way: 1. To add an AddReg-type subfolder to the INF file, right-click on the AddRegistry Sections folder and then select the New Add Registry Section option from the popup menu. In the Infedit user interface, this creates a new unnamed subfolder under the Add Registry folder. 2. To name the new subfolder (section), double-click on the new subfolder and then double-click on the Section Name label in the Item column of the edit area. Use the Edit String dialog to enter the name. You can use any name; in this example, StdIOS_RegEntries is the name used. 3. To add an item to the new AddReg-type section, right-click on the folder that represents the section (the folder named StdIOS_RegEntries). Then select the Add Section Value option from the popup menu. This creates a new subfolder, named Item 0, to hold the new item. 4. To add the item to the section, double-click on the Item 0 folder. The edit region of the Infedit interface displays the items that can be put in an item that goes into an AddReg-type INF file section. 5. Double-click on the Value Name in the Item column of the display and use the Edit String dialog to enter the string DevLoader. Then double-click on Value in the Item column and use the Edit String dialog to enter the string IOS. When you are done, the edit region display will look like this: Creating the AddReg-type Section for the Miniport Driver You can use the same method to add an AddReg-type section to the INF file that creates a registry entry for the Miniport driver at installation time. In this example, that section is named CX2590_RegEntries, but can be named anything as long as it is a unique section name in the INF file. The filename of the miniport driver is CX2590.MPD. The AddReg-type section items that must be put into an INF file vary between classes of devices. One way to find out what entries are required is to look at the AddReg-type sections in the INF files for your class of device that are in the %WINROOT%\INF directory after Windows 95 is installed on your machine. Adding References to the AddReg-Type Sections to the Install Section For the AddReg-type sections you have built (named StdIOS_RegEntries and CX2590_RegEntries) to be recognized by the operating system installer, the names of the two sections have to be added to the Install section. To do this 1. Double-click on the Install sections subfolder named CX2590.Install. A list of all the types of sections that can be referred to in an Install section will be displayed in the edit area on the right side of the screen. 2. Since you want to add the names of AddReg-type sections to the Install section of the INF file, double-click the AddReg item in the edit box list. Use the Edit Section List dialog to move the two AddReg-type section names (StdIOS_RegEntries and CX2590_RegEntries in this example) from the Available Sections list box to the Included Sections list box and then click OK. At this point, the edit display looks like this: This display reflects that the two AddReg-type sections and two logical configuration sections have been put into the INF file and the names of all four sections have been added to the Install section script. Sections that enable files to be copied from an installation diskette to specific hard disk directories have to added to the INF file also. Copying Files One or more sections must be put into the INF file that causes the files on an installation diskette to be copied to specific sub directories on the hard disk, and these section names must be listed in the CX2590.Install section in the INF file. Corporation X is providing two files to support the device on one installation diskette: SYMBOL 183 \f "Symbol" A SCSI miniport driver with the filename CX2590.MPD, which must be copied from a device installation diskette to the directory %WINROOT%\SYSTEM\IOSUBSYS on the Windows 95 computer. SYMBOL 183 \f "Symbol" A utility program with the filename SRSUTIL.EXE, which must be copied from a device installation diskette to the BIN sub directory of the Windows 95 computer boot directory. The BIN subdirectory of the computer boot directory is the default destination directory for this installation. SYMBOL 183 \f "Symbol" Both CX2590.MPD and SRSUTIL.EXE fit on one installation diskette. The descriptive name of a device installation diskette is CX2590 Windows 95 Installation Disk (this is the name of the installation diskette that is displayed to the user during the device installation procedure). The installation diskette label is Instd1 and there is no serial number on the installation diskette. The following sections walk through the procedure of using Infedit to add the required sections and Install section items to the INF file. Note that in this example case, no files have to be renamed when they are copied from the diskette to the hard disk; if renaming was required, a Rename Files-type section would have to be put into the INF file. Also note that for this example CX2590 installation, no preexisting files on the hard drive, such as obsolete drivers, have to be deleted as part of the overall file copying strategy; if there were such requirements, a DelFiles-type section would have to be put in the INF file. Specifying the Default Destination Directory The default destination directory for an installation is specified in the INF file header section. (The header section of an INF file is also called the Version section.) To use Infedit to specify the default destination directory: 1. Double-click on the root folder of the Infedit display (the folder at the top of the tree in the Infedit user interface, which is labeled C:\sampinf\xscsi.inf in this example). 2. Double-click on the label Default Destination Directory in the Item column of the edit area of the Infedit user interface. This causes the Edit Destination dialog to be displayed. 3. In the Edit Destination dialog, select LDID_BOOT from the LDID dropdown list, and then enter BIN in the Subdirectory Relative to LDID Path edit box. 4. Select the OK button on the dialog box and the path C:\BIN appears in the Default Destination Directory value column in the edit area (if, as in this example, the computer boot directory is C:\). Specifying the Files to Copy and Their Destination To put the names of the two files to be copied and their directory destinations on the hard disk of the computer, you can use the Infedit interface in the following way: 1. To create a CopyFiles-type section in the INF file, right-click on the CopyFiles Sections folder and select the New Copy Files Section option. This creates a new subfolder labelled NewFileSection that represents the new CopyFiles-type section in the INF file. 2. To enter the name of the new CopyFiles-type section and the destination directory for the files listed in that section, double-click on the new subfolder. 3. To change the section name, double-click on Section Name in the Item column and use the Edit String dialog to enter a section name. You can use any section name, as long as it is a unique section name in the INF file. For this example, the section name MoveMiniport is used because this is the section that will contain the destination directory for the file CX2590.MPD. 4. To change the destination directory to C:\WINDOWS\SYSTEM\IOSUBSYS, double-click on Destination Directory in the Item column of the edit area and use the Edit Destination Directory dialog. From the LDID list box, select LDID_IOS. Notice that at the bottom of the dialog, you can see the complete path that corresponds to the LDID value you selected and it is C:\WINDOWS\SYSTEM\IOSUBSYS. Note that you may need to blank out the Subdirectory Relative to LDID Path edit box. For more information about LDID values, see the topic DestinationDirs Section topic in Reference. Now you need to specify all the files on the installation diskette(s) that will be copied into the LDID_IOS sub directory. In this example, there is only one: CX2590.MCD. To use the Infedit interface to add this filename as an item to the MoveMiniport section: 1. Right-click on the subfolder named MoveMiniport and select Add File Name from the popup menu. This will cause a File Name item to be added to the edit area: 2. Double-click on File Name in the Item column of the edit area and use the Edit String dialog to enter the filename CX2590.MCD. You can repeat steps 1 and 2 as many times as necessary to list all the files that are to be copied into the sub directory whose complete path is the value of the Destination Directory item in this section. If you make a mistake with a File Name item, right-click on File Name for the mistaken item and select Delete from the popup menu. To put the file copy information into the INF file for the other file on the installation diskette, the file named SRSUTIL.EXE, repeat the process you used for CX2590.MPD. Start by right-clicking the CopyFiles Sections folder and selecting the New Copy Files Section item from the popup menu. Note that the name of the default destination directory path which you set earlier in the INF file header section (C:\BIN in this example) is displayed in the edit area. Since that is the destination directory for SRSUTIL.EXE, it is not necessary to use the Edit Destination dialog in this case. You can also accept the default value for the Name item, which is the value NewFileSection, as long as it is a unique section name in the INF file. Specifying the Source Diskette(s) CX2590.MPD and SRSUTIL.EXE are on an installation diskette. with the descriptive name of CX2590 Windows 95 Installation Disk. The installation diskette label is Instd1 and there is no serial number on the installation diskette. To use Infedit to add a Disk Names-type section to the INF file, you can: 1. Right-click on the Disk Names Section folder and select the Add Diskname option. This creates a new subfolder labeled with the logical disk number, 1. 2. To add items to the new Disk Names-type section, double-click on the new subfolder. The items that can be put into a Disk Names-type section are displayed in the edit area of the Infedit screen. 3. To enter the descriptive name of the installation diskette, double-click on the Disk Description label in the Item column of the edit area and use the Edit String dialog to enter the string CX2590 Windows 95 Installation Disk. 4. To enter the label of the installation diskette, double-click on the Disk Label label in the Item column of the edit area and use the Edit String dialog to enter the string Instd1. 5. To add the filenames of all the files on the installation diskette to the INF file, double-click on the File Name(s) label in the Items column of the edit area and use the Edit Disk File List dialog. Move the two filenames, CX2590.MPD and SRSUTIL.EXE, from the Available Files list to the Included Files list. When you are done with these steps, the edit area looks like this: At this point, all the sections necessary to copy the files from the installation diskette to the appropriate sub directories on the hard disk have been added to the INF file, except for adding references in the install section to the two new CopyFiles-type sections that have just been built. Adding References to the CopyFiles-Type Sections to the Install Section For the CopyFiles-type sections you have built (named MoveMiniPort and NewFileSection) to be recognized by the operating system installer, the names of the two sections have to be added to the Install section. 1. Double-click on the Install sections subfolder named CX2590.Install. A list of all the types of sections that can be referred to in an Install section will be displayed in the edit area on the right side of the screen. 2. Since you want to add the names of CopyFiles-type sections to the Install section of the INF file, double-click the Copy File Sections item in the edit area. Then use the Edit Section List dialog to move the two CopyFiles-type section names from the Available sections list box to the Included Sections list box and then click OK. At this point, the edit display looks like this: This display reflects that the two CopyFiles-type sections have been put into the INF file and the names of the two sections have been added to the Install section. At this point, the Install section is complete. It refers to two Copy File Sections names, two AddReg section names, and two LogConfig section names. Completing the INF File Header Section Every INF file has a header. Infedit creates a default header when you open a new INF file. To look at the header on the example INF file, double-click on the top-most folder in the Infedit interface, the folder just to the left of the INF file name (which in the example case is XSCSI.INF). To complete this header, you must supply a value for the Class item. In the example case of the CX2590, the class name is the string SCSIAdapter. For a list of all the device classes recognized by Windows 95, see the topic Introducing the INF Editor earlier in this chapter. If your device is not in a class recognized by Windows 95, then in addition to setting the Class item value here in the INF file header, you will also have to put a Class Install section into your INF file. Use the Class Install folder in the Infedit interface to do that. See the Class Install Section topic in the Reference section for information about the items that go into a Class Install section. You may also want to supply a value for the Provider item in the header. This is the name of the organization that builds and tests the INF file. For example, in this case it might be Corporation X. You also must ensure that the INF file signature value is correct. It must be $CHICAGO$. If the Signature item has any value other than $CHICAGO$, change it. The code that checks this signature in the installer uses a case-insensitive string comparison on the Signature item value, so you can use $Chicago$, for example. A layout file is an alternative way to specify the file and directory structure on the installation media. In the example case, where there are only two files on one installation diskette and they are both in the root directory, there is no need to use a layout file. Note that the Default Destination Directory item has the value that was put into the INF file header section earlier (in this example, the value is C:\BIN). Adding Strings to the Strings Section The values of all the items in the Strings section of an INF file are strings that appear in the user interface when the device is installed. Having all these strings in one section of the INF file makes it easier to translate them for international markets. Infedit automatically puts a Strings section in any INF file it is building and adds items to it as needed. For example, when you add the device description item to the Manufacturer section, Infedit automatically puts that string, CX2590 SCSI Adapter in the sample INF file, into the Strings section. You never directly edit the strings put into the Strings section in this way by Infedit. To add strings to the Strings section in addition to the strings Infedit automatically places there, right-click on the Strings folder and select the Add String Value option from the popup menu. In the edit area, two items are displayed: String Name and Replacement Value. For the String Name value, use a name of a form other than %Stringn% where n is an integer value. The Replacement Value value is the actual string that will be displayed at the user interface when the INF file is used. In the example case of XSCSI.INF, there are no strings to add to the Strings section. In other INF files, it may be necessary for you to add strings to the Strings section. In particular, after you have built an AddReg. Ini File to Registry, Update Ini File, or Update Ini Fields type of section, ask yourself if any of the string values in these types of sections will be displayed at the user interface. If you identify such strings, you are responsible for making an entry in the Strings section for each one. It is important to note that you will have to change the item value in the other section (such as the AddReg type section) the String Name value that you use in the Strings section (String Name values have the form %string-name%). For a look at the relationship between string name values in the Strings section and the other sections of an INF file, see the topic Sample INF File Listing later in this chapter. Sample INF File Listing The INF file that is built when you use Infedit in the way described above is listed below. [Version] Signature="$CHICAGO$" Class=SCSIAdapter Provider=%String0% [DestinationDirs] DefaultDestDir=30,BIN MoveMiniPort=12 [Manufacturer] %String1%=SECTION_0 [SECTION_0] %String2% = CX2590.Install,*CX2590 [CX2590.Install] Copyfiles=MoveMiniPort,NewFileSection AddReg=StdIOS_RegEntries,CX2590_RegEntries LogConfig=CX2590_DMA,CX2590_NoDMA [MoveMiniPort] CX2590.MPD [NewFileSection] srsutil.exe [StdIOS_RegEntries] HKR,,DevLoader,0,IOS [CX2590_RegEntries] HKR,,Miniport,0,CX2590.MPD [CX2590_DMA] ConfigPriority=NORMAL IOConfig=4@180-1B3%fff0(3::) IRQConfig=4,5,9,10,11 DMAConfig=0,1,2,3 [CX2590_NoDMA] ConfigPriority = SUBOPTIMAL IOConfig = 4@180-1B3%fff0(3::) IRQConfig = 4,5,9,10,11 [ControlFlags] [SourceDisksNames] 1=CX2590 Windows 95 Installation disk,Instd1,0000-0000 [SourceDiskSFiles] CX2590.MPD=1 srsutil.exe=1 [Strings] String0="Corporation X" String1="Corporation X" String2="CX2590 SCSI Adapter" Special Uses of INF Files There are several device installation requirements that can be met by INF files, but which are not part of the installation requirements for the sample INF file, XSCSI.INF. These special requirements of INF files are: SYMBOL 183 \f "Symbol" Installing a multifunction device. SYMBOL 183 \f "Symbol" Installing a property provider. SYMBOL 183 \f "Symbol" Overriding PCMCIA tuples on PC card devices. MultiFunction Card INF Description A multifunction card is any card which is enumerated as a single device but is actually more than one device on a single card. Typical would be a sound card which is a CD-ROM interface and a sound controller on the same card. During installation, the device installer will execute both the install section for this device and the InstallSection.HW as described previously. The following special HW section items have been created for multifunction devices: SYMBOL 183 \f "Symbol" HardwareID List SYMBOL 183 \f "Symbol" Resource Map A HardwareID List item is a text item that is added with an AddReg-type section. Hardware ID items cause the Configuration Manager to create devnodes for every HardwareID item used. The Configuration Manager enumerates these devices. An example HardwareID item looks like this: HKR,Child0000,HardwareID,,MF\ID A Resource Map item is used in an INF file when installing an EISA multifunction card. Resources are not really assigned to the parent but rather to the independent functions. The EISA enumerator, however, reports only the parent device and reports all resources as belonging to the common parent. A Resource Map item tells the Configuration Manager how to divide the parent resource between the children. The resource map is a binary format record added using an AddReg-type entry, where each byte represents the ordinal of the EISA resource record belonging to the child. This is not a bit map, it is a list of ordinals. There is a limit of 256 EISA ordinal values. An example Resource Map item looks like this: HKR,,ResourceMap,,1,01,04,26 Installing a Property Provider Class property providers can be registered in the class install section. A property provider entry point specified the class section of the registry will be called any time properties are displayed for a device of the appropriate class. A property provider can be registered by using the following addreg entry in the class AddReg section. hkr,,EnumPropPages,,"DLL,Entrypoint" Similarly a property providers can be registered for a specific device by using the following addreg entry in the device install section. Doing this makes HKR relative to the driver section and thus is invoked only for the specific device. hkr,,EnumPropPages,,"DLL,Entrypoint" PCMCIA Configuration Tuple Overrides On occasion, the tuples found on a PCMCIA card are not correct. When this happens, an override can be specified in the INF and will be installed into the registry during device installation. Overrides are Logical Config sections in binary format specified using an AddReg entry. HKR,Override,0000,1, Reference This section describes the syntax and meaning of the items used in each of the various types of INF file sections. Add Registry Sections [add-registry-section] reg-root-string, [subkey], [value-name], [flag], [value] [reg-root-string, [subkey], [value-name], [flag], [value]] . . . Adds subkeys or value names to the registry, optionally setting the value. The add-registry-section name must appear in an AddReg-type item in an Install section. reg-root-string Registry root name. Can be one of these value: HKCRSame as HKEY_CLASSES_ROOTHKCUSame as HKEY_CURRENT_USERHKLMSame as HKEY_LOCAL_MACHINEHKUSame as HKEY_USERS.HKRMeans relative from the Key passed into GenInstallEx subkey Optional. Identifies the subkey to set. Has the form key1\key2\key3.... This parameter can be expressed as a replaceable string. For example, you could use %Subkey1% where the string to replace %Subkey1% is defined in the Strings section of the INF file. value-name Optional. Identifies the value name for the subkey. For string type, if the value-name parameter is left empty, the value of the subkey specified in the subkey parameter is set to a NULL string. Note that the value-name parameter can be expressed as a replaceable string. For example, you could use %Valname1% where the string to replace %Valname1% is defined in the Strings section of the INF file. flag Optional. Determines both the value type and whether the registry key is replaced if it already exists. The flag value is a bit map where: BitValueMeaning00(Default) Value is an ANSI string.01Value is a hexadecimal number.10(Default) Replace key if it exists.11Do not replace key if it exists. value Optional. Value to set. Can be either an ANSI string or a number in hexadecimal notation and Intel format. Any item containing a binary value can be extended beyond the 128-byte line maximum by using a backslash (\) character. A string key of the form %strkey% can also be given. The strkey must be defined in the Strings section of the INF file. To use a % character in the line, use %%. At least two fields are required, however one can be null thus at least one comma is required when using this form. The two items in the example AddReg-type section below, which is named MOD1, add two value names to the registry, DevLoader and Miniport, if not already present. It also sets the value of these names to IOS and CX2590.MCD. [MOD1] HKR,,DevLoader,,IOS HKR,,Miniport,,CX2590.MCD Class Install Section [ClassInstall] AddReg=Add-registry-section[,]... Copyfiles=file-list-section[,]... Delfiles=File-list section[,]... DelReg=Del-registry-section[,]... Renfiles=File-list-section>[,]... UpdateInis=Update-ini-section>[,]... UpdateIniFields=Update-inifields-Section[,]... Installs a new class for a device in the class section of the registry. Not all the item types shown in the syntax above are needed or required. Typically a ClassInstall section will use AddReg-type items to add a class description and a class icon to the registry. These will be visible in the Windows 95 user interface. In addition a class install section can specify a property provider and exert control over how the class is handled in the Windows 95 user interface. Every device installed in Windows 95 has a class associated with it even if the class is "UNKNOWN" and every class has a class installer associated with it. The installer processes the ClassInstall section if one of the devices defined in an INF file is about to be installed and the class is not built into Windows 95. Following is a list of the hardware class names that are built into Windows 95: CD-ROM Controllers Display Adapters Floppy disk controllers Hard disk controllers Keyboard Memory Technology Drivers (MTDs) Modem Mouse Multi-function adapters Network adapters Other devices PCMCIA sockets Ports (COM & LPT) Printer SCSI Controllers Sound, video and game controllers System devices The relative key is your class section. The Device Manager will create a class entry then you have a normal install section in here. This example creates the class Sample and registers the description, installer, and icon for the class: [ClassInstall] Addreg=SampleClassReg CopyFiles=@Sample.cpl [SampleClassReg] HKR,,,,%SampleClassDesc% HKR,,Installer,,Sample.cpl HKR,,Icon,HEX,00,00 [Strings] SampleClassDesc=Sample The following special controls over the class can be registered by adding one or more of the following items in the AddReg-type item referred to by the ClassInstall section: HKR,,NoUseClass,,1 ;Class will not be seen anywhere HKR,,NoInstallClass,,1 ;Class is not shown in New Device Wizard HKR,,NoDisplayClass,,1 ;Class will not be displayed by Device Manager HKR,,SilentInstall,,1 ;Class is installed without any user interaction CopyFiles Sections [CopyFiles-section-name] destination-file-name[, source-file-name][, temporary-file-name][,flag] [destination-file-name[, source-file-name][, temporary-file-name]][,flag] . . . Lists the names of files to be copied from a source disk to a destination directory. The source disk and destination directory associated with each file are specified in other sections of the INF file. The file-list-section name must appear in the CopyFiles item of an Install section. Note that you can specify the copying of a single file in the CopyFiles item of the Install section itself, without building a Copy Files section. To do this, use the special character @ to force a single file copy. An example of using the @ character in a CopyFiles-type item is in the Install section reference topic. Copying a single file in this way is somewhat limited because the source and destination filenames must be the same in this case and you cannot use a temporary file. destination-file-name Name of the destination file. If no source filename is given, this is also the name of the source file. source-file-name Name of the source file. If the source and destination filenames for the file copy operation are the same, this is not required. temporary-file-name Name of a temporary file for the file copy operation. The installer copies the source file but gives it the temporary file name. The next time the operating system starts, it renames the temporary file to the destination file name. This is useful for copying files to a destination which is currently open or in use by Windows. flag Optional parameter used to indicate a file that is critical to the installation process. For those files that the copy operation cannot be skipped during the installation process, set the flag parameter value to 2. This example copies three files: [CopyTheseFilesSec] file11 ; copies file11 file21, file22, file23 ; copies file22, temporarily naming it file23 file31, file32 ; copies file32 to file31 All the source filenames used in this example must be defined in a SourceDisksFiles section and the logical disk numbers that appear in the SourceDisksFiles section must have been defined in a SourceDisksNames section. As an alternative, you can use a LAYOUT.INF file to supply this information. Delete Registry Sections [del-registry-section] reg-root-string, subkey, [value-name] [reg-root-string, subkey, [value-name]] . . . Deletes a subkey or value name from the registry. The del-registry-section name must appear in an DelReg item in an Install section. reg-root-string Registry root name. Can be one of these values: HKCRSame as HKEY_CLASSES_ROOTHKCUSame as HKEY_CURRENT_USERHKLMSame as HKEY_LOCAL_MACHINEHKUSame as HKEY_USERS.HKRMeans relative from the Key passed into GenInstallEx subkey Identifies the subkey to delete. Has the form key1\key2\key3... This parameter can be expressed as a replaceable string. For example, you could use %Subkey1% where the string to replace %Subkey1% is defined in the Strings section of the INF file. value-name Optional. Identifies the value name for the subkey. Note that the value-name parameter can be expressed as a replaceable string. For example, you could use %Valname1% where the string to replace %Valname1% is defined in the Strings section of the INF file. This type of section can contain any number of items. Each item deletes one subkey or value name from the registry. DelFiles Sections [file-list-section] file-name[,,,flag] . . . A DelFiles section lists the names of files to be deleted. The file-list-section name must appear in the Delfiles item of an Install section. file-name Identifies a file to be deleted. flag Optional parameter used to force Windows 95 to delete the file named in the item if it is in use during the installation process. Set the flag parameter value to 1 to cause Windows 95 to queue the file deletion operation until the system has restarted. If a file marked with the flag=1 parameter setting cannot be deleted because it is in use, a system restart will occur after the device installation is complete. If you do not use the flag parameter value equal to 1 along with a file-name parameter, then if that file is in use when the DelFiles section is executed that file will not be deleted from the system. This example deletes three files: [DeleteOldFilesSec] file1 file2 file3 All the filenames used in this example must be defined in a SourceDisksFiles section and the logical disk numbers that appear in the SourceDisksFiles section must have been defined in a SourceDisksFiles section. DestinationDirs Section [DestinationDirs] file-list-section=ldid[, subdir ] . . . [DefaultDestDir=ldid[, subdir ]] The DestinationDirs section defines the destination directories for the operations specified in file-list sections, which are either CopyFiles, RenFiles, or DelFiles sections. Optionally, a default destination directory may be specified for any CopyFiles, RenFiles, or DelFiles sections in the INF file that are not explicitly named in the DestinationDirs section. file-list-section Name of a CopyFiles, RenFiles, or DelFiles section. This name must be referred to in a Copyfiles, RenFiles, or DelFiles item in an Install section. ldid A logical disk identifier (LDID). Can be one of these values: 00Null LDID. This LDID can be used to create a new LDID01Source Drive:\pathname02Temporary setup directory. This is valid only during setup03Uninstall directory04Backup directory10Windows directory11System directory12IOSubsys directory 13Command directory14Control Panel directory15Printer directory16Workgroup directory17INF Directory18Help directory19Administration20Fonts21Viewers22VMM3223Color directory25Shared directory26Winboot27Machine specific28Host Winboot30Root directory of the boot drive31Root directory for Host drive of a virtual boot drive33Old Windows directory if it exists34Old Dos directory if it exists subdir Name of the directory, within the directory named by ldid, to be the destination directory. The optional DefaultDestDir item provides a default destination for any CopyFiles items that use the direct copy (@filename) notation or any CopyFiles, RenFiles, or DelFiles sections not specified in the DestinationDirs section. If a DefaultDestDir is not used in a DestinationDirs section, then the default directory is set to LDID_WIN. This example sets the destination directory for the MoveMiniPort section to WINDOWS\IOSUBSYS and sets the default directory for other sections to be the BIN directory on the boot drive: [DestinationDirs] MoveMiniPort=12 ; Destination for MoveMiniPort Section is ; windows\iosubsys DefaultDestDirs=30,bin ; Direct copies go to Boot:\bin Disk Names Section For information about this type of section, see the SourceDisksNames Section and SourceDisksFiles Section topics. HW Section [InstallSection.HW] The HW section is a special case of an Install section. It is the only type of section that enables entries to be made to the Hardware branch of the registry. The only types of items that can appear in a HW section are AddReg and DelReg items. Using the HKR designation in the AddReg and DelReg items adds and deletes registry entries directly into the registry hardware branch. This is useful for multifunction devices. Ini File to Registry Sections [ini-to-registry-section] ini-file, ini-section, [ini-key], reg-root-string, subkey[,flags] . . . Moves lines or sections from an INI file to the registry, creating or replacing a registry entry under the given key in the registry. The section name ini-to-registry-section must appear in an Ini2Reg item in an Install section of the INF file. ini-file Name of the INI file containing the key to copy. For more information about specifying the INI filename, see the comments in the Reference topic about the Update Ini File Section. ini-section Name of the section in the INI file containing the key to copy. ini-key Name of the key in the INI file to copy to the registry. If ini-key is empty the whole section is transferred to the specified registry key. reg-root-string Registry root name. Can be one of these values: HKCRSame as HKEY_CLASSES_ROOTHKCUSame as HKEY_CURRENT_USERHKLMSame as HKEY_LOCAL_MACHINEHKUSame as HKEY_USERS.HKRMeans relative from the Key passed into GenInstallEx subkey Identifies the subkey to receive the value. Has the form key1\key2\key3... flags Indicates whether to delete the INI key after transfer to the registry and whether to overwrite the value in the registry if the registry key already exists. Can be one of these values: BitValueMeaning00(Default) Do not delete the INI entry from the INI file after moving the information in the entry to the registry.01Delete the INI entry from the INI file after moving the information in the entry to the registry.10(Default) If the registry subkey already exists, do not replace its current value.11If the registry subkey already exists, replace its current value with the value from the INI file entry. For example, suppose the following entry exists in the WIN.INI file: [Windows] CursorBlinkRate=15 If a CursorBlinkRate subkey does not exist under the Control Panel\Desktop, then the following item in an Ini File to Registry section creates the subkey, sets the value of the subkey to 15, and leaves the original line in WIN.INI unchanged: win.ini,Windows,CursorBlinkRate,HKCU,"Control Panel\Desktop" If the subkey already exists, the INF file item sets the value of the subkey to 15, and leaves the original line in WIN.INI unchanged. Install Sections [install-section-name] LogConfig = log-config-section-name[, log-config-section-name]... Copyfiles=file-list-section[,]... Renfiles=file-list-section[,file-list-section]... Delfiles=file-list-section[,file-list-section]... UpdateInis=update-ini-section[,update-ini-section]... UpdateIniFields=update-inifields-section[,update-inifields-section]... AddReg=add-registry-section[,add-registry-section]... DelReg=del-registry-section[,del-registry-section]... Ini2Reg=ini-to-registry-section[,ini-to-registry-section]... UpdateCfgSys=update-config-section UpdateAutoBat=update-autoexec-section Reboot | Restart Identifies the additional sections in the INF file that contain descriptions of the device and instructions for installing files and information needed by the device driver(s). The name of the section, install-section-name, must be defined in a Device section that is associated with a Manufacturer section. Not all the types of items shown in the syntax above are needed or required in an Install section. If an item type is used, it must specify the name of a section in the INF file. (An exception to this is the CopyFiles item, which may use the @ character along with a filename to copy a single file without specifying a section name.) The section name must consist of printable characters. Only one of each type of item can be used in any one Install section. More than one section name can be listed in an item, but each additional name must be preceded with a comma. The Reboot or Restart items can be added to an Install section to force the system to either restart or to reboot the machine after carrying out the Install section script. This example shows a typical Install section. It contains a LogConfig item that identifies two logical configuration sections for this device. It also contains Copyfiles and AddReg items that identify the sections containing information about which files to install. [SuperSCSI] ; SCSI Are Us Model 01 - SuperSCSI+ Log_Config = With_Dma, WithoutDMA Copyfiles=MoveMiniPort, @SRSutil.exe AddReg=MOD1 The CopyFiles item provides a special notation which will allow a single file to be copied directly from the copy line. An individual file can be copied by prefixing the file name with an @ symbol. The destination for any file copied using this notation will be the DefaultDestDir as defined in the DestinationDirs section. The following example shows how to copy individual files: CopyFiles=FileSection1,@myfile.txt,@anotherfile.txt,LastSectionName Log Config Sections [log-config-section-name] ConfigPriority = priority-value [DMAConfig = dma-list] [IOConfig = io-range-list] [IRQConfig = irq-list] [MemConfig = mem-range-list] A Log Config section defines device configuration details, such as interrupt request lines, memory ranges, I/O ports, and DMA channels. The name of the section, log-config-section-name, must be used in the LogConfig item in an Install section of the INF file. Not all types of items shown in the syntax above are needed or required in a Log Config section. The syntax and meaning of each of the item types that can be used in a Log Config section are given later in this topic. Each item can specify more than one resource. However, during installation one and only one resource from an item is used. If a device needs multiple resources of the same type, multiple items of that type must be used in the Log Config section. For example, to ensure two IRQs for a device, two IRQConfig items must be used in the Log Config section. If a device does not require an IRQ, no IRQConfig item should be used. An INF file can contain any number of Log Config sections, as many as are needed to describe the device dependencies. However, each section must contain complete details for installing one device. More than one Log Config section can be specified for device. If this is done, only one of the Log Config sections will be used during installation. For each Log Config section item, the installer builds binary logical configuration records and adds these to the driver section of the registry. The syntax of each of the different types of Log Config section items is shown below. ConfigPriority Item ConfigPriority = Priority_Value Sets the priority value for the logical configuration. Only one ConfigPriority item can be used in a LogConfig section. Priority_Value Can be one of these values: ValueMeaningHARDWIREDCannot be reset in any wayDESIREDSoft Configurable most optimalNORMALSoft Configured medium optimalSUBOPTIMALSoft Configured least optimalDISABLEDHardware disabledRESTARTRequires Windows restart to affectREBOOTRequires system reboot to affectPOWEROFFRequires power cycle to affectHARDRECONFIGRequires Jumper setting DMAConfig Item DMAConfig = [DMAattrs:]DMANum[,DMANum] Sets the DMA channel numbers for the logical configuration. DMAattrs Optional. Can be the letter D for 32-bit channels or W for 16-bit channels. These are specific to the appropriate bus. If no value is given, the default is 8-bit channels. DMANum DMA channel number in decimal notation. IOConfig Item IOConfig = io-range[,io-range]... Sets the IO range(s) for the logical configuration. More than one io-range can be given, but each additional value but be preceded with a comma. Note EISA adapters which use their slot-specific ports do not need to include those ports in their logical configuration. An io-range value has two forms, called Type 1 I/O Range and Type 2 I/O Range. Type 1 I/O Range Value start-end[([decode-mask]:[alias-offset]:[attr])] start Starting address of the IO port region. This is a 16-bit value in hexadecimal notation. end Ending address of the IO port region. This is a 16-bit value in hexadecimal notation. The start and end values must be separated with a hyphen. decode-mask Optional. Bit mask to indicate number of bits of IO address the device decodes. This is a 16-bit value in hexadecimal notation which is the most-significant byte of the actual decode mask. The most-likely values for this field are either 3FF (for 10-bit decode) or FFFF (for 16 bit decode.) alias-offset Optional. Value to indicate additional ports decoded by the adapter. The additional ports are calculated by adding multiples of this offset to the base IO port region. Leaving this field blank indicates that driver software will only access the ports in the base IO region and never access any of the aliases. attr Optional. Reserved; do not use. Type 2 I/O Range Value size@min-max[%align-mask][([decode-mask]:[alias-offset]:[attr])] size Size of the required IO port region in bytes. This is a 16-bit value in hexadecimal notation. The start and end values must be separated with a hyphen. min Smallest possible starting IO port. This is a 16-bit value in hexadecimal notation. max Largest possible ending IO port. This is a 16-bit value in hexadecimal notation. The min and max values must be separated with a hyphen. align-mask Optional. This 16-bit hexadecimal mask is applied to range specified by min and max to determine legal starting addresses for the IO region. To construct the mask, all bits which must be 0 in the starting address must be 0 in the mask. All other bits should be 1. decode-mask Optional. Bit mask to indicate number of bits of IO address the device decodes. This is a 16-bit value in hexadecimal notation which is the most-significant byte of the actual decode mask. The most-likely values for this field are either 3FF (for 10-bit decode) or FFFF (for 16 bit decode.) alias-offset Optional. Value to indicate additional ports decoded by the adapter. The additional ports are calculated by adding multiples of this offset to the base IO port region. Leaving this field blank indicates that driver software will only access the ports in the base IO region and never access any of the aliases. attr Optional. Reserved; do not use. Note In order to avoid conflicts with older cards, all adapters in ISA slots which use IO ports must allocate ports which fall in the 100-3FF range, even if they only use the 10-bit aliases of those ports. Adapters in PCI slots which use the 10 bit aliases of ports in the 100-3FF range do not need to allocate the ports in the 100-3FF range because those addresses will not appear on the ISA bus. The following examples illustrates the use of a list of three Type 1 I/O range values in an IOConfig item. This specifies an IO port region of 8 bytes which can start at 1F8, 2F8, or 3F8. Additionally, the device decodes 10 bits of its address and does not use any of its aliases. IOConfig=1F8-1FF(3FF::), 2F8-2FF(3FF::), 3F8-3FF(3FF::) The following example shows the use of a Type 2 I/O range value in an IOConfig item. This specifies an IO port region of 8 bytes which can start at 300, 308, 310, 318, 320, or 328. The device decodes 10 bits of its address and does not use any of its aliases. IOConfig=8@300-32F%FF8(3FF::) The following example shows the use of a Type 1 I/O range value in an IOConfig item. This specifies 16 IO port regions of 1 byte each, where each region starts at x2E8 where x is 0-Fh. IOConfig=2E8-2E8(FFFF:4:) IRQConfig Item IRQConfig = [IRQattrs:]IRQNum[,IRQNum] Sets the interrupt request (IRQ) numbers for the logical configuration. IRQattrs Optional. Can be the letter S to indicate a sharable interrupt. If no value is given, the default is a non-shareable interrupt. If used, this flag only appears once in an IRQConfig item and affects all IRQs listed in that item. IRQNum IRQ number in decimal notation. More than one IRQ number can be used in a IRQConfig item, but each must be preceded with a comma. MemConfig Item MemConfig = mem-range[,mem-range]... Sets the memory range(s) for the logical configuration. More than one mem-range can be given, but each additional value but be preceded with a comma. The mem-range value has two forms: start-end[(attr)] size@min-max[%align-mask][(attr)] start Starting address of the physical memory region. This is a 32-bit value in hexadecimal notation. The start and end values must be separated with a hyphen. end Ending address of the physical memory region. This is a 32-bit value in hexadecimal notation. size Size of the required region in bytes. This is a 32-bit value in hexadecimal notation. min Smallest possible starting address of the memory region. The min and max values must be separated with a hyphen. max Largest possible ending address of the memory region. alignMask Optional. A 32-bit hexadecimal mask applied to range specified by min and max to determine legal starting addresses for the memory region. To construct the mask, all bits which must be 0 in the starting address must be 0 in the mask. All other bits should be 1. attr Optional. Reserved; do not use. The following examples illustrate the MemConfig item. MemConfig = C0000-C7FFF, D0000-D7FFF This specifies a memory region of 32K bytes which can start at either C000:0000 or D000:0000. MemConfig = 8000@C0000-D7FFF%F0000 This specifies exactly the same region (32K range starting on 64K boundaries only). Manufacturer [Manufacturer] manufacturer-name | %strings-key%=device-section-name The Manufacturer section identifies a manufacturer of a device that can be installed using the INF file and names a Device section that describes that device. manufacturer-name Name of the device manufacturer. This name can be any combination of printable characters, but must uniquely identify the manufacturer and must be enclosed in double quotation marks. strings-key Name of a string defined in the Strings section of the INF file. device-section-name Name of the Device section. This name can be any combination of printable characters, but must uniquely identify another section in the INF file. The Device section: SYMBOL 183 \f "Symbol" Specifies a device description string for a device (device description strings may be displayed at the user interface by the New Device Wizard and/or by the Device manager). SYMBOL 183 \f "Symbol" Specifies the name of the Install section for each of the devices (the Install section for a device gives the primary script for installing the device). SYMBOL 183 \f "Symbol" Specifies the device ID (also called the hardware ID) of the device and, optionally, a list of compatible device IDs for the device. The device ID specified in the Device section may be used in a ControlFlags section to modify the way the New Device Wizard and/or the Device Manager use the device description. The syntax and meaning of items that can be in a Device section and in a ControlFlags section are described later in this topic. The syntax of a Device section is: [device-section] device-description=install-section-name,device-id[,compatible-device-id]... [device-description=install-section-name,device-id[,compatible-device-id]...] Each Device section item gives the device description, identifies the install-type section, and specifies the device ID for a device. Optionally, a Device section item may specify one or more device IDs of compatible devices. There may be one or more items in the Device section, depending upon how many devices the INF file installs for a manufacturer. device-description Description of a device to install. This can be any combination of printable characters or a strings key. install-section-name Name of the Install section for this device. device-id Identifier for this device. compatible-device-id Identifier of a compatible device. More than one compatible-device identifier can be given, but each must be preceded with a comma. This example shows a typical Device section containing one item. The name of the Install section for this device is SuperSCSI. The device-id is *PNPA000 and it is compatible with devices identified as *PnPA001. [SCRUS] %DevDesc1% = SuperSCSI, *PNPA000, *PnPA001 For each driver installed using this INF file, the Device Manager and the New Device Wizard will use the information in the Manufacturer and Device sections to generate Driver Description, Manufacturer Name, DeviceID, and Compatibility List entries in the registry. The device ID specified in the Device section may be used in a ControlFlags section to modify the way the New Device Wizard and/or the Device Manager use the device description. The syntax of the items that can be contained in a ControlFlags section is shown below: [ControlFlags] CopyfilesOnly=Device-id[,device-id]... ExcludeFromSelect=Device-id[,device-id]... The ControlFlags section provides a way to control how a device is handled both during installation and by the Device Manager. The Windows 95 New Device Wizard builds its list of installable devices by searching through INF files. The Device Manager also displays information about devices which originates in INF files. CopyFilesOnly Listing a device-id in a CopyFilesOnly item will allow the user to choose the device in the New Device Wizard but will stop the Wizard from actually doing the installation. When the user chooses the device from the Wizard will only copy files to the destination directory. Typically, devices which are enumerated should be listed in a CopyFilesOnly item. ExcludeFromSelect Listing the device-id of a device in an ExcludeFromSelect item will remove the device completely from the New Device Wizard. Optionally, an asterisk (*) can be specified in place of the id list. Doing this will set ExcludeFromSelect for all devices listed in this INF file. NoResDup Section [InstallSection.Noresdup] Device-id[,device-id]... The NoResDup section is similar to the NoPosDup section except it works for devices which use no resources. When the Device Manager installs a device, it always looks for a NoResDup section. If the section is found the Device Manager will search the \enum\root branch of the registry for devices whose Device-ID matches any Device-ID in the NoResDup Device-ID list. If a match is found, the Device Manager will assume it has found a duplicate entry and will move the \enum\root entry to the enumerator branch and remove the root node. Listing an ID in this section can have unintended side affects as there is no way to tell the difference between a duplicate and a second instance of the device. PosDup Section [Device-id.posdup] Device-id[,device-id]... The Posdup section provides a method for identifying devices which can may appear to be separate devices but in fact are the same device. This can occur when a device is detected and is also enumerated. Typically, detection cannot identify the device exactly but enumeration can. In these cases the Device Manager will detect a conflict. The Device Manager will look at this list and search the root branch of the registry for devices listed in this section. If one is found and the resource in use by these devices overlap, the device manager will assume it has detected a duplicate and will move the root branch entry to the enumerator branch. Rename Files Sections [rename-files-section-name] new-file-name, old-file-name . . . Lists the names of files to be renamed. The name of the section must appear in a Renfiles item in an Install section of the INF file. new-file-name New name of the file. old-file-name Old name of the file. This example renames the files file42 to file41, file52 to file51, and file62 to file61: [RenameOldFilesSec] file41, file42 file51, file52 file61, file62 All the old filenames used in this example (file42, file52, and file62) must be defined in a SourceDisksFiles section and the logical disk numbers that appear in the SourceDisksFiles section must have been defined in a SourceDisksNames section. SourceDisksFiles Section [SourceDisksFiles] filename=disk-number[,subdir] . . . Names the source files used during installation and identifies the source disks that contain the files. filename Name of the file on the source disk. disk-number Ordinal of the source disk that contains the file. This ordinal must be defined in the SourceDisksNames section, and must have a value greater than or equal to 1 (zero is not a valid disk-number parameter value). subdir Optional parameter that specifies the subdirectory on the source disk where the file resides. If this parameter is not used, the source disk root directory is the default. This example SourceDisksFiles section identifies a single source file, SRS01.386, on the disk having ordinal 1: [SourceDisksFiles] SRS01.386 = 1 SourceDisksNames Section [SourceDisksNames] disk-ordinal="disk-description",disk-label,disk-serial-number . . . Identifies and names the disk(s) that contain the source files for file copying and renaming operations. disk-ordinal A unique number that identifies a source disk. If there is more tan one source disk, each must have a unique ordinal. disk-description A string or a strings key describing the contents or purpose of the disk. The installer displays this string to the user to identify the disk. The description is enclosed in double quotation marks. disk-label Volume label of the source disk that is set when the source disk is formatted. disk-serial-number Serial number for the source disk that is set when the source disk is formatted. The default value is 0000-0000. This example identifies one source disk and assigns it ordinal 1. The disk description is given as a strings key: [SourceDisksNames] 0 = %ID1%, Instd1, 0000-0000 [Strings] ID1=CX2590 SCSI Adapter Installation Disk 1 Strings Section [Strings] strings-key=value . . . Defines one or more strings keys. A strings key is a name that represents a string of printable characters. Although the Strings section is generally the last section in the INF files, a string key defined in this section may be used anywhere in the INF file that the corresponding string would be used. The Installer expands the string key to the given string and uses it for further processing. Using a strings key requires that it be enclosed in percent signs (%). strings-key A unique name consisting of letters and digits. value A string consisting of letters, digits, or other printable characters. It should be enclosed in double-quotation marks if the corresponding strings key is used in a type of item that requires double quotation marks. The Strings section makes translation of strings for international markets easier by placing all strings that can be displayed at the user interface when the INF file is used in a single section of the INF file. Strings keys should be used whenever possible. The following example shows the strings section for a sample INF file. [Strings] String0="Corporation X" String1="Corporation X" String2="CX2590 SCSI Adapter" Update Autoexec.bat Sections [update-autoexec-section] CmdAdd=command-name[,command-parameters] CmdDelete=command-name PrefixPath=ldid[,ldid] RemOldPath=ldid[,ldid] TmpDir=ldid[,subdir] UnSet=env-var-name Provides commands to manipulate lines in the AUTOEXEC.BAT file. The section name, update-autoexec-section-name, must appear in the UpdateAutoBat item in an Install section of the INF file. Not all item types shown in the syntax above are needed or required in an Update Autoexec.bat section. The section can contain as many CmdAdd, CmdDelete and UnSet items as needed, but only one PrefixPath, RemOldPath and TmpDir items can be used in an INF file. The syntax and meaning of each of the item types is described later in this topic. The installer processes all CmdDelete items before any CmdAdd items. CmdAdd Item CmdAdd=command-name[,command-parameters] Adds the given command and optional command parameters to the AUTOEXEC.BAT file, at the end of the file. command-name Name of an executable file, with or without an extension. If the filename is also defined in the SourceDisksFiles and DestinationDirs sections of the INF file, the installer adds the appropriate path to the filename before writing it to the AUTOEXEC.BAT file. command-parameters A string enclosed in double quotation marks or a replaceable string like %String1% or %Myparam%, where the strings that replace %String1% and %Myparam% are defined in the Strings section of the INF file. The installer appends the string to the command-name before appending the line to the end of the AUTOEXEC.BAT file. The format of this line is dependent on the command line requirements of the given executable file. CmdDelete Item CmdDelete=command-name Deletes any lines from AUTOEXEC.BAT that include the given command name. The installer searches for and deletes any occurrence of the given name that has a filename extension of .EXE, .COM, and .BAT. command-name Name of an executable file without an extension. PrefixPath Item PrefixPath=ldid[,ldid]... Appends the path associated with the given LDID to the path command. ldid Can be any of the predefined LDID values or a new value defined in the INF. For a definition of all the predefined LDID values, see the Reference topic about the DestinationDirs section. RemOldPath Item RemOldPath=ldid[,ldid] Removes the path associated with the given LDID from the path command. For example, if the user installs the new version of Windows into c:\newwin and has an old copy of Windows in c:\windows, the following INF file item removes c:\windows from the path environmental variable: RemOldPath=10 ldid Can be any of the predefined LDID values or a new value defined in the INF. For a definition of all the predefined LDID values, see the Reference topic about the DestinationDirs section. TmpDir Item TmpDir=ldid[,subdir] Creates a temporary directory within the directory given by the LDID, if it does not already exist. ldid Can be any of the predefined LDID values or a new value defined in the INF. For a definition of all the predefined LDID values, see the Reference topic about the DestinationDirs section. subdir A path name. If ldid\subdir does not already exist, it is created. UnSet Item UnSet=env-var-name Removes any set command from the AUTOEXEC.BAT file that includes the given environment variable name. env-var-name Name of an environment variable. Update Config.sys Sections [update-config-section] Buffers=legal-dos-buffer-value DelKey=key DevAddDev=driver-name,configkeyword[,flag][,param-string] DevDelete=device-driver-name DevRename=current-dev-name,new-dev-name Files=legal-dos-files-value PrefixPath=ldid[,ldid] RemKey=key Stacks=dos-stacks-values Provides commands to add, delete, or rename commands in the CONFIG.SYS file. The section name, update-config-section-name, must appear in the UpdateConfigSys item in an Install section of the INF file. Not all item types shown in the syntax above are needed or required. An Update Config.sys section may contain as many DevRename, DevDelete, DevAddDev, DelKey, and RemKey items as needed, but the Buffers, Files, and Stacks items may only be used once in a section. When processing an Update Config.sys section, the Installer processes all DevRenames items first, all DevDelete items second, and all DevAddDev items last. The syntax and meaning of each of the types of items that can be used in an Update Config.sys section are given later in this topic. Buffers Item Buffers=legal-dos-buffer-value Sets the number of file buffers. As it does with the Stacks item, the Installer compares the existing value with the proposed value and always sets the file buffers to the larger of the two values. legal-dos-buffers-value A legal MS-DOS buffers value. DelKey Item DelKey=key Causes the CONFIG.SYS command with the specified key to be remarked out in the CONFIG.SYS file. For example, the INF file item DelKey=Break would cause a Break=on command to be remarked out in the CONFIG.SYS file. The DelKey item has the same effect as the RemKey item. There can be multiple DelKey and/or RemKey items in a section of the INF file. key The key of the CONFIG.SYS command to be remarked out. DevAddDev Item DevAddDev=driver-name,configkeyword[,flag][,param-string] Adds a device or install command to the CONFIG.SYS file. driver-name Name of the driver or executable file to add. The installer validates the filename extension, ensuring that it is .SYS or .EXE. configkeyword Command name. Can be device or install. flag Optional placement flag. If 0, the command is placed at the bottom of the file. If 1, it is placed at the top. If flag is not given, 0 is used by default. param-string Optional command parameters. Must be valid for the given device driver or executable file. DevDelete Item DevDelete=device-driver-name Deletes any line containing the specified filename from the CONFIG.SYS file. device-driver-name Name of a file or device driver. The Installer searches the CONFIG.SYS file for the name and deletes any line containing it. Because MS-DOS does not permit implicit filename extensions in CONFIG.SYS, each device-driver-name must explicitly specify the filename extension. This example DevDelete item in an Update Config.sys section deletes lines 1 and 3 but not line 2 of the example CONFIG.SYS file: DevDelete=Foo.sys ;; lines in CONFIG.SYS Device=Foo.sys ;; line #1 Install=foo.exe ;; line #2 Device=Foo.sys /d:b800 /I:3 ;; line #3 DevRename Item DevRename=current-dev-name,new-dev-name Renames a device driver in the CONFIG.SYS file. current-dev-name Name of the device driver or executable file to rename. The installer looks for the name on the right side of a device or install command in the CONFIG.SYS. new-dev-name New name for driver or executable file. Files Item Files=legal-dos-files-value Sets the maximum number of open files in the CONFIG.SYS file. As it does with the Stacks item, the Installer compares the existing value with the proposed value and always sets the maximum number of open files to the larger of the two values. legal-dos-files-value A legal MS-DOS files value. PrefixPath Item PrefixPath=ldid[,ldid]... Appends the path associated with the given LDID to the path command. ldid Can be any of the predefined LDID values or a new value defined in the INF. For a definition of all the predefined LDID values, see the Reference topic about the DestinationDirs section. RemKey Item RemKey=key Causes the CONFIG.SYS command with the specified key to be remarked out in the CONFIG.SYS file. For example, the INF file item RemKey=Break would cause a Break=on command to be remarked out in the CONFIG.SYS file. The RemKey item has the same effect as the DelKey item. There can be multiple RemKey and/or DelKey items in a section of the INF file. key The key of the CONFIG.SYS command to be remarked out. Stacks Item Stacks=dos-stacks-values Sets the number and size of stacks in the CONFIG.SYS file. The Installer compares the existing value with the proposed value and always sets the stacks to the larger of the two values. For example, if CONFIG.SYS contains stacks=9,218 and an INF contains stacks=5,256, the installer sets to new value to stacks=9,256. legal-dos-stacks-value A legal MS-DOS stacks value. Update INI Fields Sections [update-inifields-section-name] ini-file, ini-section, profile-name, [old-field], [new-field],[flags] . . . Replaces, adds, and deletes fields in the value of a given INI entry. Unlike the Update INI File section type, this type of section replaces, adds, or deletes portions of a value in an INI file entry rather than the whole value. The section name, update-inifields-section-name, must appear in the UpdateIniFields item in an Install section of the INF file. ini-file Name of the INI file containing the entry to change. For more information about specifying the INI filename, see the topic that describes the Update INI File section type. ini-section Name of the INI file section containing the entry to change. profile-name Name of the entry to change. old-field Field value to delete. new-field Field value to add, if not already there. flags Specifies whether to treat the old-field and new-field parameters as if they have a wild card character or not and/or what separator character to use when appending a new field to an INI file entry. Can be any of these values: BitValueMeaning00(Default) Treat * character literally when matching fields, and not as a wild card character.01Treat * character as a wild card character when matching fields.10(Default) Use blank ( ) as a separator when adding a new field to an entry.11Use comma (,) as a separator when adding a new field to an entry. Any comments in the INI file line are removed as they might not be applicable after changes. When looking for fields in the line in the INI file, spaces, tabs and commas are used as field delimiters. However, a space is used as the separator when the new field is appended to the line. Update INI File Sections [update-ini-section-name] ini-file, ini-section, [old-ini-entry], [new-ini-entry], [flags] . . . Replaces, deletes, or adds complete entries in the given INI file. The section name, update-ini-section-name, must appear in the UpdateInis item in an Install section of the INF file. ini-file Name of the INI file containing the entry to change. For more information about specifying the INI filename, see the comments below. ini-section Name of the section containing the entry to change. old-ini-entry Optional. Usually in the form Key=Value. new-ini-entry Optional. Usually in the form Key=Value. Either the key or value may specify replaceable strings. For example, either the key or value specified in the new-ini-entry parameter may be %String1%, where the string that replaces %String1% is defined in the Strings section of the INF file. flags Optional action flags. Can be one of these values: 0Default. If old-ini-entry key is present in an INI file entry, that entry is replaced with new-ini-entry. Note that only the keys of the old-ini-entry parameter and the INF file entry must match, the value of each entry is ignored. To add new-ini-entry to the INI file unconditionally, set old-ini-entry to NULL. To delete old-ini-entry from the INI file unconditionally, set new-ini-entry to NULL.1If both key and value of old-ini-entry exist in an INI file entry, that entry is replaced with new-ini-entry. Note that the old-ini-entry parameter and the INF file entry must match on both key and value for the replacement to be made (this is in contrast to using an action flag value of 0, where only the keys must match for the replacement to be made).2If the key in the old-ini-entry parameter does not exist in the INI file, then no operation is performed on the INI file. If the key in the old-ini-entry parameter exists in an INI file entry and the key in the new-ini-entry parameter exists in an INI file entry, then the INI file entry that matches the key in the new-ini-entry parameter is deleted and the INI file entry that matches the old-ini-entry parameter is operated on in the following way: the key of the INI file entry is replaced with the key in the new-ini-entry parameter. If the key in the old-ini-entry parameter exists in an INI file entry and the key in the new-ini-entry parameter does not exist in an INI file entry, then an entry is added to the INI file made up of the key in the new-ini-entry parameter and the old value. Note that the match of the old-ini-entry parameter and an INI file entry is based on key alone, not key and value.3Same as flag parameter value of 2 described above, except match of the old-ini-entry parameter and an entry in the INF file is based on matching both key and value, not just the key. The wild card character (*) can be used in specifying the key and value and they will be interpreted correctly. The ini-file name can be a string or a strings key. A strings key has the form %strkey% where strkey is defined in the Strings section in the INF file. In either case, the name must be a valid filename. The name should include the name of the directory containing the file, but the directory name should be given as a logical directory identifier (LDID) rather than an actual name. The installer replaces an LDID with an actual name during installation. An LDID has the form %ldid% where ldid is one of the predefined identifiers or an identifier defined in the DestinationDirs section. Note that when the constants LDID_BOOT and LDID_BOOTHOST are replaced, the backslash is included in the path. For example LDID_BOOT may be replaced with C:\. However, in your INF file you can either use the backslash character or not. For example, either %30%boot.ini and %30%\boot.ini can be used to reference BOOT.INI in the root of the boot drive. The following examples illustrate individual items in an Update INI File section of an INF file: %11%\sample.ini, Section1,, Value1=2 ; adds new entry %11%\sample.ini, Section2, Value3=*, ; deletes old entry %11%\sample.ini, Section4, Value5=1, Value5=4 ; replaces old entry The following set of items in an Update INI File-type section of an INF file work together to operate on the Boot section of SYSTEM.INI. The conditionality built into the flags parameter of the INF file items is used to add the entry comm.drv=comm.drv to the Boot section unless the entries comm.drv=*vcoscomm.drv or comm.drv=*r0dmdcom.drv exist in the Boot section, in which case the existing entry is preserved and the entry comm.drv=comm.drv is not added to the INI file. In other words, after the four INF file entries shown below are executed, there will be one comm.drv= entry in the Boot section of the INI file: comm.drv=*vcoscomm.drv or comm.drv=*r0dmdcom.drv or comm.drv=comm.drv. system.ini, boot, "comm.drv=*vcoscomm.drv","~CommDrvTemp~=*", 3 system.ini, boot, "comm.drv=*r0dmdcom.drv","~CommDrvTemp~=*", 3 system.ini, boot,,"comm.drv=comm.drv" system.ini, boot, "~CommDrvTemp~=*","comm.drv=*", 3 Version Section [Version] Signature="$Chicago$" Class=class-name Provider=INF-Creator LayoutFile=filename.inf Defines the standard header for all Windows 95 INF files. Note that if the signature is not $Chicago$ then Windows 95 will not accept the INF file as an INF file for any of the classes of devices recognized by Windows 95. For a list of all the device classes recognized by Windows 95, see the topic Introducing the INF Editor earlier in this chapter. Note the signature string recognition is case-insensitive. So, for example, you can use either $Chicago$ or $CHICAGO$. class-name Defines the class in the registry for any device installed from this INF. INF-creator Identifies the creator of the INF file. Typically this is the name of the organization that creates the INF file. filename.inf Names the INF file that contains the layout information (source disks and files) required fro installing this driver software. This line is optional. If not given, the SourceDisksNames and SourceDisksFiles sections must be given in this INF. This example shows a typical Version section: [Version] Signature="$CHICAGO$" Class=SCSIAdapter Provider=%String0% [Strings] String0="Corporation X" Chapter SEQ CHAPTER \R 77 Property Page Providers About Property Page Providers Property page providers are dynamic-link libraries (DLLs) that work in conjunction with the Device Manager to display property sheets for examining and modifying the settings and configuration of a device. The Device Manager provides a default property page provider that gives access to typical device properties. If your device has properties that are not supported by the default provider, you can extend the capabilities of the default property page provider by creating a custom property provider. With a custom provider you can add new and replace existing property pages in the default property sheets. This chapter describes property page providers and explains how to create and register custom providers. For more information about creating and managing property sheets, see the Microsoft Win32 Programmers Reference. User Requests for Properties A user requests access to the properties or a device or class by pressing the Properties button presented by the Device Manager. The Device Manager always gives the class installer for the device or class the first opportunity to carry out the request by sending a DIF_PROPERTIES request to the ClassInstall function of the installer. The installer either processes the request completely, displaying and handling its own property sheets, or it returns the ERR_DI_DO_DEFAULT value directing the Device Manager to build a default property sheet to complete the request. (For more information about the class installer, see Chapter 5, Plug and Play Installation.) If the Device Manager builds a property sheet, it relies on custom and default property page providers for the property pages. The Device Manager uses the property pages from the default property page provider if no custom property pages are available for the device. The default property pages, called default general property page and the default resource property page, let the user view and set the general and resource properties of a device. If a custom property page provider exists, the Device Manager gives that provider the opportunity to replace the default property pages or provide new property pages in addition to the default pages. The custom provider must be registered in order for the Device Manager to use it. Default General Property Page The default general property page displays the name of the device and the device driver, and also offers these actions to the user: Enable/Disable Device Enables or disables the device. The action taken to enable or disable depends on the capabilities of the device. Remove Device Removes the hardware and driver keys from the registry in preparation of the user physically removing the device. Remove Driver Removes the driver key in the registry but leaves the device configured. Change Driver Installs a new device driver for the device. Hardware Profile Settings Lets the user specify how to deal with hardware when the machine is docked or undocked. Default Resource Property Page The default resource property page shows the basic system resources consumed by a given device, such as memory addresses, I/O ports, IRQ, and DMA channels. It also lets the user view current resource settings and set a forced configuration for the device. Custom Property Page Providers A custom property page provider adds new property pages or replaces default property pages for a specific device or class. A provider can be a separate DLL or it can be combined with the class installer or the control panel applet for the device. If combined with the installer, the provider must be distinct from any properties handling provided by the ClassInstall function of the installer. Every property page provider exports the property page enumeration function, usually named EnumPropPages. The Device Manager dynamicly links and calls this function just before displaying the default property sheet to give the provider a chance to add pages or replace the default pages. A provider must export dialog procedures to support the property pages it adds to the default property sheet. The dialog procedures process initialize values and process user input for the property pages when the Device Manager displays the property sheet. The Device Manager uses the PropertySheet function to display the properties sheet, so the dialog procedures for the individual pages must be prepared to process the messages and notifications associated with this function. Property Page Enumeration Function When the Device Manager calls EnumPropPages, it passes three arguments: the address of a DEVICE_INFO structure, the address of a AddPropSheetPageProc function, and a 32-bit value. The DEVICE_INFO structure identifies the device or class that the user has requested properties for. The 32-bit value is used by the Device Manager to keep track of internal processing and must not be changed. You use the AddPropSheetPageProc function to add property pages to the default property sheet. The function requires two parameters: a handle of a valid property sheet page and the supplied 32-bit value. You create a valid property sheet page and retrieve its handle by using the CreatePropertySheetPage function. The AddPropSheetPageProc function returns TRUE if it added the page, FALSE otherwise. To replace one or both default property pages, you add the replacement pages using AddPropSheetPageProc, then set one or both of these values in the Flags member of the DEVICE_INFO structure: DI_GENERALPAGE_ADDEDReplaces the default general property page.DI_RESOURCEPAGE_ADDEDReplaces the default resources property page. If you replace a default page, your replacement page must provide all the basic functions provided by that default page. If you do not replace a default page, the Device Manager uses the default page for the class or device as appropriate. The EnumPropPages function returns TRUE to direct the Device Manager to display the property sheet or FALSE to prevent display. Property Page Dialog Procedure Property page dialog procedures support property pages added by a provider. The procedures must adhere to the guidelines given for property sheets in the Microsoft Win32 Programmers Reference. In particular, a dialog procedure must process any WM_NOTIFY messages appropriately. A property page dialog procedure should also save the address of the DEVICE_INFO structure sent as the lParam parameter with the WM_INITDIALOG message. The Device Manager sends this structure to help the dialog procedure determine the device or class. Dialog procedures typically use the SetWindowLong to store this value in the DWL_USER portion of the window handle, then retrieve the address using the GetWindowLong function on subsequent messages. If a reboot or restart is necessary due to the settings provided by the user, a dialog procedure show always set an appropriate value in the Flags member of the DEVICE_INFO structure. It must not send a PSN_GUISTART or PSN_REBOOT notification to the property sheet dialog procedure. Provider Registration The Device Manager requires that you register your property page provider by adding appropriate entries to the registry. You register a provider by using the EnumPropPages entry in either the class branch for a class provider or the device driver branch (one level below the class branch) for a device provider. The entry has this form: EnumPropPages=DLL-name,[EnumPropPagesName] The EnumPropPagesName must be the name of a function exported by the given DLL. If no name is given, the Device Manager searches the given DLL for an exported function having the name EnumPropPages. If you register a provider of a device, the Device Manager uses that provider only if the user requests access to the properties of that specific device. If you register for a class, the Device Manager uses it whenever the user requests access to properties of a device in that class for which no device-specific provider exists. You should always register a property page provider by specifying the appropriate registry commands in the INF file for your device or class of devices. Class Provider The Device Manager calls the class property page provider to provide property pages for both class properties and device properties. This allows the class provider to add property pages to every device in its class. The class provider is responsible for determining whether the request is for class properties or device properties by checking for the DI_CLASSONLY value in the Flags member in the DEVICE_INFO structure. If the value is present, the request is for class properties; otherwise, for device properties. When DI_CLASSONLY is set, the provider cannot replace the default resource property page. This means the Device Manager ignores the DI_RESOURCEPAGE_ADDED value even if set. If the class provider adds or replaces property pages on a request for device properties, it must follow the same rules as the device property provider. Device Provider The Device Manager calls the device property sheet provider to provide property pages for a specific device. The Device Manager determines the device provider by checking for the EnumPropPages entry under the device driver branch in the registry. A device provider can add new property pages or replace one or both of the default property pages. Reference This section describes the functions and structures used to support device property pages. Functions This section describes functions used with property pages. AddPropSheetPageProc BOOL AddPropSheetPageProc(HPROPSHEETPAGE hPage, LPARAM lParam); Adds a property page to the default property sheet. This function is supplied by the Device Manager and called by a property page provider. symbol 183 \f "Symbol" Returns TRUE if the page is added, FALSE otherwise. hPage Handle of a valid property sheet page as created by the CreatePropertySheetPage function. lParam Data passed to the EnumPropPages function. This value must not be modified in any way. EnumPropPages BOOL EnumPropPages(LPDEVICE_INFO lpdi, LPFNADDPROPSHEETPAGE AddPropSheetPageProc, LPARAM lParam); Adds property pages to the default property sheet. This provider-supplied function is called by the Device Manager before the default property sheet is displayed. symbol 183 \f "Symbol" Returns TRUE to display the property sheet, FALSE otherwise. lpdi Address of a DEVICE_INFO structure that contains information about the device or class that the user has requested properties for. AddPropSheetPageProc Address of the system-supplied callback function. For more information about this callback, see the AddPropSheetPageProc function. lParam System-supplied data. This data must be passed unchanged to the AddPropSheetPageProc function. Constants This section describes constants used with property pages. Dynamic Hardware Install Wizard Constants Constants that are used when adding custom pages to the hardware install wizard. Constants MAX_INSTALLWIZARD_DYNAPAGES The maximum number of dynamic hardware installation wizard pages that can be added by a class installer. IDD_DYNAWIZ_FIRSTPAGE Resource ID for the first page that the install wizard will go to after adding the class installer pages. IDD_DYNAWIZ_SELECT_PREVPAGE Resource ID for the page that the Select Device page will go back to. IDD_DYNAWIZ_SELECT_NEXTPAGE Resource ID for the page that the Select Device page will go forward to. IDD_DYNAWIZ_ANALYZE_PREVPAGE Resource ID for the page that the Analyze page will go back to. This will only be used in the event that there is a problem (i.e a conflict), and the user selects Back from the analyze page. IDD_DYNAWIZ_ANALYZE_NEXTPAGE Resource ID for the page that the Analyze page will go to if it continues forward. The wAnalyzeResult in the INSTALLWIZARDDATA struct will contain the anaysis results. IDD_DYNAWIZ_INSTALLDETECTED_PREVPAGE Resource ID for that page that the Install detected devices page will go back to. IDD_DYNAWIZ_INSTALLDETECTED_NEXTPAGE Resource ID for the page that the Install detected devices page will go forward to. IDD_DYNAWIZ_INSTALLDETECTED_NODEVS Resource ID for the page that the Install detected devices page will go to in the event that no devices are detected. IDD_DYNAWIZ_SELECTDEV_PAGE Resource ID of the hardware install wizard's select device page. This ID can be used to go directly to the hardware install wizard's select device page. IDD_DYNAWIZ_ANALYZEDEV_PAGE Resource ID of the hardware install wizard's device analysis page. This ID can be use to go directly to the hardware install wizard's analysis page. IDD_DYNAWIZ_INSTALLDETECTEDDEVS_PAGE Resource ID of the hardware install wizard's install detected devices page. This ID can be use to go directly to the hardware install wizard's install detected devices page. IDD_DYNAWIZ_SELECTCLASS_PAGE Resource ID of the hardware install wizard's select class page. This ID can be use to go directly to the hardware install wizard's select class page. Chapter SEQ CHAPTER \R 88 Device Registry Keys and Values About Device Registry Keys and Values Windows 95 uses the registry to store information that identifies detected or enumerated devices and the device drivers that support them. The system relies on this information to reliably allocate resources for legacy devices (those without Plug and Play circuitry) and to install appropriate device drivers and other supporting components. This chapter describes the registry keys and values used to support devices and device drivers. However, it does not describe how to access these keys and values. For more information about accessing the registry, see the Chapter 9, Registry Services. Root Keys and Branches Windows 95 stores information about devices and device drivers in the branches of the HKEY_LOCAL_MACHINE key (sometimes abbreviated HLM). Initially, the system creates this information during system setup in response to detecting or enumerating a device. The setup utility copies information about the given device or a compatible device from a matching .INF file to the registry. The INF file provides the instructions needed to add resource requirements, driver-specific data, and switch settings to the appropriate branches of the registry. The HLM\ENUM branch contains information about all the devices that are presently and were previously installed in the system. The system uses this branch during system startup to retrieve information about enumerated devices. If the system cannot find information about the device in this branch, it assumes that new hardware has been installed and automatically invokes the device installer to create the necessary entries and to install the drivers. Information remains in this branch, even if the corresponding device is removed, so that the necessary information is present if the device is reinstalled. The HLM\CONFIG branch contains information about hardware profiles. A hardware profile is a set of information that defines the hardware present in the system. Hardware profiles are typically used in docking systems in which the number and type of devices may be different with each docking station. The typical docking system has one hardware profile for each docking station and one for when it is not docked. The HLM\SYSTEM branch contains detailed information about the available devices and their current configuration. This includes information about each class of device as well as individual devices. Unlike Windows NT, Windows 95 does not use the HLM\HARDWARE branch to store device information. Instead, Windows 95 leaves this branch empty. Windows 95 uses the HLM\SOFTWARE branch to store information about applications and system components. It is recommend that all applications, including those that provide support for device drivers, use this branch to store version-specific information. Each application should store information under its own subkey. The subkey should have this general form: SOFTWARE\manufacturer\product\version. Windows 95 also stores information in the branches of the HKEY_USERS key. While Windows 95 is not currently expected to be a true-multiuser system, this key and the associated key HKEY_CURRENT_USER key (sometimes abbreviated HCU) are available so that applications may take advantage of future enhancements. Currently, the HKEY_CURRENT_USER key maps to a single default user branch under HKEY_USERS, but eventually it will map to the users login name, giving applications the ability to store user-specific profile information on a network server and letting users work at multiple workstations without requiring them to maintain multiple profiles. In general, applications should store user-specific information under HCU\SOFTWARE rather than under HLM\SOFTWARE. HKEY_LOCAL_MACHINE The HKEY_LOCAL_MACHINE branch contains all device information relevant to the given machine, including information about devices found by detection modules during system setup, devices enumerated by Plug and Play enumerators, and devices manually identified by the user. The following keys identify branches of HKEY_LOCAL_MACHINE that contain device information: CONFIG\profile Contains configuration information for a specific hardware profile. The profile subkey is a 4-digit, hexadecimal number identifying a specific hardware profile. Although the CONFIG branch is in HKEY_LOCAL_MACHINE, the predefined key HKEY_CURRENT_CONFIG can also be used to open the branch. CONFIG\profile\ENUM\ROOT\device-id\instance-number Contains configuration information for a specific legacy device for a specific hardware profile. The profile subkey is a 4-digit, hexadecimal number identifying a specific hardware profile. The device-id and instance-number specify the devices ID and an instance number that uniquely identifies the device. This branch may contain an CSConfigFlags value, which is a bitmapped field defined as follows: Bit 0: Device is disabled Bit 1: Device is removed Bit 2: Do Not Start ENUM Contains information for all legacy, Plug and Play, and user-installed devices. Initially, this branch receives subkeys and values during system setup. Setup records information for each device found by hardware detection modules in the ROOT branch, Plug and Play enumerators record information about devices stored by that enumerator in another enumerator specific branch as described below. ENUM\enumerator Contains a permanent record of all hardware that has been installed, whether currently present or not. The information includes the list of devices, their resource requirements, and driver bindings. The enumerator subkey uniquely identifies an enumerator; there is one subkey for each Plug and Play enumerator installed in the system. ENUM\ROOT Contains information for all detected legacy devices. Because it is not possible to redetect all existing legacy devices each time the system starts, the root enumerator uses this information to load the drivers for this hardware. If ENUM\ROOT identifies a device, the system loads the corresponding driver. It is the responsibility of the driver to unload itself if the device is not available. ENUM\enumerator\device-id\instance Contains device-specific information. The enumerator uniquely identifies the enumerator associated with the device. The device-id is the device identifier for the device, and instance is a string that uniquely identifies a particular instance of this device. This branch contains values such as DeviceDesc, Class, CompatibleIDs, and Driver. ENUM\ROOT\device-id\device-number Contains information for a specific legacy device. The device-id is the device identifier for the device and and device-number is a 4-digit, hexadecimal number that uniquely identifies an instance of that device. This branch contains values such as DeviceDesc, Class, CompatibleIDs, BootConfig, and Driver. ENUM\ROOT\device-id\device-number\LogConfig Contains logical configuration information for a legacy device. The device-id is the device identifier for the device and and device-number is a 4-digit, hexadecimal number that uniquely identifies an instance of that device. This branch contains one or more binary values that contain the configuration information. The name for each value is a decimal digit. SOFTWARE\vendor-name\product-name\version Contains information about the given version of an given application. The vendor-name must be a unique name identifying the manufacturer. The product-name also must uniquely identify the application. The version identifies the given version of the application or can be CurrentVersion to indicate the most recent current version if multiple versions are on the system. This branch contains zero or more application-specific subkeys and values. SYSTEM\CurrentControlSet\Control\IDCONFIGDB Identifies the hardware profile database. This branch contains one or more keys that identify instances of hardware-profile information. This branch contains values such as CurrentConfig, FriendlyNamexxxx, and Map. SYSTEM\CurrentControlSet\Services\Class Contains information about detected or enumerated hardware. This branch contains zero or more subkeys. Each corresponds to the registry-path given in the Driver value of a corresponding ENUM\enumerator\device-id\instance or ENUM\ROOT\device-id\instance branch. SYSTEM\CurrentControlSet\Services\Class\device-class Contains information about a specific device class. The device-class is the unlocalized name for the class. This branch contains values such as Installer, Icon, and EnumPropPages. This branch also contains an unnamed value that specifies the localized name of the class to present to the user during device installation. SYSTEM\CurrentControlSet\Services\Class\device-class\instance Contains information about a specific device within the given class. The device-class is the class name; the instance is a 4-digit, hexadecimal number. This branch contains values such as DriverDesc, DevLoader, and Enumerator. SYSTEM\CurrentControlSet\Services\VxD Contains information about static virtual devices, that is, virtual devices that are loaded with the system rather than dynamically loaded. This branch is used to identify virtual devices, such CONFIGMG, that are not associated with a specific device. This branch supersedes the corresponding entries in the [386Enh] section of the SYSTEM.INI file. To avoid loading duplicate virtual devices, Windows 95 loads all virtual devices identified in this branch first, then loads virtual devices from SYSTEM.INI, giving preference to virtual devices loaded from the registry. This guarantees that new drivers specified in this branch take precedence over old drivers specified in SYSTEM.INI. SYSTEM\CurrentControlSet\Services\VxD\device-class Contains information about drivers and other system components that do not necessarily have corresponding devices. The device-class is the class name of the virtual device. This branch contains values such as Start and StaticVxD. Reference This section describes the values used in the various registry branches to support device drivers. BootConfig BootConfig=binary-data Identifies the boot configuration for a device. The binary-data is configuration data, in binary format, that specifies the IRQ, I/O ports, and other resources used by this device. This value is used in HLM\ENUM\ROOT\device-id\instance. Class Class=string Identifies the name of the device class. The string can be any character string. This value is used in HLM\ENUM\enumerator\device-id\instance and HLM\ENUM\ROOT\device-id\instance. CompatibleIDs CompatibleIDs=device-id Identifies a list of compatible device IDs for a device that can be used for purposes of loading a default driver when a specific one from the vendor is not available. The device-id is a multiple-string value that specifies one or more valid device identifiers. This value is used in HLM\ENUM\enumerator\device-id\instance and HLM\ENUM\ROOT\device-id\instance. CurrentConfig CurrentConfig=profile Identifies the current hardware profile. The profile is a 4-digit, hexadecimal number that corresponds to one of the profile keys in the IDCONFIGD      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxz{|}~B branch. The system sets this number when it starts or when the user docks, undocks, or forces a switch between hardware profiles by using the the docking control panel. This value is used in HLM\SYSTEM\CurrentControlSet\Control\IDCONFIGDB. DeviceDesc DeviceDesc=string Identifies the the localized name of the device. This name is typically presented to the user when the device is installed. The string can be any character string. This value is used in HLM\ENUM\enumerator\device-id\instance and HLM\ENUM\ROOT\device-id\instance. DevLoader DevLoader=name Identifies the device loader associated with this device. The name is the file name of the virtual device that serves as the device loader. This value is used in the appropriate subbranch of HLM\SYSTEM\ CurrentControlSet\Services\Class. Driver Driver=registry-path Identifies the branch (under the SYSTEM\CurrentControlSet\Service\Class branch) that contains information about the device driver to load for the new device. The registry-path is a subkey that typically consists of a class name and a 4-digit, hexadecimal, device-instance number. This value is used in HLM\ENUM\enumerator\device-id\instance and HLM\ENUM\ROOT\device-id\instance. DriverDesc DriverDesc=string Identifies the the localized name of the device driver. This name is typically presented to the user when the driver is installed. The string can be any character string. This value is used in HLM\SYSTEM\CurrentControlSet\Services\Class\device-class. Enumerator Enumerator=name Identifies the enumerator associated with this device. The name is the filename of the virtual device that serves as the enumerator. This value is used in HLM\SYSTEM\CurrentControlSet\Services\Class\device-class. EnumPropPages EnumPropPages=module-and-entry-point-name Specifies the name of the property page handling function for this device class. The module-and-entry-point-name is a character string that specifies the name of the dynamic-link library containing the handler and optionally the exported name of the handler. If the name of the function is given, it is given after the DLL name and is preceded by a comma. This value is used in HLM\SYSTEM\CurrentControlSet\Services\Class\device-class. FriendlyName FriendlyNamenumber=string Specifies a user-defined name for the given hardware profile. The number is a 4-digit, hexadecimal value identifying the hardware profile. The string can be any null-terminated string. This value is used in SYSTEM\CurrentControlSet\Control\IDCONFIGDB. Icon Icon=number Identifies the icon used to represent the class installer in the control panel. The number is a string representing a signed, decimal number. This value is used in HLM\SYSTEM\CurrentControlSet\Services\Class\device-class. Installer Installer=module[,entry point] Specifies the name of the class installer for this device class. The module-and-entry-point-name is a character string that specifies the name of the dynamic-link library containing the installation function and optionally the exported name of the installation function. If the name of the function is given, it is given after the DLL name and is preceded by a comma. This value is used in HLM\SYSTEM\CurrentControlSet\Services\Class\device-class. MAP MAP=binary-data Specifies the ID-to-Hardware-Profile mapping for a system. The binary-data is an array of dock-serial/hardware-checksum tuples and hardware profile identifiers, given as a single binary value. This value is used in HLM\SYSTEM\CurrentControlSet\Control\IDCONFIGDB. Start Start=value Currently this value is ignored. The system always loads the given virtual device. Indicates whether the given virtual device should be started. If value is 0, the system loads the virtual device identified by the StaticVxD value in the same branch. If value is 4, the system does not load the given virtual device. If the Start value is not present in a branch, its value is assumed to be 0. This value is in HLM\SYSTEM\CurrentControlSet\Services\VxD\device-class. StaticVxD StaticVxD=name Identifies a static virtual device. The name is a string specifying the name of a static virtual device, that is, one loaded with the system rather than dynamically loaded. Such names typically start with an asterisk (*). This value replaces the corresponding DEVICE entry in the [386Enh] section of the SYSTEM.INI file. This value is used in HLM\SYSTEM\CurrentControlSet\Services\VxD\device-class. Chapter SEQ CHAPTER \R 99 Registry Services About Registry Services The registry services give virtual devices access to the keys and values of the Windows 95 registry. This chapter describes the registry services and explains how to use them in your virtual devices to retrieve and set values in the Windows 95 registry. This chapter does not describe the registry keys and values that are used to support hardware devices in Windows 95. For more information about device registry keys and values, see Chapter 8, Device Registry Keys and Values. Root Keys, Subkeys, and Values The registry consists of a hierarchically arranged set of keys. Each key has a name and can have associated subkeys and values. A key represents a branch in the registry hierarchy. A root key is a predefined value that identifies a topmost branch in the registry hierarchy. For example, the HKEY_LOCAL_MACHINE key identifies the branch that contains hardware and software information about the given computer. The keys and values you access are always within a branch of a root key. To access keys and values in the registry you must open a key. Opening a key creates a handle that you can use to open other keys or to examine and set values. The predefined root keys are always considered to be open. You can create new keys and new values in any open key. Each value has a corresponding value name and data type. The value name identifies the value and the data type specifies the format of the data, whether a null-terminated string (REG_SZ) or binary data (REG_BINARY). Other values such as REG_DWORD are valid as well, although internally any value that is not REG_SZ is treated as REG_BINARY. Any You can also delete keys and values, but you cannot delete the root keys. Registry Services Virtual devices can open, read, write, create, and delete registry keys and values using the registry services provide by the VMM. There are these registry services: _GetRegistryKey _GetRegistryPath _RegCloseKey _RegCreateKey _RegDeleteKey _RegDeleteValue _RegEnumKey _RegEnumValue _RegFlushKey _RegOpenKey _RegQueryValue _RegQueryValueEx _RegSetValue _RegSetValueEx During the protected-mode initialization phases, the registry may be written to but the data will not be flushed to disk until the end of the Device_Init phase. Until the end of this phase, virtual devices may only access the HKEY_LOCAL_MACHINE key. No other predefined keys are available. The registry services can be called from either assembly-language or C-language source in a VxD. To call the registry from a Ring 3 driver or application, refer to the SDK documentation for Win32 registry services. Assembly-language calls have this form: include vmmreg.inc VMMCall _RegCloseKey cmp eax,ERROR_SUCCESS jnz CreateFail C-language calls have this from: include if (VMM_RegCloseKey(phKey) != ERROR_SUCCESS) { MyErrorHandler("RegCloseKey Failed"); } Real-mode Registry Functions Static virtual devices can open and retrieve values from the registry during real-mode initialization. During this time, the registry is read-only and only the keys and values under the HKEY_LOCAL_MACHINE key are accessible. Virtual devices call these functions by filling registers and calling the loader services function or by using one of these real-mode registry function macros: LDR_RegCloseKey LDR_RegEnumKey LDR_RegEnumValue LDR_RegOpenKey LDR_RegQueryValue LDR_RegQueryValueEx Reference This section describes the registry services, real-mode functions, and constants. Services This section describes the registry services. All services have corresponding C-callable VMM functions. _GetRegistryKey DWORD _GetRegistryKey(DWORD dwType, LPSTR lpszDevName, DWORD dwFlags, LPHKEY lphKey); Gets a registry key handle for the given device name under the given branch of the HKEY_LOCAL_MACHINE key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. dwType Parent registry branch in which to open the key. Can be one of these values: REGTYPE_CLASS\System\CurrentControlSet\Services\ClassREGTYPE_ENUM\ENUM lpszDevName Address of a null-terminated string specifying the device-name subkey. dwFlags Action flags. Can be 0 or REGKEY_CREATE_IFNOTEXIST to indicate the key should be created if it does not already exist. lphKey Address of the variable that receives the handle of the opened key. _GetRegistryPath DWORD _GetRegistryPath(DDB ddb, LPSTR lpszPath, DWORD cbPath); Gets the registry path for the device driver associated with the given virtual device descriptor block (DDB). SYMBOL 183 \f "Symbol" Returns the number of bytes copied to the buffer or the buffer size, in bytes, needed to receive the complete path. This service returns 0 if no registry path exists. ddb Device descriptor block for the virtual device for which to retrieve the registry path. lpszPath Address of the buffer that receives the null-terminated registry path. This buffer receives the path only if buffer is large enough to hold the complete path. cbPath Size, in bytes, of the lpszPath buffer. _RegCloseKey DWORD _RegCloseKey(HKEY hKey) Closes a previously opened key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, ERROR_BADKEY, ERROR_KEY_DELETED, or other errors indicating the given hKey is invalid. hKey Handle of a previously opened key. _RegCreateKey DWORD _RegCreateKey(HKEY hKey, LPSTR lpszSubKey, LPHKEY lphKey) Creates or opens the registry key for the given registry path. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or one of the predefined root keys given in Constants later in this chapter. lpszSubKey Subkey string to be opened. Can be NULL. Can also be NULL-string only if hKey is a predefined key. lphKey Address of the returned HKEY for a successful open/create. _RegDeleteKey DWORD _RegDeleteKey(HKEY hKey, LPSTR lpszSubKey) Deletes the given registry key including its subkeys from the registry database. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key. lpszSubKey Address of a null-terminated string specifying the subkey to delete. This service also marks all other open references to the key being deleted as deleted, so that all accesses through these other open references will fail with an ERROR_KEY_DELETED error. But a virtual device could create a new key with the same name, even before these open references are closed, without any conflict. _RegDeleteValue DWORD _RegDeleteValue(HKEY hKey, LPSTR lpszValue) Deletes the value for the given registry key and the given value name. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or one of the predefined root keys given in Constants later in this chapter. lpszValue Address of a null-terminated string specifying the value name to delete. Can be NULL or an empty string. Each key can have one value for which the value name is NULL. This is treated as the value for the key itself. This value can be deleted by passing a NULL or a null string for lpszValue parameter. _RegEnumKey DWORD _RegEnumKey(HKEY hKey, DWORD iSubKey, LPSTR lpszBuffer, DWORD cbBuffer) Enumerates the subkeys of a given registry key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or one of the predefined root keys given in Constants later in this chapter. iSubKey Index of the subkey to retrieve. This should be zero for the first call to this service. lpszBuffer Address of a buffer that receives the name of the subkey. cbBuffer Size, in bytes, of the lpszBuffer buffer. The virtual device should initially set iSubKey to zero, then increment it on successive calls. _RegEnumValue DWORD _RegEnumValue(HKEY hKey, DWORD iValue, LPSTR lpszValue, LPDWORD lpcbValueName, LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData) Enumerates the value names and values of a given registry key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or one of the predefined root keys given in Constants later in this chapter. iValue Index of the value name to retrieve. This should be zero for the first call to this service. lpszValue Address of a buffer that receives the name of the value. Can be NULL if value name is not required. lpcbValueName Address of a 32-bit variable that contains the size, in bytes, of the lpszValue buffer. The variable receives the size, in bytes, of the retrieved value name. Can be NULL only if lpszValue is NULL. lpdwReserved Reserved; should be set to NULL by the caller. lpdwType Address of a 32-bit variable that receives the data type for the given value name. Can be NULL if data type is not needed. lpbData Address of a buffer that receives the value data for the given value name. Can be NULL if value data is not required. lpcbData Address of a 32-bit variable that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved value data. Can be NULL only if lpbData parameter is also NULL. The virtual device should initially set iValue to zero, then increment it on successive calls. _RegFlushKey DWORD _RegFlushKey(HKEY hKey) Flushes the data for the given Registry Key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or one of the predefined root keys given in Constants later in this chapter. This is a time consuming operation and should not be used under normal circumstances. This service returns only after the registry file is flushed to disk. This may also flush data for other keys in the same registry file. Note that the registry is periodically flushed to the disk by VMM. _RegOpenKey DWORD _RegOpenKey(HKEY hKey, LPSTR lpszSubKey, LPHKEY lphKey) Opens the registry key for the given registry path. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or one of the predefined root keys given in Constants later in this chapter. lpszSubKey Address of a null-terminated string specifying the subkey to be open. May also be NULL or NULL-string. lphKey Address of the variable that receives the handle of the opened key. _RegQueryValue DWORD _RegQueryValue(HKEY hKey, LPSTR lpszSubKey, LPBYTE lpbData, LPDWORD lpcbData) Retrieves the value for the given registry key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or one of the predefined root keys given in Constants later in this chapter. lpszSubKey Address of a null-terminated string specifying the subkey for which to retrieve the value. Can be NULL or point to a NULL-string. lpbData Address of a buffer that receives the value data for given registry key. lpcbData Address of a 32-bit variable that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved data. _RegQueryValueEx DWORD _RegQueryValueEx(HKEY hKey, LPSTR lpszValueName, LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData) Retrieves the value for the given registry key for the given value name. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or one of the predefined root keys given in Constants later in this chapter. lpszValueName Address of a null-terminated string specifying the value name to for which to retrieve the value. Can be NULL or point to a NULL-string. lpdwReserved Reserved; set to NULL. lpdwType Address of a 32-bit variable that receives the data type for the given value. Can be NULL if data type is not needed. lpbData Address of a buffer that receives the value data for given registry key. lpcbData Address of a 32-bit variable that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved data. _RegSetValue DWORD _RegSetValue(HKEY hKey, LPSTR lpszSubKey, DWORD fdwType, LPBYTE lpbData, DWORD cbData) Sets the value for the given registry key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or one of the predefined root keys given in Constants later in this chapter. lpszSubKey Address of a null-terminated string specifying the subkey for which to set the value. Can be NULL. fdwType Value data type to set. Must be REG_SZ. lpbData Address of a buffer that contains the value data to set. cbData Size in bytes of the value data buffer (lpbData). Can be zero, in which case, the value length is automatically calculated. _RegSetValueEx DWORD _RegSetValueEx(HKEY hKey, LPSTR lpszValueName, DWORD dwReserved, DWORD fdwType, LPBYTE lpbData, DWORD cbData) Sets the value for the given registry key and the given value name. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or one of the predefined root keys given in Constants later in this chapter. lpszValueName Address of a null-terminated string specifying the value name for which to set the value. Can be NULL or point to a NULL-string. dwReserved Reserved; set to NULL. fdwType Value data type to set. Must be one of REG_SZ or REG_BINARY. Must be REG_SZ if lpszValueName is NULL or points to a NULL-string. See Constants later in this chapter. lpbData Address of a buffer that contains the value data to set. cbData Size in bytes of the value data buffer (lpbData). Can be zero for REG_SZ, in which case, the value length is automatically calculated. Real-mode Functions This section describes the real-mode registry function macros. These macros expand to calls to the loader service function. Access is restricted to the HKEY_LOCAL_MACHINE key and is read-only. LDR_RegCloseKey DWORD LDR_RegCloseKey(HKEY hKey) Closes a previously opened key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, ERROR_KEY_DELETED, ERROR_BADKEY, or other errors to indicate the given hKey is invalid. hKey Handle of a previously opened key. LDR_RegEnumKey DWORD LDR_RegEnumKey(HKEY hKey, DWORD iSubKey, LPSTR lpszBuffer, DWORD cbBuffer) Enumerates the subkeys of a given registry key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or is the HKEY_LOCAL_MACHINE key. iSubKey Index of the subkey to retrieve. This should be zero for the first call to this API. lpszBuffer Address of a buffer that receives the name of the subkey. cbBuffer Specifies the size, in bytes, of lpszBuffer. The virtual device should initially set the iSubKey to zero, then increment it on successive calls. LDR_RegEnumValue DWORD LDR_RegEnumValue(HKEY hKey, DWORD iValue, LPSTR lpszValue, LPDWORD lpcbValueName, LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData) Enumerates the value names and values of a given registry key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or is the HKEY_LOCAL_MACHINE key. iValue Index of the value name to retrieve. This should be zero for the first call to this function. lpszValue Address of a buffer that receives the name of the value. Can be NULL if value names are not required. lpcbValueName Address of a variable that contains the size, in bytes, of buffer. This variable receives the size, in bytes, of the retrieved value name. Can be NULL only if lpszValue is NULL. lpdwReserved Reserved; set to NULL. lpdwType Address of a 32-bit variable that receives the data type of the given value name. Can be NULL if data type is not needed. lpbData Address of a buffer that receives the value of the given value name. Can be NULL if value data is not required. lpcbData Address of a 32-bit variable buffer that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved data. Can be NULL only if lpbData parameter is also NULL. The virtual device should initially set iValue to zero, then increment it on successive calls. LDR_RegOpenKey DWORD LDR_RegOpenKey(HKEY hKey, LPSTR lpszSubKey, LPHKEY lphKey) Open the registry key for the given registry path. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or is the HKEY_LOCAL_MACHINE key. lpszSubKey Address of a null-terminated string specifying the subkey to open. May be NULL or point a Null-string. lphKey Address of a variable that receives the handle to the open key. LDR_RegQueryValue DWORD LDR_RegQueryValue(HKEY hKey, LPSTR lpszSubKey, LPBYTE lpbData, LPDWORD lpcbData) Retrieves the value for the given registry key. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or is the HKEY_LOCAL_MACHINE key. lpszSubKey Address of a null-terminated string specifying the subkey to retrieve the value from. Can be NULL or point to a NULL-string. lpbData Address of a buffer that receives the value data for given registry key. lpcbData Address of a 43-bit variable that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved data. LDR_RegQueryValueEx DWORD LDR_RegQueryValueEx(HKEY hKey, LPSTR lpszValueName, LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData) Retrieves the value for the given registry key for the given value name. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if successful; otherwise, one of the error values given in Constants later in this chapter. hKey Handle of a previously opened key or is the HKEY_LOCAL_MACHINE key. lpszValueName Address of a null-terminated string specifying the value name for which to retrieve value data. Can be NULL or point to a NULL-string. lpdwReserved Reserved; set to NULL. lpdwType Address of a 32-bit variable that receives the data type for the value. Can be NULL if data type is not needed. lpbData Address of a buffer that receives the value data for given value name. lpcbData Address of a 32-bit variable that contains the size, in bytes, of the lpbData buffer. This variable receives the size, in bytes, of the retrieved data. Constants This section describes the constants used with the registry services. Predefined Keys HKEY_LOCAL_MACHINEContains information about the hardware and software on the computer.HKEY_USERSContains information about the users of the computer. In particular, this contains any user-specific information associated with hardware or software is stored.HKEY_CURRENT_USERContains information about the current user. This is mapped to the default user branch under the HKEY_USERS key.HKEY_CURRENT_CONFIGContains information about the hardware configuration of the computer. This typically HKEY_CLASSES_ROOTContains information about OLE classes.HKEY_PERFORMANCE_DATAContains information about system performance.HKEY_DYN_DATAContains information about dynamic data. Registry Value Types REG_SZNull-terminated stringREG_BINARYBinary data consisting of a specified number of bytes.All other typesValid, but treated as binary internally. Error Values ERROR_SUCCESSCompleted successfully.ERROR_CANNOT_OPEN_REGFILECannot find the required registry hive file or possibly the file is kept open by another application.ERROR_INSUFFICIENT_MEMORYNot enough memory to open this registry key or not enough memory to load the required data from the registry file, or the given buffer is not enough to hold the data.ERROR_INVALID_PARAMETERlpszDevName is an invalid address, or dwFlags is incorrect.ERROR_REGFILE_READERRORError reading the registry file. Possibly, the file is corrupt.ERROR_REGFILE_WRITEERRORError writing the registry file. Possibly, the file is corrupt.ERROR_REGKEY_INVALIDKEYThe lpszSubKey string contains an invalid character or the given hKey is invalid.ERROR_FILE_NOT_FOUNDNo more subkeys, or the key specified is not found in the registry database.ERROR_VALUE_NOT_FOUNDNo more values to enumerate, or the given value name is not present for the given registry key. chapter SEQ CHAPTER \R 1010 Multifunction Plug and Play Hardware About Multifunction Plug and Play Hardware This chapter describes how multifunction devices get installed and configured by the Windows 95 Plug and Play architecture. Multifunction devices are physical devices which incorporate multiple logical devices. For example a board incorporating a SCSI controller and a sound chip is considered a multifunction device, a DSP board that can behave as a modem, a sound device or both is considered a multifunction device as well. The following devices/scenarios are covered: SYMBOL 183 \f "Symbol" PNP - Multiple logical devices on a single board consuming non-overlapping resources. (Resources refers to use of IRQs, I/O ranges, memory ranges, or DMA channels.) SYMBOL 183 \f "Symbol" PNP - Multiple logical devices on a single board consuming overlapping resources SYMBOL 183 \f "Symbol" PNP - Multiple devices incorporated in a parent/daughter card configuration SYMBOL 183 \f "Symbol" PNP - Multiple devices incorporated in a master/slave configuration via a proprietary bus SYMBOL 183 \f "Symbol" PNP - A multi-personality board (eg. a DSP with multiple functions but only one available at a time) SYMBOL 183 \f "Symbol" Legacy multifunction devices This chapter assumes the reader is familiar with the Windows 95 Plug and Play architecture and the relevant chapters in the Windows 95 Device Driver Development Kit (DDK). One of the most important aspects of installing and configuring a multifunction card is having a proper INF file. The Beta 2 INF format has been extended to support the different flavors of multifunction cards. Sample INF files are included in this document. Considerations for Logical Grouping of Devices Note that many audio devices have dependencies which fall outside of the normal hardware resource sharing idiom, that is, IRQ, I/O, DMA, or memory ranges. For example, FM synthesizer chips often have an internal dependency on the mixer device of the card. In this example the devices should not be treated as separate logical device even though functionally they are somewhat independent of each other. Other considerations for how to logically group the devices of a multifunction board: SYMBOL 183 \f "Symbol" Functionally independent but tightly coupled devices Example: An audio card that includes an FM synthesizer and a digital audio (wave) playback device both connected to a mixer device. Although these devices are somewhat functionally independent, they still have important interconnections. There must be a way to associate the synthesizer, wave, and mixer devices with each other. If such an association cannot be made, then an application would not, for example, be able to determine which mixer device to utilize in order to alter the audio being produced by a given synthesizer device. In some cases, this association cannot be accomplished in a bus-independent manner. By grouping the resources of all the devices as a single logical device (with a single devnode) the association can be made more easily. SYMBOL 183 \f "Symbol" Devices providing compatibility modes Example: An audio card that provides Sound Blaster compatibility. However, the device can only operate in compatibility mode or native mode, but not both simultaneously. Such a device would typically implement two register planes (one native and a second compatibility plane for Sound Blaster emulation) which are connected to a single DAC/ADC. Obviously these register planes are not functionally independent, they are in fact mutually exclusive. The device should not be designed as two logical devices (one using a native PNP ID and another using the Sound Blaster PNP ID). Instead, to properly handle this case, a single devnode should be created containing all required resources including both the native registers and the Sound Blaster compatible registers. The supporting drivers must handle the hardware contention between the separate register sets at the I/O level. Multiple Logical Devices - non-overlapping resources This is the most common flavor of multifunction cards and the one recommended for full Windows 95 Plug and Play compatibility. The Plug and Play ISA specification and the PCI specifications define a standard way for identifying and configuring the various logical devices on a given physical board. The logical devices included in these boards must be functionally independent, electrically isolated, consume different resources and are treated as separate devices with independent INFs and drivers. For example a display adapter that has video acceleration functions on a separate chip will specify two separate logical devices with distinct device IDs. Each logical device will be supported by a dedicated driver. The two drivers may interact among themselves via a private interface. Multiple Logical Devices - overlapping resources If the logical devices must share certain resources such as memory or I/O regions, one of the logical devices may claim the shared resources for the others and make them available through a private interface. This will also ensure that proper initialization and clean-up is not impacted by driver load sequence. For example, a display adapter with built-in MPEG support will specify two logical devices. The display device will claim the frame buffer which is shared by both devices and make it available to the MPEG driver via a private interface. If the frame buffer is accessed via a dedicated port which is used only by the MPEG driver, that port should be claimed by the MPEG device. This will ensure the port is available to other devices if the MPEG device is disabled for some reason. If there are multiple drivers accessing the shared memory regions through the same ports, those ports should be claimed by the display device and made available to the other drivers through a private interface. Multiple Logical Devices - parent/daughter card configuration In this case some logical devices may not be always physically present on the parent board at all time. The recommended Plug and Play solution is to tie the device information and configuration logic to the presence of the daughter card. This will enable Windows 95 to correctly enumerate and configure the devices when they are present. If this is not possible, another alternative is to always report all the possible logical devices. Windows 95 will install all these devices and configure them. This will require the board vendor to provide device drivers and INF files for all the possible devices. The drivers will be loaded by Windows 95 at boot time. If the driver(s) for the daughter card device(s) don't find their respective devices they can return DEVICE_NOT_THERE to the configuration manager. This will enable the configuration manager to re-use the resources the daughtercard would ordinarily require. When the daughter card is plugged in, the drivers will initialize successfully and retain their assigned resources. If installing all the drivers is not possible, the user will be forced to select "don't use device" for each of the missing logical devices. In this case, when the daughter card is added to the system, the user will need to re-enable the daughter card's logical devices via the device manager. See the next section for discussion on the case in which the driver for the parent card needs to be replaced when the daughter card is added. Multiple logical devices - master/slave card configuration This case is similar to the parent/daughter card configuration. The main difference is the ability to off-load the enumeration and configuration responsibility from the parent to the slave in this case. If the slave card is not present Windows 95 will not enumerate it and the drivers won't be installed or loaded for the card. When the slave card is installed it will be detected by one of the Windows 95 enumerators and its drivers will be installed. The responsibility for establishing the communication between the master and slave card will typically lie on the master card. This poses an interesting problem: the master card may be driven by a default Windows 95 driver which doesn't have the enumeration/communication capabilities for the bus that's connecting the two boards. For example a display adapter with a VESA Media Channel (VMC) on board may work perfectly fine with a generic display driver. But when the slave card is installed the driver for the parent card needs to be replaced with a VMC aware driver so it can communicate with the slave. Currently there is no method to accommodate this scenario unless the display driver is already VMC aware. Legacy multifunction devices Windows 95 provides a mechanism which allows mapping a single physical device to multiple logical devices even when the appropriate identification and configuration structures are missing or lacking. In this case the Windows 95 configuration manager creates the various logical devices based on information included in the INF file of the physical device. The class for these cards is defined in the INF as "Multifunction" and the Ids and the specific driver and configuration information for each of the logical devices is included in the INF as well. When Windows 95 detects a "multifunction" device it will install each of the logical devices listed in the INF separately, then enumerate each of them every boot or whenever the physical device is plugged in (in the case of hot plug-able devices). The following section describes the structure of the INF file for multifunction devices and provides an example of a multifunction PCMCIA card. Multifunction Legacy Devices - Registry A legacy multifunction card is enumerated by the relevant Windows 95 enumerator as a single device with all resources allocated to that device. When a legacy multifunction card is detected, the configuration manager will act as the default enumerator for its children (the logical devices on the device). This is depicted in the registry by listing CONFIGMG as the enumerator and device loader for child devices. The following example shows how a multifunction sound/SCSI card will appear in the registry: [HKEY_LOCAL_MACHINE\Enum\Root\ACM1234\0000] InfName=ACMAMF.INF DeviceDesc=ACMA Audio card with SCSI Class=MEDIA HardwareID=ACM1234 Driver=MEDIA\0000 Mfg=ACMA Corp. ConfigFlags=hex:00,00,00,00 [HKEY_LOCAL_MACHINE\Enum\Root\ACM1234\0000\LogConfig] 0= 1= [HKEY_LOCAL_MACHINE\Enum\Root\ACM1234\0000\Child0000] HardwareID=MF\ACM1234_Dev0 ResourceMap=hex:00,01,02,03,04,05,06,07,0c,0e [HKEY_LOCAL_MACHINE\Enum\Root\ACM1234\0000\Child0001] HardwareID=MF\ACM1234_Dev1 ResourceMap=hex:01,05,06,08,09,0a,0b,0d In the above example a legacy multifunction card by ACMA has two child devices. The driver branch for the parent device MEDIA\0000 includes information about the parent driver which may be used for initialization\configuration of the physical card as well as coordination between the children. The child branches include information about the simulated hardware Ids and indexes of the parent's logical configurations. [HKEY_LOCAL_MACHINE\Enum\MF\CHILD0000\ROOT&ACM1234&0000] HardwareID=MF\ACM1234_Dev0 Class=MEDIA Driver=MEDIA\0001 Mfg=ACMA Corp. DeviceDesc= ACMA Audio card with SCSI (Audio) ConfigFlags=hex:00,00,00,00 [HKEY_LOCAL_MACHINE\Enum\MF\CHILD0001\ROOT&ACM1234&0000] HardwareID=MF\ACM1234_Dev1 Class=SCSIAdapter Driver=SCSIAdapter\0000 Mfg=ACMA Corp. DeviceDesc= ACMA Audio card with SCSI (SCSI) ConfigFlags=hex:00,00,00,00 The device information of the child devices is kept under the Enum\MF (for multifunction). Beside the location, these entries look exactly the same as standard single function device entries. Each of the devices specifies an independent device class and device descriptions. [HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class\MEDIA\0000] DevLoader=*CONFIGMG Enumerator=*CONFIGMG DeviceDriver=acma.vxd InfPath=ACMAMF.INF InfSection=ACM1234_Device DriverDesc= ACMA Audio card with SCSI [HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class\MEDIA\0001] DevLoader=mmdevldr.vxd Driver=acmaudio.vxd InfPath=ACMAUDIO.INF InfSection=ACM1234_Dev0_Device DriverDesc= ACMA Audio card with SCSI (Audio) [HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class\SCSIAdapter\0000] DevLoader=*IOS PortDriver=acma.mpd InfPath=ACMASCSI.INF InfSection= acm1234.drv DriverDesc= ACMA Audio card with SCSI (SCSI) The device loader and enumerator for the multifunction parent is CONFIGMG. The driver itself is provided by the vendor for initialization and coordination purposes. Multifunction Legacy Devices - INF definition The new information in the registry will be communicated via the INF file. During installation, the device installer will install not only the section pointed at by the section name in a device line but will also look for a section, named InstallSection.MF and will execute this section too. The device personalities will be installed through separate INFs. This is because an INF can only contain descriptions of a single class and the device personalities will be of multiple classes. [InstallSection.MF] This is a standard installation section except that Addreg relative (HKR) commands will refer to the Hardware branch. In this section, the ChildList can be generated as well as the resource map. Resource Map This entry in the INF is used in the [InstallSection.mf] section. When installing an EISA Multifunction Card, the resources are not really assigned to the parent board but rather to the independent functions. The EISA enumerator, however, reports only the parent device and reports all resources as belonging to the common parent. This section will tell the configuration manager how to divide the parent resource between the children. the resource map is a binary format record added using an addreg command, where each byte represents the ordinal of the EISA resource record belonging to the child. This is not a bitmap, it is a list of ordinals. There is a limit of 256 EISA ordinal values. HKR,,ResourceMap,,1,01,04,26 Child List This entry is a text entry that, like the resource map, is added via the addreg command from an [InstallSection.MF] section. These entries cause the configuration manager to create devnodes for every logical device contained in the child list. Configuration Manager, enumerates these devices. The INF entry would look like the example below. HKR,ChildList,LogicalDeviceID1,,CompatibilityIDList PCMCIA Multifunction Card Example The following example shows the main INF file for a multifunction modem\network PCMCIA card. The child INFs are not shown since they are not different than standard single function device INFs. INF File [Version] LayoutFile=layout.inf Signature="$WINDOWS 95$" Provider=%MS% Class=MultiFunction ; ; Table of Contents ; [Manufacturer] %CARDWIZ%=CARDWIZ [CARDWIZ] %CARDWIZ10BT%=CARDWIZ10BT.mf,PCMCIA\CARDWIZ-CREDITCARD_ETHERNET+MODEM_10BASE-T-XXXX2 [CARDWIZ10BT.mf] AddReg=StandardMF.Reg,ADDREG_CARDWIZ.reg [CARDWIZ10BT.mf.HW] AddReg=CARDWIZ10BT.mf.RegHW [CARDWIZ10BT.mf.RegHW] HKR,Child0000,HardwareID,,MF\CARDWIZCEM_DEV0 HKR,Child0000,ResourceMap,1,00,01,02,04 HKR,Child0001,HardwareID,,MF\CARDWIZCEM_DEV1 HKR,Child0001,ResourceMap,1,01,02,03,04 [StandardMF.Reg] HKR,,DevLoader,,*CONFIGMG HKR,,Enumerator,,*CONFIGMG HKR,,CMDrivFlags,01,03,00,00,00 ; Sets flags as described ; in CM_Register_DeviceDriver call ; Mark device as ; Can be removed ; Can be configured [ADDREG_CARDWIZ.reg] HKR,Override,0000,1, \ ; ; CONFIGMG_VERSION ; 00,04,00,00, \ ; ; PRIORITY ; 00,00,00,00, \ ; ; I/O Resource Descriptor 0 ; <> ; ; I/O Resource Descriptor 1 ; <> ; ; IRQ Resource Descriptor ; <> ; ; MEM Resource Descriptor 0 ; <> ; ; MEM Resource Descriptor 1 ; <> ; ; REQUEST_CONFIG_PKT Descriptor ; <> ; ; TERMINATOR ; 00,00,00,00 ; ; Translatable strings ; [Strings] MS="Microsoft" ; ; Manufacturer names ; CARDWIZ="Cardwiz" ; Adapter names ; CARDWIZ10BT="Cardwiz CreditCard Ethernet+Modem 10Base-T" The calculation of this checksum is described in the PCMCIA section of the DDK. A tool called DTPL.EXE is provided to help card developers create device Ids and configuration information for their cards. Chapter SEQ CHAPTER \R 1111 Dynamic Registry Keys in Windows 95 Introduction The Registry has become the central repository for all the configuration information in the Microsoft 32 bit operating systems. Both Windows NT and Windows 95 store configuration information for hardware and software components in the registry. The Windows 95 registry supports both static data and dynamic data. A static value is one that is actually stored within the registry on disk. Dynamic data is data that changes very often, such as performance data. It is not practical to store such data in the registry; it would obviously not be a good idea for the system to continually update the registry with current values. Thus, a different mechanism was designed to support dynamic data. Note Windows NT 3.5 supports dynamic data differently than Windows 95. Windows NT 3.5 uses Volatile keys, which Windows 95 does not support. Dynamic keys were introduced in Windows 95 to handle dynamic registry data. Rather than storing the actual values, the registry stores a pointer to a function that returns a value or values. When a registry call is made to query a value or values associated with a dynamic key, that function is called to return the desired value(s). From the point of view of the consumer of registry data (the caller of the registry APIs), dynamic keys appear and behave like any other keys in registry name space (except that they are read-only). Overview Each dynamic key has a provider (also called handler) associated with it. A provider is a piece of code that, when requested by the OS registry code, provides one or more values that are associated with that dynamic key. Windows 95 supports only VxD providers. Future versions of Windows will support Win32 providers as well. Windows NT does not support either VxD or Win32 dynamic key providers, but will in future versions. The ring 0 for Windows NT will be different than the Windows 95 VxD interface. However, the Win32 interface should be the same for future versions of Windows 95 and Windows NT. Note This document describes only the Windows 95 VxD interface for dynamic keys. Following are some issues that implementors of dynamic keys should be aware of: SYMBOL 183 \f "Symbol" All dynamic keys are stored under the HKEY_DYN_DATA registry hive. Thus, all child keys of dynamic keys must also be dynamic. SYMBOL 183 \f "Symbol" Dynamic keys are not restored across boots. If HKEY_DYN_DATA is unloaded, all dynamic keys in it are deleted. SYMBOL 183 \f "Symbol" One provider manages all of the values under one dynamic key. SYMBOL 183 \f "Symbol" One provider can manage multiple dynamic keys. SYMBOL 183 \f "Symbol" Values of a dynamic key cannot be added or deleted dynamically. In order to add (or delete) values from a dynamic key, the key must be deleted and recreated with the new set of values. SYMBOL 183 \f "Symbol" The value lengths can be maintained either by the provider or by the registry code. If the value lengths are maintained by the system Registry code, they need to be passed into the system when the key is created. SYMBOL 183 \f "Symbol" Dynamic keys are typically created by the VxD provider at VxD initialization time. They cannot be created until Init_Complete. A single provider handles multiple keys and/or values via the notion of a context. A context is just a 32-bit value that is meaningful only to the provider; the system registry code never tries to evaluate it. When the provider is called, it can examine the key context that was passed in to determine which key is being queried, and the value context to figure out which value is being queried. Thus the key context is only necessary when one provider function is handling multiple dynamic keys. Likewise, the value context is only needed when the same provider function is handling a key or keys with multiple values. There is an additional Win32 registry API that has been defined in Windows 95, in part to support dynamic keys, called RegQueryMultipleValues. This allows an application to atomically query multiple values of one registry key. Please consult the Win32 documentation for more information about this API. RegCreateDynamicKey When a component wants to add a dynamic key to the Registry namespace, it calls the RegCreateDynamicKey VxD service. Notes 1. Dynamic keys are like volatile keys in that they disappear when the hive they are in is unloaded 2. Providers have no knowledge of the sub-keys under their dynamic keys. They just provide data for their key/values 3. RegNotifyChangeKeyValue will return ERROR_NOT_SUPPORTED when called against a dynamic key 4. For dynamic keys, the lastWriteTime parameter in RegQueryInfoKey returns the time when the key was created Sample code In this example, the provider handles one dynamic key, under which there are 2 values. This provider will handle both values. The provider is keeping track of the value lengths instead of the registry. Note there is a static number (2) of values under this dynamic key. If the number of values under a dynamic key will change, then the key must be deleted and readded in order to do so. The path of the dynamic key in this example is HKEY_DYN_DATA\Keyname1\Keyname2. There are two values under this key. One value is called First Valuename, and the other is called Second Valuename. /***************************************************************************** * * (C) Copyright MICROSOFT Corp., 1994-1995 * *****************************************************************************/ #include #include #include #define MODULE_NAME Dynamic Keys example #define LEN 100 #define DYNKEY_PATH "Keyname1\\Keyname2" // This path is passed to RegCreateDynKey. // The registry will create Keyname1 (if it does not exist) and Keyname2; the provider // will only be queried for values under Keyname2. #define REGVAL_DATA1 "First Valuename" #define REGVAL_DATA2 "Second Valuename" #pragma VxD_PAGEABLE_CODE_SEG #pragma VxD_PAGEABLE_DATA_SEG // Structure for registry value context pointers. // This allows us to return data quickly for our dynamic registry key. // NOTE: This structure is being used as the value context because this sample has values with varying lengths. If this were not the case, we would set PROVIDER_KEEPS_VALUE_LENGTH, and then we could use the value pointer itself as the value context. typedef struct { PVOID pData; // Pointer to the data PUINT pcbData; // Pointer to the size of the data } REGVAL_CONTEXT, *PREGVAL_CONTEXT; DWORD fData1; DWORD cbfData1 = sizeof(fData1); char szData2[LEN + 1]; unsigned cbData2; // Assign values to data1 and data2. These are of course not normally static values - they would change // dynamically in your code. However, they are being set here in order to complete this example. fData1= 100; szData2 = This is the string for the second value; // declarations used below const REGVAL_CONTEXT rvcData1 = {&fData1, &cbfData1}; const REGVAL_CONTEXT rvcData2 = {szData2, &cbData2}; // RegKeyHandler - The handler function that must be defined in your VxD VMMREGRET __cdecl RegKeyHandler( PVOID pvKeyContext, PVALCONTEXT pValueContext, DWORD cValueContext, PBYTE pbBuffer, DWORD *pcbBuffer, DWORD fFlags) { VMMREGRET status = 0; PVALCONTEXT pvcCurrent; DWORD cbBufRemaining; // Save the input buffer size and initialize the return buffer size assert(pcbBuffer != NULL); cbBufRemaining = *pcbBuffer; *pcbBuffer = 0; // Since this function handles only one key, the key context is unused assert(pvKeyContext == NULL); // Walk the list of requested values, filling them in the buffer if // there's room. for (pvcCurrent = pValueContext; cValueContext > 0; pvcCurrent++, cValueContext--) { PREGVAL_CONTEXT prvcCurrent = pvcCurrent->value_context; pvcCurrent->valuelen = *prvcCurrent->pcbData; if (cbBufRemaining >= (DWORD) pvcCurrent->valuelen) { // value fits, copy it in memcpy(pbBuffer, prvcCurrent->pData, pvcCurrent->valuelen); *pcbBuffer += pvcCurrent->valuelen; pvcCurrent->val_buff_ptr = pbBuffer; ((PBYTE) pbBuffer) += pvcCurrent->valuelen; cbBufRemaining -= pvcCurrent->valuelen; } else { pvcCurrent->val_buff_ptr = NULL; status = ERROR_MORE_DATA; } } return status; } // *** Init code and data is below here *** #pragma VxD_INIT_CODE_SEG #pragma VxD_INIT_DATA_SEG // This structure is used as the 3rd parameter to RegCreateDynKey struct provider_info RegKeyHandlerInfo = { RegKeyHandler, // pointer to the VxD handler function for query of one value RegKeyHandler, // pointer to the VxD handler function for query of multiple values NULL, // Should be NULL for Win95; reserved for future pointer to Win32 handler fn NULL, // Should be NULL for Win95; reserved for future pointer to Win32 handler fn PROVIDER_KEEPS_VALUE_LENGTH, // Provider will keep track of value lengths NULL // Key context; not used in this example since handler only manages 1 key }; // A Pvalue struct that is passed as 4th parameter to RegCreateDynKey PVALUE RegKeyValueInfo[] = { {REGVAL_DATA1, sizeof(DWORD), (PVOID) &rvcData1, REG_BINARY}, {REGVAL_DATA2, 0, (PVOID) &rvcData2, REG_SZ}, }; #define RegKeyValueCount (sizeof(RegKeyValueInfo) / sizeof(*RegKeyValueInfo)) int __stdcall CreateDynamicKey(void) { // Note: We never delete the key VMMHKEY hkeyDynamicConfig; int uStatus; cbData2 = strlen(szData2) + 1; if (uStatus = _RegCreateDynKey(DYNKEY_PATH, NULL, // No key context is needed &RegKeyHandlerInfo, RegKeyValueInfo, RegKeyValueCount, &hkeyDynamicConfig)) { #ifdef DEBUG Out_Debug_String(MODULE_NAME ": Cannot create dynamic registry key " DYNKEY_PATH "\r\n"); #endif return uStatus; } // We're never going to use this key, so we can close it // BUG - The dyn-key code relies on this being kept open, so we leave it open //_RegCloseKey(hkeyDynamicConfig); return 0; } Reference Functions _RegCreateDynKey VMMREGRET _RegCreateDynKey (PCHAR lpszSubKey, PVOID pvKeyContext, PPROVIDER pprovHandlerInfo, PPVALUE ppvalueValueInfo, DWORD cpvalueValueInfo, PVMMHKEY phkResult); Creates a dynamic key. It is defined in VXDWRAPS.H. This function makes copies of pprovKeyHandlerInfo and ppvalueValueInfo. SYMBOL 183 \f "Symbol" Returns ERROR_SUCCESS if the function succeeds; otherwise returns one of the error values which can be returned by RegCreateKeyEx. In addition if the key already exists the function will return ERROR_REGISTRY_CANNOT_CREATE. lpszSubKey Pointer to the name of key to be created. The name is relative to HKEY_DYN_DATA. For example, suppose the new dynamic key will be HKEY_DYN_DATA\Keyname1\Keyname2. Then lpszSubKey=Keyname1\\Keyname2. The registry will create Keyname1 if it does not exist, and Keyname2. The provider will only be queried for values under the lowest level key (Keyname2). pvKeyContext The key context. This is a 32-bit value that is only meaningful to the provider. It is only necessary when the same provider is handling multiple dynamic keys. If the provider is only going to handle one dynamic key, then this parameter can be NULL. pprovHandlerInfo A pointer to a provider_info structure. ppvalueValueInfo An array of Pvalue structures. There must be one structure for each value under the dynamic key to be created. cpvalueValueInfo The number of structures in the ppvalueValueInfo array, which is equal to the number of values under this dynamic key. phkResult Pointer in which the function will return the open handle of the newly created dynamic key. PQUERYHANDLER typedef VMMREGRET (_cdecl *PQUERYHANDLER)(PVOID pvKeyContext, PVALCONTEXT pvalcontextValues, DWORD cvalcontextValues, PBYTE pbData, DWORD* pcbData, DWORD dwReserved); This is the type definition for the provider, or handler function. pvKeyContext This is the key context; it is an input paramater that lets the provider know which key is being queried, if this handler function handles multiple keys. pvalcontextValues This is an array of val_context structures; one structure per value. Parts of the val_context structure are input parameters, and parts are output parameters - please see the comments for the val_context structure. cvalcontextValues This is the number of val_context structures in the array of the previous argument; it is an input parameter. pbData This is a buffer, supplied by the registry to the provider, in which the provider stores the value or values that are queried. If the registry is keeping track of the value lengths, this buffer should always be large enough. pcbData A pointer to the length of the above buffer. On input, it contains the size of the available buffer. On output, it should contain the size of the buffer that is actually used / filled. dwReserved Reserved. Structures These are defined in vmmreg.h in the DDK. PVALUE #define PROVIDER_KEEPS_VALUE_LENGTH 0x1 typedef struct pvalue { PCHAR pv_valuename; // The value name pointer DWORD pv_valuelen; // The length of the value in bytes. PVOID pv_value_context; // The context for this value DWORD pv_type; // Registry type of this vallue. } PVALUE; typedef struct pvalue *PPVALUE; An array of these structures is passed to RegCreateDynKey, one structure per value under that key. pv_valuename The name of the value. The provider must fill this in when it calls _RegCreateDynKey. pv_valuelen The length (in bytes) of the value. If the registry is keeping value lengths, then this must be filled in by the provider when it calls _RegCreateDynKey. pv_value_context The value-context. This is a 32-bit value that is only meaningful to the provider; it is never evaluated by the registry code. This is a value in some way uniquely identifies this particular value so that when the provider is called, it knows which value is being queried. This is what enables one provider to handle multiple values. The provider must fill this in when it calls _RegCreateDynKey. pv_type The registry type of this value. In Windows 95, this can be REG_BINARY or REG_SZ. The provider must fill this in when it calls _RegCreateDynKey. PROVIDER typedef struct provider_info { PQUERYHANDLER pi_R0_1val; // pointer to VxD handler // single value PQUERYHANDLER pi_R0_allvals; // pointer to VxD handler, // multiple values PQUERYHANDLER pi_R3_1val; // Should be NULL in Win95 PQUERYHANDLER pi_R3_allvals; // Should be NULL in Win95 DWORD pi_flags; // capability flags } PROVIDER; typedef PROVIDER *PPROVIDER; This structure must be passed as parameter to _RegCreateDynKey pi_R0_1val Pointer to the VxD handler function that should be called when this dynamic key is queried for one of its values. The provider must fill this in when it calls _RegCreateDynKey. pi_R0_allvals Pointer to the VxD handler function that should be called when the dynamic key is queried for all of its values (via RegQueryMultipleValues). If the handler function does not support multiple values, this should be set to NULL. In this case the registry code calls pi_R0_1val repeatedly, once for each value, when RegQueryMultipleValues is called for this key. Having this handler is useful in the case where the key is being queried remotely, because this would reduce the number of Remote Procedure Calls. The provider must fill this in when it calls _RegCreateDynKey (if it has a handler that responds to a query of multiple values). pi_R3_1val Win32 providers are not supported in Windows 95. This should be NULL. pi_R3_allvals Win32 providers are not supported in Windows 95. This should be NULL. pi_flags Capability flags. These are used to tell the registry code whether the provider is handling certain kinds of housekeeping, or whether the registry code should do this housekeeping. Currently, there is one such flag: PROVIDER_KEEPS_VALUE_LENGTH. If this flag is set, then the provider has the responsibility for maintaining and providing the value length when needed. If it is not set, then the registry code keeps track of the value lengths. This flag is useful if the value lengths are not static. If any of the value lengths can change dynamically, then the provider must do the work of keeping the value lengths. Note this flag is per-key, not per-value. val_context struct val_context { int valuelen; // the total length of this value PVOID value_context; // the value context PVOID val_buff_ptr; // where in the ouput buffer the value is. }; typedef struct val_context *PVALCONTEXT; An array of these structures is passed to the handler function. There is one structure for each value. This structure should not be confused with a value_context, which is one of the fields in this structure. valuelen The length of the value. It includes the null terminating character for strings. If the provider keeps value lengths, then this needs to be filled in by the provider in the handler function. (It is sometimes an output parameter). value_context The value context for this value - the 32-bit value that is meaningful only to the provider. It is provided to the handler function by the registry code (it is an input parameter) val_buff_ptr A pointer to the place in the buffer where the value is. It must be filled by the provider in the handler function. (It is an output parameter) PAGEi Introduction Introduction PAGEi PAGEi PAGEiv Plug and Play Drivers styleref CnChapter 1 styleref ChPlug and Play Introduction PAGEv PAGEii PAGE1 Plug and Play Drivers styleref CnChapter 2 styleref ChPlug and Play Device Drivers PAGE1 PAGE1 PAGE1 Plug and Play Drivers styleref CnChapter 3 styleref ChConfiguration Manager PAGE1 PAGE1 PAGE1 Plug and Play Drivers styleref CnChapter 4 styleref ChPlug and Play and PCMCIA PAGE1 PAGE1 PAGE1 Plug and Play Drivers styleref CnChapter 5 styleref ChPlug and Play Installation PAGE1 PAGE1 PAGE1 Plug and Play Drivers styleref CnChapter 6 styleref ChDevice Information Files PAGE1 PAGE1 PAGE1 Plug and Play Drivers styleref CnChapter 7 styleref ChProperty Page Providers PAGE1 PAGE1 PAGE1 Plug and Play Drivers styleref CnChapter 8 styleref ChDevice Registry Keys and Values PAGE1 PAGE1 PAGE1 Plug and Play Drivers styleref CnChapter 9 styleref ChRegistry Services PAGE1 PAGE1 PAGE1 Part 1 Part Head Chapter 1 Chapter Head PAGE1 PAGE1 PAGE1 Plug and Play Drivers styleref CnChapter 11 styleref ChDynamic Registry Keys in Windows 95 PAGE1 PAGE1 !7h T!7h T!7h T!7h T!7h T!7h T!7h T!7h T!7h Tࡱ!7h T!7h T!7h T pi":vC7?&2 .     --$:i ik:i---%:i ik:i- --$:i:=---%:i:=- --$:i i =:=:i---%:i i =:=:i-( ArialF-"System- . -!Configuration Managerf- --$:8 8k:8---%:8 8k:8- --$:8: W---%:8: W- --$:8 8  : :8---%:8 8  : :8--% Arial/F-- . - ! Bus Driver\-!(e.g. ISAPNP.VXD)!- --%- - - --%-i-i- --%- - - --%- - - --%-i-i- --$:  k  : ---%:  k  : - --$ : : ---% : : - --$:  :: ---%:  :: -  ArialE- ArialE- ArialH----- . -!HKEY_LOCAL_MACHINEA-!c! > A! > g-!ENUM> -!> R ! A ! Root  ! BIOS A ! ISAPNP. A! TCM1234~ A! 0000 A! LogConfig A ! n A- !SYSTEMn -!n ! CurrentControlSet A! Services A! Class^ A! ... A! - 0 Arial- - . - ! Registry:W - - -$E( Es E- -- %E( Es E-  - -$ED- -- %ED-  - -$E( E( E- -- %E( E( E-  -- %  % % %/ %/ p % % % p % % %  % % %  % % %  % % % -  -- %/ / Q %/ Q[Q[ %/ Q) Q)  %/ Q/ Q/  %/ Q/ Q/  %/ Q/ Q/  %/ Q/ Q/ -  - -$t   pt pt - -- %t   pt pt - -- . - !PnP BIOS - - -$z 2<2<z z 2- -- %z 2<2<z z 2- -- . - ! ISAPNP Bus - - -$U bb}U }U - -- %U bb}U }U - -- . - ! Network card - - -$`   p` p` - -- %`   p` p` - -- . -!Legacy Sound Card - - -$m 2 2 m m 2- -- %m 2 2 m m 2- -- . - !SCSI Bus - - -$     - -- %     - -- . - ! Root Devnode~. - --  %[2[X[X[}-  - - . - ! Hardware Tree( - - -$:W:8(  W:W- -- %:W:8(  W:W- -- . - !Step 3:G!Build Device Nodes- - -$B i( is  B i- -- %B i( is  B i-  - -$ B iB =  - -- % B iB =  -  - -$B i( i( =B =B i- -- %B i( i( =B =B i- --- . -!Net Card Driver -!(e.g.somemac.vxd) ! - - -$::i( =:- -- %::i( =:- -- . - !Step 4:G!Load device driver- - -$ x-i- xx- -- % x-i- xx-  ArialE- - . - !Step 1:%!Enumerate Bussesi- - -$ x-8EE-ExEx- -- % x-8EE-ExEx- - - . - !Step 2:!Get device infoDi-0/W[NA :(!>4 Z  9 &MrEdMicrosoft DrawZ&MrEd System)_  &MrEd   l   &MrEd- "-&MrEdO Y\ L&MrEd  ."Arial-2  Application 12 X Application 22  Application 3&MrEd%  "&MrEd DG  & MrEd%I.2 Configuration Manager2  Hardware-tree&MrEd CF  2 Registry&MrEdT-W&MrEd!-$&MrEdyJ-Mv&MrEd-2 Socket Services & MrEd%I & MrEd%D & MrEd%LIh &MrEdV-Y2 , Card Services2 PC 2 \Card&MrEd -2 dPC 2 \LCard&F &MrEdN - K2 > Plug and Play2  Device Driver & & &MrEd  2  Plug and Play2 \ Device Driver & & 2 8 PCMCIA Bus 2  Enumerator & &) 2 8)Resource 2 ) Arbitrator & &U&MrEd]-Z 2 Resource 2 y Arbitrator & "System- 2  Windows 95"Systemn- "--'' &yn :/6O [Z   &MrEdMicrosoft DrawZ&MrEdnn  System)_  &MrEd_ 9 _    &MrEdg Q- "-T d&MrEdX  U & MrEd%R."Arial- 2  ConfigMan 2 gH/W-tree 2 Registry&MrEdZ-]&MrEd    &MrEd4ru1 2 4 PCMCIA Bus2 :Socket Services & MrEd% a&MrEda[^^2 " Card Services&MrEd }   2 " Card Services Client & MrEd% X  & MrEd%[ &MrEd: 7 2 mCardDRV & MrEd%\\&MrEdZ-] 2 PFlash FS & MrEd%t & MrEd%[4&MrEdM1-4J & MrEd%[ &MrEdgR-Ud 2 File 2 System & MrEd%R&MrEd M 1-4 J  2  Static & MrEd% K2 ac Plug and Play2 c Device Driver2 z Plug and Play2 ' Card Services Client 2 >4 Enumerator2 +Flash or SRAM MTDs & MrEd%_G"System- 2  Windows 95"Systemn- "--'' 3 :43M@ 'Z   &MrEdMicrosoft DrawZ&MrEd@ System)_  &MrEdh  h  "   &MrEd-- ."Arial-- 2 ROOT&MrEd84."Arial*- 2 PKeyboard&MrEd     2 JG Display&MrEd 2 zSerial&MrEdH L  2 zParallel & MrEd%r  & MrEd%  & MrEd%P  &MrEdh  pt |d ."Arial-- 2  ISA Bus&MrEdh r  b f n d  2 D ( SCSI &MrEd R  V ."Arial- 2 v Hard-Disk&MrEd   2 v CD-ROM & MrEd% b & MrEd%N b &MrEdF   B  2 z PIC&MrEd   2 z DMA & MrEd%   & MrEd%  &MrEdpl2 t3IO 2  Controller&MrEd | 2 M Controller & MrEd%l &MrEds |w ."Arial-- 2 "BIOS."Arial- 2 Legacy 2 RSound & MrEd%b  & MrEd%h & MrEd%ll  & MrEd% |B 6 & MrEd% p l & MrEd%B 0 z & MrEd%< *h&MrEd hX-\d."Arial*-2 tPCMCIA Adapter&MrEd   ."Arial- 2 Z Net & MrEd%X&MrEdh  d 2 Z 1Modem & MrEd%4X4."Arial*-2 Plug and Play "System---''V~t~u vvj"~t~ShapewareVISIO20ࡱ> *  !"#$%&'(+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Root EntrybjInfoF D#Ole-h0ءlS _85507PICF`7 OleLMETA  PIC"ࡱ> LvC7?&2ࡱ>  FVISIO 2.0 DrawingVISIO FiguresShapewareVISIO20ࡱ> ࡱ> vC7^[ .     --$:i ik:i---%:i ik:i- --$:i:=---%:i:=- --$:i i =:=:i---%:i i =:=:i-( ArialF-"System- . -!Configuration Managerf- --$:8 8k:8---%:8 8k:8- --$:8: W---%:8: W- --$:8 8  : :8---%:8 8  : :8--% Arial/F-- . - ! Bus Driver\-!(e.g. ISAPNP.VXD)!- --%- - - --%-i-i- --%- - - --%- - - --%-i-i- --$:  k  : ---%:  k  : - --$ : : ---% : : - --$:  :: ---%:  :: -  ArialE- ArialE- ArialH----- . -!HKEY_LOCAL_MACHINEA-!c! > A! > g-!ENUM> -!> R ! A ! Root  ! BIOS A ! ISAPNP. A! TCM1234~ A! 0000 A! LogConfig A ! n A- !SYSTEMn -!n ! CurrentControlSet A! Services A! Class^ A! ... A! - 0 Arial- - . - ! Registry:W - - -$E( Es E- -- %E( Es E-  - -$ED- -- %ED-  - -$E( E( E- -- %E( E( E-  -- %  % % %/ %/ p % % % p % % %  % % %  % % %  % % % -  -- %/ / Q %/ Q[Q[ %/ Q) Q)  %/ Q/ Q/  %/ Q/ Q/  %/ Q/ Q/  %/ Q/ Q/ -  - -$t   pt pt - -- %t   pt pt - -- . - !PnP BIOS - - -$z 2<2<z z 2- -- %z 2<2<z z 2- -- . - ! ISAPNP Bus - - -$U bb}U }U - -- %U bb}U }U - -- . - ! Network card - - -$`   p` p` - -- %`   p` p` - -- . -!Legacy Sound Card - - -$m 2 2 m m 2- -- %m 2 2 m m 2- -- . - !SCSI Bus - - -$     - -- %     - -- . - ! Root Devnode~. - --  %[2[X[X[}-  - - . - ! Hardware Tree( - - -$:W:8(  W:W- -- %:W:8(  W:W- -- . - !Step 3:G!Build Device Nodes- - -$B i( is  B i- -- %B i( is  B i-  - -$ B iB =  - -- % B iB =  -  - -$B i( i( =B =B i- -- %B i( i( =B =B i- --- . -!Net Card Driver -!(e.g.somemac.vxd) ! - - -$::i( =:- -- %::i( =:- -- . - !Step 4:G!Load device driver- - -$ x-i- xx- -- % x-i- xx-  ArialE- - . - !Step 1:%!Enumerate Bussesi- - -$ x-8EE-ExEx- -- % x-8EE-ExEx- - - . - !Step 2:!Get device infoDi-0/W[ࡱ> CompObj]ObjInfoOlePres000"VisioDocument)`vC7\" .     --$:i ik:i---%:i ik:i- --$:i:=---%:i:=- --$:i i =:=:i---%:i i =:=:i-( ArialF-"System- . -!Configuration Managerf- --$:8 8k:8---%:8 8k:8- --$:8: W---%:8: W- --$:8 8  : :8---%:8 8  : :8--% Arial/F-- . - ! Bus Driver\-!(e.g. ISAPNP.VXD)!- --%- - - --%-i-i- --%- - - --%- - - --%-i-i- --$:  k  : ---%:  k  : - --$ : : ---% : : - --$:  :: ---%:  :: -  ArialE- ArialE- ArialH----- . -!HKEY_LOCAL_MACHINEA-!c! > A! > g-!ENUM> -!> R ! A ! Root  ! BIOS A ! ISAPNP. A! TCM1234~ A! 0000 A! LogConfig A ! n A- !SYSTEMn -!n ! CurrentControlSet A! Services A! Class^ A! ... A! - 0 Arial- - . - ! Registry:W - - -$E( Es E- -- %E( Es E-  - -$ED- -- %ED-  - -$E( E( E- -- %E( E( E-  -- %  % % %/ %/ p % % % p % % %  % % %  % % %  % % % -  -- %/ / Q %/ Q[Q[ %/ Q) Q)  %/ Q/ Q/  %/ Q/ Q/  %/ Q/ Q/  %/ Q/ Q/ -  - -$t   pt pt - -- %t   pt pt - -- . - !PnP BIOS - - -$z 2<2<z z 2- -- %z 2<2<z z 2- -- . - ! ISAPNP Bus - - -$U bb}U }U - -- %U bb}U }U - -- . - ! Network card - - -$`   p` p` - -- %`   p` p` - -- . -!Legacy Sound Card - - -$m 2 2 m m 2- -- %m 2 2 m m 2- -- . - !SCSI Bus - - -$     - -- %     - -- . - ! Root Devnode~. - --  %[2[X[X[}-  - - . - ! Hardware Tree( - - -$:W:8(  W:W- -- %:W:8(  W:W- -- . - !Step 3:G!Build Device Nodes- - -$B i( is  B i- -- %B i( is  B i-  - -$ B iB =  - -- % B iB =  -  - -$B i( i( =B =B i- -- %B i( i( =B =B i- --- . -!Net Card Driver -!(e.g.somemac.vxd) ! - - -$::i( =:- -- %::i( =:- -- . - !Step 4:G!Load device driver- - -$ x-i- xx- -- % x-i- xx-  ArialE- - . - !Step 1:%!Enumerate Bussesi- - -$ x-8EE-ExEx- -- % x-8EE-ExEx- - - . - !Step 2:!Get device infoDi-ࡱ> Visio (TM) Drawing `P _fffMMM333` Arial`Times New RomanL@P @ h A?A?A?A? Y@ Y@bbb0{Gz?@0{Gz?bb@bbbbbbbbbb????????bbbbbbbbbbb b b b b bbbbbbbaaaaa&````. 4!f'0UUUUUU?bbbbb!?b0UUUUUU?g???033333300???!333333?00bb xh@ - i@0,8 pj  k@ !'h bbb0{Gz?@bb????????bXF!???033333300bGh@ g&jPbbb0{Gz?@bbF!Xh@ehbbb2qq?2qq?2qq?2qq?2qq?2qq?2qq?2qq?0{Gz?@b!!'0UUUUUU?b#h@e"i@ ,8,bbbb!4h@ cF@        !"# $!%"&#'$(%)&*'+(,)-*.+/,0-1.2/30415263748596:7;8<9=:>;?bbbb!4h@P'h@bbbb!4h@ c@bbbb!4h@!c@bbbb!4h@!c@bbbb!4h@"cb@bbbb!4h@"c@bbbb!4h@#cB@bbbb!4h@'h@bbbb!4h@#c"@bbbb!4h@$c@bbbb!4h@$c@bbb b !4h@%cr@bbbb!4h@%c@bbb b !4h@&cR@bbb b !4h@&c@bbb b !4h@'c2@bbb b !4h@'c@bbbb!4h@(c@bbbb!4h@(c@bbbb!4h@)c@bbbb!4h@)cb@bbbb!4h@*c@bbbb!4h@*cB@bbb0O贁Nk?@0O贁Nk?b!Th@+c`bbb0{Gz?@0{Gz?b!Th@+cB`bbb0Q?@0Q?b!Th@X,c`bbb0O贁Nk?@0O贁Nk?b!Th@,cb`bbb0{Gz?@b0{Gz?!Th@-c`bbb0Q?@0Q?b!Th@8.c`bbb0O贁Nk?@0O贁Nk?b!Th@.c `bbb0{Gz?@0{Gz?b!Th@x/c `bbb0Q?@0Q?b!Th@P82!`bbb0O贁Nk?@0O贁Nk?b!Th@8!`bbb0{Gz?@b0{Gz?!Th@8R"`bbb0Q?@0Q?b!Th@08"`bbb0O贁Nk?@0O贁Nk?b!Th@gr#`bbb0O贁Nk?@b0O贁Nk?b!\h@8$hbbb0O贁Nk?@b0O贁Nk?bb!d`h@x8$pbbb2qq?2qq?2qq?2qq?b!T'2qq?2qq?b)1???033333300bGdh@ 'h:%`i@ e%<j@X!'h%Pbbb0O贁Nk?@b0O贁Nk?!Th@(8v&`bbb0O贁Nk?@b0O贁Nk?!Th@8'`bbb2qq?2qq?2qq?2qq?b!T'2rq?2rq?b)1???033333300bGdh@8'`i@ ,8'<j2(Pbbb2qq?2qq?2qq?2qq?b!T'2UUUUUU?b2UUUUUU?1???033333300bGdh@H8(`i@ (-82)<jn)Pbbb2qq?2qq?2qq?2qq?b!T'2?2?b)1???033333300bGdh@8*`i@ p-8n*<j*Pbbb2qq?2qq?2qq?2qq?b!T'2UUUUUU?2UUUUUU?b)1???033333300bGdh@8J+`i@ -8+<j+Pbbb2qq?2qq?2qq?2qq?b!T???033333300bG'2qq?b2qq?1(h@8,`j,Pi@ .86-<bbb2qq?2qq?2qq?2qq?b!T???033333300bG'2rq?b2rq?1(h@H 8-`j".Pi@ H.8r.<bbb2qq?2qq?2qq?2qq?b!T'2qq?b2qq?1???033333300bGdh@ 8.`i@ .8^/<j/Pbbb2qq?2qq?2qq?2qq?b!T'2rq?b2rq?1???033333300bGdh@ 8:0`i@ .80<j0Pbbb2qq?2qq?2qq?2qq?b!T '2qq?2qq?b )1???033333300bGdh@ 8v1`i@ /81<j2Pbbb2qq?2qq?2qq?2qq?b!T '2qq?b 2qq?1???033333300bGdh@H 82`i@ h/83<jN3Pbbb2qq?2qq?2qq?2qq?b!T???033333300bG '2qq?b 2qq?1(h@ 83`jN4Pi@ /84<bbb2qq?2qq?2qq?2qq?b!T '2rq?b 2rq?1???033333300bGdh@ 8*5`i@ x5<j5Pbbb2qq?2qq?2qq?2qq?b!T '2rq?b 2rq?1???033333300bGdh@8f6`i@ `x6<j7Pbbb2qq?2qq?2qq?2qq?b!T???033333300bG '2rq?b 2rq?1(h@H87`j8Pi@ xR8<bbb2qq?2qq?2qq?2qq?b!T '0UUUUUU?b #???033333300bGh@88`i@ x>9,jj9Pbbb2qq?2qq?2qq?2qq?b!T '2?b 2?1???033333300bGdh@8 :`i@ (xj:<j:Pbbb2qq?2qq?2qq?2qq?b!T '2UUUUUU?b 2UUUUUU?1???033333300bGdh@8F;`i@ px;<j;P@JP, `JPgJ@JPe0JP!'h@JPc04H cJP'h0JP` cR0JP c0JP`!c20JP!c0JP`"c0JP"c0JP'h0JP`#cb0JP#c0JP`$cB0JP$c0JP`%c"0JP%c0JP`&c0JP&cr0JP`'c0JP'cR0JP`(c0JP(c20JP`)c0JP)c0JP`*c0JP*c0JP+c0JP ,c20JP,c0JP`-cR0JP.c0JP.cr 0JP@/c!0JP8!0JP8""0JPX8"0JP8B#0JPXg#0JP8j$0JP@8 %0JPP 'h&&PJP8&0JP8f'0JP08(PJP8)PJP8*PJPp86,PJP08r-PJP8.PJP 8/PJPp 8&1PJP0 8b2PJP 83PJP 84PJPp 86PJP08R7PJP88PJP89PJPp8:PJP082<PHP LaserJet 4/4M  D@ XS S!@HP LaserJet 4/4MHPPCL5ELPT2:I@I@???I?I?I@I@???bbb bI?I? N h@'hBe B DDDDDDDDDDDGDCDK4KDDDKDKKKDD;4KDKDK;K4;C;DDD&KKK;KKDKKKKKDDDDDDDDDDDDLook at this shape for hints on making neat drawings using the thick arrow shapes.1L*c??1L@*c?ռ*>y-T?ռ*@>y-TgMZp5߿@?@ 8Ϛ?@1L@@*c?@@1L@@*c??P@?@ 8Ϛ?@1L@@*c?@  u` ?  u` ?Pbb b@@@1L@@*c?@''u` ?u` ?  r    r      a -      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvxyz{|}~-$]]]---%]]]- Arial-"System- . -!'You can create neat drawings with thick3!%arrows by using the "Open end" arrows[!&and bars in conjunction with the other!$arrows and bar shapes. Use the "Open!(end" bars to "break a hole" in the other!#shapes - the "Open end" shapes have!%extra white space that overprints the#!$lines of other shapes. Simply lay anK! "Open end" shape against anothers!&shape and apply Bring to Front (in the!%Layout menu) to the "Open end" shape.!"You can also use Ctrl+F to bring a!$shape to front, and Ctrl+B to send a !shape to back.;- --$jAA j jA---%jAA j jA---- 7m+ ---%-4%-4%-4%-4%-4%j-j4%]-]4%O-O4%A-A4%3-34%&-&4%-4% - 4%-4%-4%-4%-4%-4%t-t4%-4%-4%-4%-4%-4%-4%-4%-4%-4%-4%"-"4%0-04%=-=4%K-K4%X-X4%f-f4%4j4%'j'%j% j %j%j%j%j%j%-j-%;j;%HjH%VjV%cjc%qjq%j%j%j%j%j%j%j%#j#%j%j%j%j%j%j%j%j%j%j%uju%gjg%ZjZ%LjL%>j>%1j1- -- $ VVHVV----% VVHVV- -- $qq- -- $KKXKcKqq----%KKXKcKqq-- Ariale--"System-  . -!"-  - - $ 11>111- --- % 11>111-  - - $ ggZgg- --- % ggZgg-  - - $-  - - $fftfuf- --- %fftfuf- --  . -!)-  - - $ " "-  ---  %""  - - Arial+K- -  . - !-  - - $-  - - $==#K==- --- %==#K==- --  . -! -  - - $      -  ---  %" " - --  . -!-  - - $-  - - $ - --- % - - -  . - !|-  - - $-  ---  %- - -  . - !-  - - $-  - - $&&3&&- --- %&&3&&- --  . -!-  -  ArialK- -  . - !Place the "Open end"[f!arrows and bars againstuf!other arrows and bars,f!and bring the "Open end"f!shapes to front to obscuref!the other shape's line.f-    ''''N"' !o o o o ;h@8D F`%-# FP/ C@#@ h8RC @ X87DS @8D+@8DbNP88a@<=>@BCELO T A@A@A?AI?I? A@A@A?Abbb b I?I?H h@'h%ce d VwwwwpwwpwwpwwpwwpwwpwwpwwpwwpwwpwwpwwwwpwwpwwpwwpwwpwwpwwpwwwwpwwpwwpwwpwwpwwBox grows to surround text. Hit to start a new line of text.??Կt@ 贁N? t@ ?贁NԿ@?@?A?A?A?A?P@?@?rrA@rrA@u` ?u` ?Pbb b( ( A?A?@?@[[?@?@[[?P uL`-@uL`u`.@u` ?u` ?u` ?u ` ?P   L@  aaabbV.)aaaAAu` u`    A?Au` ?u` A?A?u` ?u` ?AA?u` u` ?AA r r h:Box sizes with text. Hit to start a new line of text.A?@ $@ @ bA @,u`r>@b bb@u`r=@,u `r>@b bb@u `r=@  AA?A u`bA?A? u`bu`A?A? u`b u`bA?A u`bAA?A?u` u`b\2),!#h@enfliX ^jGi@/ jdjqkp->9FP'h!d@#@ 8add @ 8eF @8 f+@8 fbHP@elA@A@A?AI?I? A@A@A?Abbb b I?I?H ? h@'hme n4H h8n fwwxwwwwpwww  wp wp ww  wwpwwwwwwwwwwwxwwwwwwwwwwwwwwwwxwwwwwwwwwwwwAdjust the width of the box to change the paragraph width. Box's height adjusts according to text. of text.??ܿt@ 贁N? t@ ?贁Nܿ@?@?@?A?@?A?P@?@?@?.  rrA@u` ?( u` ?Pbb b  L@@?A?@5h$?@88?@5h$?@88?PuL`u`-@u` ?u` ?  uL`u`.@u` ? u ` ?PbbaaaX.N(~aaa@Au` u`    @?Au` ?u` @?A?u` ?u` ?@A?u` u` ?@A r r h:AA?A u`b@?A? u`bu`@?A? u`b u`b@?A u`bA@?A?u` u`b\2Adjust the width of the box to change the paragraph width. Box's height adjusts according to text.A?@ $@ @  bA @,u`r>@b bb@u`r=@,u `r>@b bb@u `r=@),2h3qlsXq#u vkdv-~U<FP'hnP#@ `8nt @ 8cpm @X8p+@h8pbHP8VwA@A@A?AI?I? A@A@A?Abbb b I?I? G h@0'hpxe Xy wwwwwwwwwpwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwControl handle controls box thickness. Use horizontal/vertical flips to change depth perspective.??t@ t@ ? t@ ?t@ @?@?@?@?@?@?P@?@?@?@?u` ?u` ?Pb bF           F           bL@ bnW H H H @@@@bbb@?@?@@    @@  r r     r@?@?u` ?u` ?@?@?u` ?u` ?@?@u` ?u` @@?u` u` ?@?@?u` ?u` ?t<) hy{e },p E}d }|q ]~4@?@@?@?@?@?Pt` ?(rb t` r[@u`A@t` ?r@A@u` ?u` ?Pbrb  b      0O贁Nk?@ bA@Aaaa@@?@u`       @?@?u` r @?@u`r@   @@ r r @@? r r `@@  p  p       | ) 4h@P'hPlQ8d @@?@?@?@?@?P(rb t` r[@u`A@t` ?r@A@t` ?u` ?u` ?Prb b b      0O贁Nk?@ bA@Aaaa@@@ r     @?@u`@   @?@? r u`@@? r u`r@@ r r c@@  p  p        | ) $h@'h_Pl8d @?@?@?@?@?@?Pt` ?t` ?t` ?t` ?u` ?u` ?Pbb b    0O贁Nk?@ bA@aaa@@u` u`      @?@u` ?u` @?@?u` ?u` ?@@?u` u` ?@@ r r h: ),_h@ 'h,lX%hċ FP'hly@#@x8y @8zb @8{+@8{bGXx8pHP'h RHPx'hkRHP'hABA@A@A?AI?I? A@A@A?Abbb b I?I?H h@ 'he s wwwwwwwpwwpwwpww pwwwx wwwwwwwwwwwwwwwwwwwpwwpwwpwwpwwpwwwwwwThick arrow shape with arrowhead at one end. Shape is 2-D and behaves like a box.@?@?@?@?@?@?P@?@?@?@?Pu` ?u` ?bb b      @?@?@?@?@?@?Qu` ?u` ?u` ?u` ?u` ?u ` ?9u`Q(-DT!? u`Q(-DT!? @QQ(-DT! @@    L@a@@? ru`br    @@? r u`r  @?@?r u`u` @r r   @?@ r @  @?@?u`ru` ?  @?@? r u`@?@? r r @@? r r _c @ ? ?b bb bb      ),Uh0lGdO??пt@ 贁N? t@ ?贁NпpdB (GFP'h@#@ 8Nj @8ČR @X8HPh8ߑR+@81bA@A@A?AI?I? A@A@A?Abbb b I?I?H $ h@ 'h+e  3󎻂󎻂󎻂󎻂;3;3 ;󻳆3 03;3;;    󎻂󎻂󎻂󎻂󎻂3Thick arrow shape with arrowhead at one end. Shape is 1-D and behaves like a line.@?@?@?@?@?@?Pu `u `bu `u `b@?!u `u `bu `u `b@u `u `u `u `@u` ?u` ?bb b      @?@?@?@?@?@?Qu` ?u` ?u` ?u` ?u` ?u ` ?9u`Q(-DT!? u`Q(-DT!? @QQ(-DT! @@    @?@?@@@?@?@?@@@?L@&(a@@? ru`br    @@? r u`r  @?@?r u`u` @r r   @?@ r @  @?@?u`ru` ?  @?@? r u`@?@? r r @@? r r _c @ ? ?b  bb bb    ),Mh@ h+e lĘd̚??пt@ 贁N? t@ ?贁Nп?DB R^FP 'h'@#@ 8 8g @ @!8dS @!8HP+e\R+@!8bA@A@A?AI?I? A@A@A?Abbb b I?I?H h@ 'he  3:::33󉻂3?;;;󉻃3;;;󉻄3󉻃 󻳇3  3󉻃 ;;;󉻃3;;;;󉻃3;󎻂󎻂󎻂3Drag control handles off main stem to position up to 6 "limbs" of tree.=?t@ ࿸贁N?,t@ ?紁Nп?=@?@?@?@gﮃC<@?@gﮃ3>?@II?@>>?@II?PAAA?AA?A?AA?AAXD0l??A?@ @ @ <PnP BIOSAA?A?A?    A?A?A?AA?A?`Lv'h@0elAe( V.d D@peq@`c@@@?A?A?A?A?Pt` ڕ]?t` h/?bb  A?A?@>>?@II?@>>?@II?PAAA?AA?A?AA?AAXD0l??A?@ @ @ <ISAPNP BusAA?A?A?    A?A?A?AA?A?`Lz'h@elA(e#( .d D@ eq@(c0@@@?A?A?A?A?Pt` ڕ]?t` h/?bbA?A?@8&?@II?@8&?@II?PAAA?AA?A?AA?AAXD0l??A?@ @ @ <Network cardAA?A?A?A?A?A?AA?A?t`L&'h@ HerlApen( .d $D@ Pehq@c}@?@?A?A?A?A?Pt` ?t` h/?bb  A?A?@ Ce?@II?@ Ce?@II?PAAA?AA?A?AA?AAXD0l??A?@ "@ @ <Legacy Sound CardAA?A?A?    A?A?A?AA?A?t`L0'h@ elAe ( #!.d Q!D@e!q@c!@?@?A?A?A?A?Pt` ]ڕ?t` h/?bb  A?A?@qq?@II?@qq?@II?PAAA?AA?A?AA?AAXD0l??A?@ @ @ <SCSI BusAA?A?A?    A?A?A?AA?A?t`L'h@ e"lAe#( U$.d $D@e$q@@c$@?@?@?@gﮃC<@?@gﮃ3 4H X8>@?@?@?@?@?@?Pt`& tE]t?t`& ?t`& tE]t?t`& ? %u` ? %u` ?Pbb baaa@@u` u` @?@u` ?u` @?@?u` ?u` ?@@?u` u` ?@@u` u` T4Hardware Tree???033333300bG'0UUUUUU?0UUUUUU?b)1&h@p%e>lA&e?P@ x&e&Aj@8(ePHP$eArGPp"gDPHP)e5GrGXcIpHPc_KRHP0cLRHPciPHP cSrV6Q  * METAFILEPICTvCd"vC7f% .     --$:i ik:i---%:i ik:i- --$:i:=---%:i:=- --$:i i =:=:i---%:i i =:=:i-( ArialF-"System- . -!Configuration Managerf- --$:8 8k:8---%:8 8k:8- --$:8: W---%:8: W- --$:8 8  : :8---%:8 8  : :8--% Arial/F-- . - ! Bus Driver\-!(e.g. ISAPNP.VXD)!- --%- - - --%-i-i- --%- - - --%- - - --%-i-i- --$:  k  : ---%:  k  : - --$ : : ---% : : - --$:  :: ---%:  :: -  ArialE- ArialE- ArialH----- . -!HKEY_LOCAL_MACHINEA-!c! > A! > g-!ENUM> -!> R ! A ! Root  ! BIOS A ! ISAPNP. A! TCM1234~ A! 0000 A! LogConfig A ! n A- !SYSTEMn -!n ! CurrentControlSet A! Services A! Class^ A! ... A! - 0 Arial- - . - ! Registry:W - - -$E( Es E- -- %E( Es E-  - -$ED- -- %ED-  - -$E( E( E- -- %E( E( E-  -- %  % % %/ %/ p % % % p % % %  % % %  % % %  % % % -  -- %/ / Q %/ Q[Q[ %/ Q) Q)  %/ Q/ Q/  %/ Q/ Q/  %/ Q/ Q/  %/ Q/ Q/ -  - -$t   pt pt - -- %t   pt pt - -- . - !PnP BIOS - - -$z 2<2<z z 2- -- %z 2<2<z z 2- -- . - ! ISAPNP Bus - - -$U bb}U }U - -- %U bb}U }U - -- . - ! Network card - - -$`   p` p` - -- %`   p` p` - -- . -!Legacy Sound Card - - -$m 2 2 m m 2- -- %m 2 2 m m 2- -- . - !SCSI Bus - - -$     - -- %     - -- . - ! Root Devnode~. - --  %[2[X[X[}-  - - . - ! Hardware Tree( - - -$:W:8(  W:W- -- %:W:8(  W:W- -- . - !Step 3:G!Build Device Nodes- - -$B i( is  B i- -- %B i( is  B i-  - -$ B iB =  - -- % B iB =  -  - -$B i( i( =B =B i- -- %B i( i( =B =B i- --- . -!Net Card Driver -!(e.g.somemac.vxd) ! - - -$::i( =:- -- %::i( =:- -- . - !Step 4:G!Load device driver- - -$ x-i- xx- -- % x-i- xx-  ArialE- - . - !Step 1:%!Enumerate Bussesi- - -$ x-8EE-ExEx- -- % x-8EE-ExEx- - - . - !Step 2:!Get device infoDi-E5 !-}~jO0L: Cf#FMN^_`ab>?UV&'1 2 H I BCYZ!A =E  ) * + , - H "*#%&(())))**)***?*@*V*W*n*o*****-.//001162T2$5\5|668888888UuDl uD vVuD]\88"9#999:9{9|99999999999=:>:T:U:::::R@S@V@W@AABBBBBBBBBBBB>M>V>>>v???????? @@@@GBPBfBBBBBBBBBBC C CCCC CCCCCCDD%D.DDEQEZE[EEEEEEEEEEEEEEEEEEEEEEFF]VUcFFGGG(GSGZGGGGGGG5H>H?HnHoHvH}H~HHHHHHHHI II&IIIIJ&JCJrJ{J|JJJJJJJJJJJKK.K;KKKLLLLLMMM%M&M/M8M9MAMHMIMPMQMRM_MCNNNXNNN$O,O|OOOOQQaRjRRRRS`SjSSU]VcSSSSSTTTTT$T%T&T3TTTTU UU"U@UVUUUUUUUUUUUUUUUUUUUVVVVVVV WW#W,W?WHWWW+X4X5X^X_XaXhXiXpXqXrXXYYYYYYYYYn[w[[[[[[[[[\\\ \ \\\\\\\]VU]b]]^^^^_$_%_H_I_L_S_T_[_\_]_j________```1`2`8`D`E`K`R`S`Z`[`\`i``a a.a4aaaaab b b+b,b5b~G~N~O~V~W~X~e~&,^f'0gn}!"+23:;<IU]VcIقŃ23<GHPWX_`an X`ox'(.56?FGNOP] EKЊ׊~kt )*3:;BCDQ]UV]b&Ðڐ09:Z[dnoxp{ђגKTipOXvϔؔٔ$%.56=>?L JQ09RnĘŘΘ٘ژ  FeU]Vc&=O_#Zap"+,5<=DEFS9Bnw$2MQgvS\ͦ)*1ABPWX_`anIT[&4MTc~ϩة٩ (/0789Fժګ]VUc/ȬɬҬ٬ڬ ®3"8Gbc}$-|&'/;<GTU`ghopq~7BK:Eڵ@GV_%,-VU]b-456C7@bixԸݸ#v¹ùĹѹk̻ջֻ#$078?@AN޼(nz  "+3>CO"2v]UVc#*9B$-Lk  !"#0 (ho~#*+234A6?Y`ox!*Qf%./HIPQR_V_U]Vc/07CDKWX^efmno| _f#LSbk %8>Z`w} /07@AJQRZabijkxT]VUcT_f 23<FGP[\dklstulw,56VWalmv}~:EO s~9Bn   !'./6UV]b678E!(agJP  %12<FGSZ[fmnuvw:EN/CtSZirENcy -*pwV]Uc !QZ[}~`ku!_e0Lz6AHW`5Cr'U^_07`iAKz%.VU]b. -#$+,-: JS+5dnQnhr09mv 89CJKRSTa PWfn4=Uv]V]Ub $ G P Q u v                          ] f               bkl\gm.5"Tq]VUc !"/&/   #*+<EFV]^efgtT_c|/NW9BCjktJU^]UVc=FGjkovw~JQ`ips3 P                }!!!!!!""#"""_#h#$&$|$$$$% %!%N%O%X%h%i%p%w%x%%%%%&%&.&H&O&f&m&|&&&&&&&&&&&'''''''VU]b'''(H(R(8)A)_)))))******* *-****;+B+Q+Z+x+++++ ,,,,,&,',(,5,,,,-#-2-;-]-t----------K.V.].l.u....// /!/*/5/6/?/F/G/S/]/^/c/j/k/r/s/t//!0,050O0X0z000000U]Vc00011112"2#2S2T2]2h2i2q2x2y22222 333e3m3333344445%5&5@5A5I5P5Q5X5Y5Z5g55 6686?6N6W6>7G7b7}7777778 88888%8,8-8485868C8888 9(999::::;;<2<s<|<}<<<<<<VU]b<<<<<<<<<<<j=u====W>b>d>k>>>>>>>>>w??@@Y@b@}@@@@@AAA&A'A0A7A8A?A@AAANAAAAAB1B8BGBPBwBBBBBCC!C(C)C0C1C2C?CCCC'D2D9DDDBEKELErEsEEEEEEEE/F:FKFFFF]UVcFFHHHII*I+I7I>I?IIIUIVIYI`IaIhIiIjIwIJJ+JBJLJdJgJJJJJJJJKKKK K!K"K/KKKKKKLLLM:MCMDMiMjMsM}M~MMMMMMMMMMMMMMMMMMMMNNNNNO$O8O>OOOOOP PPPQ QVU]b QJQSQTQhQiQwQ~QQQQQQR R.RRRSSTTTTjUUUUUDVKVWWWWX0XZXcXXXXX:YHYIYY!Z"Z8Z9ZZZ\\]]]]^(^m^^^^^^^z_____T`Z`aancxcccccQd\d^ded{ddddeeffhcuD]]VU_hhiiiik l(m)m?m@m1o?oooppp*ppppppqqqqq7rIrXrcrpr{rssss4s?sssssItStrwwwwxxx,xxy:yQyjykyyyyy6{7{M{N{||||#}4}}}}}~~~~~~~~GH^_tȀUVuD]`ȀɀހTU  (z{01FS\]f҆ӆ (CGbLjljȉމ߉(.׋؋ˌ̌ EF\]ĎŎ@xs͖}~]]UcVuD_~<IJ֘ݘޘ$-8@iqț˝ם؝Mygܢ.89t7fopSVdtu;CDĨSw̪۪ͪܪުߪmnݫޫccc V]]U`ޫCD}~OPíĭ<=gh׮خ =>noϯЯ./lm۰ܰ :;no[\Ȳɲ ()KLѳҳӳԳճ 12!"#2ƿ׿GH =UuD(V]uDc^=S|jkb{  2pqx{ \w;MWX$% !!"/w ,   ]uD(UuD VU]`]\IKxz % r t b""""""E#G#c%j%t%u%~%%%%%%%u*w*,,t-v---)0*0:0;0<0=0>0{033V:{:Z@m@@@;AGAAATDjDbLmLP6PQQeRsRS SSSSST)T)U=UBUXUdUxUUUV]uD]VU`VVW(WWWYYYYZ[&\4\?\V\]]^^^$^&^'^(^5^^_``a&anaaaaaaaaaaabccKcTceeceiejeeeeeeeeeeeeeeeeeefIfTffffffghh0i6i7iZi[iaibicipiiiiij;kDkrkkkV]Uckkkkkkkkkkk lHlSlYlllmmRn[nnnnnnnnooooppp]pfpqqqqrrr8r9r?rNrOrSrTrUrbrrrrxyXyayzz {&{'{B{C{G{N{O{\{c{d{k{s{t{z{{{|{{|||Y|f|}}~~*+19:I]VUcIPQZ`aemn{ ݁ $*V`ʃӃR[sք܄݄ BMQ%flmɇ͇#)*OPTUVcoz~܊HNOmn]VUcnt|}Ì ,5ˏԏSYZz{ÐĐʐːِ̐(39ّ-;0:S\ SYZopELQZȘ&]UVcӚܚY_`xy},9,<ǞȞɞ֞ڞ.2^d(KQRnostuܡʣ:;?@ANco82:@ajDKӬ`]VU]b`ͺܺ;I ɼּʽ 6LvȾ*x "I_-40D'Tg3?P[SZ^@G&5r]]UcCHJW/7=el-?[ciIP:H$P8F%p(7_%M29fpHPVU_$f]]Uc,6 .ZhL]<Jp ;Y3Eo 7,^z;W&y@[6L\/ J 3NO [uD]]U`@Om|l{  1!3!!!""""++++,,2,3,{//1122D2E2[2\2222233334444555588882939I9J9::;;;;q<r<<<]=^=t=u=====Z>[>q>r>>>????I JSJTJjJkJJJuD]UbJJJJJKKLLMMMM N NPQaXXZZd\\\_t_:`)b[b"d#d9d:d7e8eNeOeh`hnnRnSninjnnnnndoouuDxxO}]}~~~~z{Ȁɀ„ڈ=_:ڰOߵV]U]]uD`23TUklIKǸȸؼiʿ$&*.27+$>HahcV]U]uD_4>OPQRciq CR*6 ,!MSq}(,?CG&7PYel|awq$IYU]]Vb",x:LN`asAE]a(1bj3C|  +:>?@AGO^@IKS]]cUVaSX`!*,49AMT^b`abh R[]ejr57X_ GMRX%(/2ACIKPQR%,Yb"bj]]cVUa,:?D K !8=GXYZ[lr{ 456NSZnop -EKNU 4KQtZ]]VcUaZcGNZa &~ -< !),67DGRS[^ijx3IR^e'1;E' 1   % / e o  % D X i w         ! (      cV]]Ua           RZ"*nsx}@W[\_`cdeoqrs~  58$m]UVcmpux-8\hn$  Z c         !!`!i!!!!!!!!!!!!!!!!!!!!!!!!"""'"*"S"V"""##S#V#[#^##### $$$$$]U]Vb$$%%%,%R%%%(&5&6&D&E&V&Y&Z&e&g&z&&&&&','''((1(D(Q(W((((())))))f*g*}*~*$+*+D+P+++, ,[,],k,l,n,,,,,,,,,,,,,-----..l...///0/:/Y/n/00H0O0z0001uD]]UV`1}11*202J2V23$3&343L3N3`3x3}334444,6>6f6w6P7a7|777777C8K8P:_:`:r:s::::=)=+=D=F=S=U=b====== >>->>>;?K?????????@@ @@@@@@@@*A:AAAAAiByBBBC CCC(C)C*C:C]]VUb:CJWXhijklx*0NV3E5V]uDVU]`d% .     o p         p v     | }   =@AG_gq~MQ_c./%pt_`vw01GH4=W`myzcVuD]U]_z^h7EF/0FG39Yb  f m   ! !R!_!`!!!!!!:">"###$S$T$j$k$$$W%a%%%&%&&&&&&&&='A'''@(G(((((3)D)E)]VuD]`E))**1*2***+++++++X,_,,,,,K-X-Y------u.y...Y/`//////0N0]0^00112131112,22222'343333333P4d4%55565X5x5y5556 666C6R6S6m6q6y6666666h7l77788V]]VuD]_8S8[8}8888889999::z:~:::(;1;;;E<N<X<d<|<<<=w====3>:>{>>>>>?8?9?O?P???@@@@@@@:AjAkAAAAAABKBBBC"CiCpCCCC`DDDDD7E;EEEF!F9FAFFFG GPGWGGGGHJuD]]VaJJJJJJ+K,KgKtKLMM$MN N@NDN8O9OJOKOMONOOOOwQxQQQ5R6RLRMRRRRRSSSSwSxSSSSS T TU VWWXXA[B[X[Y[^)_>bob\ffXll#q@qtuw>yz|}͂h> lBCTU]uDVc]c_UWXY?D͓ٓ  ǖɖHM  _`vwyzhiKTS`%*zϢۢ&ڹ۹ݺ p|w0UV]UV]uD_0@aq-.#/.94:$(/S^ 09T^(2CKkx]i %'(,-./0456:;]` uD]U]]V^;<=>BCGHJKMcefgrs|}./126789:>?@DEFGHLMQRSTVlnop{|]` uD]]` -.0156789=>?CDEFGKLPQRSUkmnoz{] uD]]``  12459:;<=ABCGHIJKOPTUVWYoqrs~  9:<=ABCDEIJKOP]` uD]]`PQRSWX\]^_awyz{   !"#$()-./02HJKLWXbcghst]` uD]]`Vu] uD]1Nd} DEb} >P1 B !AUa - 0X0@00000000000 00R0000000000 000PoeKFCOB*- H "4"R""""#*#%&'(())*?*n***i,-..//001162T2$5\5466u78888800000000{0 00000{000000COFD+88"9{999=::;;<>AABBBBB?mɳEqrE-̴ʹAnֵ5Tfwض !/0PQlm#`ӸԸ)IJfE-ùĹչAD"e{ƻǻ Ltuϼм_`ֽؽٽjE-j1Q<9:#$=hW:} 1 jzIhE?FeQD+h 3ZM]y (`u<T+d 7Sw/2w}p_[E?F*}mC (>Zz D{:UCO_[=m00s  0<#U-(^   J  -f%#[ 0yP z "###$p$-p$|$&' (2(")))+E,,--]. //////B000w11111U2^222223#3:3H3m3z333`^_[W*33334 4/4I4\4u4}4445-5W5l5555567717M7h777788888888969I9n999W_[^`+9:::::::::;;;;3<<<R<g<<5=B==>>M>W>>>>>??;?G?P?\?v?????? @@`^_[W+@-AGBPBfBBBC CCCCCCDD%D.DDDEQEEEFFFGGG)GSG[GGGGGGG5HHHHI I_[W, II&IIIIJ&JCJrJJJJK K.K;KKKKKKKNLLLLRM_MCNNNYNNN$O-O|OOOORSSS&T[W_,&T3TTTTU UU"U@UVUUUUVVVVVVV WW#W,W?WHWWW+XrXXYYYYYYYn[w[[[[ \_[W, \\\\\\\]]^^^^_]_j________`\`i``a a.a5aaaaabFbSbbbbcc%c.c_[W,.ccccdPdddddddeeeef+f^fffgggggggBhMhhhhhhh"ioi|i jj+j|jjj_[W,jjkkk l&l?llllMmXm\mtm|mmmmmm9nFnn oooopp&p/pppppqaqnqrr)rrrs_[W,      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnrstuvwxyz{|}~sscspst t`ttttkuxuv"v,vEvPvkvyvwwwwwwnxwxxxx&y3yyyy"z,zNzVzdzmzzzzzW_[,z {2{{{!|,|4|`|g|z||}}%}5}V}_}t}}}X~e~&-^g'1go}<Iق_[W,Ńan XaoxP] ELЊ؊'=jkEW_[,ktDQ&Ðڐ0p{ђؒKUiqʓߓ #6OX`^_[W+Xvϔ?L!JRzܗ09Rn5Fޚ&ix`^_[W+K[*O`ɝ@Yo̞ !0FhΟ$Zbp_[`^,FS9CҢ2Dnw$S\xͦanIT\&5MUc~ϩ9Fժ`^_[W+ժګ/ ®$-I`|q~7BL:F_[W,@HV_y6C7AbjxԸݸ#vĹѹk̻AN޼)nW_[,n{ "+{r2v #+9B$-Lk#0 )hp~W_[,4A6@Yaox!*=Qf%R_V_o|  _gL_[W,LTbk %L kxT_g ulwW_[,Oaz,:EP s~9B^n8W`^[_+8E!)ahw:EOtS[irENcy -_[W,-+px !Q`kv"_f0Lz6AIW`'U_[W,08`jAL%. --: JT+6-Qnhs_[W,s&8^n09mv Ta PXfn34=Uv EW`^[_+ $ G      ] g             ) > Z k       b\gn.6Tf`^_[W+f"7Tq"/&/gtT_d|NW_[W^`+9JU_=JR`i3 P    }!!!"$"""_#_[W,_#h#$|$$$$$%%%&%&/&H&P&f&n&|&&&''''''''(8)A)_))) *-****;+C+Q+Z+x+_[W,x+++(,5,,,,-$-2-;-]-t----K.V.^.l.u....t//!0,060O0Y0z0000000011112_[W,222 33 3e3n333332444445Z5g55 6686@6N6W6>7G7b7}7768C8888 9)99999-:`^_[W+-:H:::::;;<2<s<<<j=u====d>l>>>>>??Y@b@}@@@AANAAAAAB1B9BGBPBwBBW_[`^+BB2C?CCCD'D2D:DDDBEEE/F:FLFFFFFHHHjIwIJJ,JBJMJdJhJJJJJJ"K/KKKKK_[W,KKLLLLM:MMMNNNNNO%O8O?OOOOOPP6PKPgP|PPPPPPPQ QJQQQR R/RR`^_[W+RRRS.SFSSSTTTTjUUCVDVLV}VVVVVVVVWW$WCWDWSWiWjWuWWWWWW i /=m0?FEW`^_[&WWWZXdXXX9Y:YHYIYY!ZZZZZZZZ[%[&[7[P[Q[_[[[[[[[[[[\\!\A\ ` /=m0?FE_['A\B\O\o\p\\\\\\\\\\\]]0]Q]R]h]]]]]]]]]]^)^^^^^^^z__S`FE_[=m0 ` /(S`T`[`````````aaa3a4aEaeafaxaaaaaaaaaab b0bFbGbTbtbubbbbbb ` /=m0_[?)bbbccc5c6cKclcmcncyccccc^dfd{dddddeffhhhhi\j]jkk l l(mm?F_[=m0 ` /'mm0o1o?o@oopp*p+ppppqqq6r7rJrorpr{r|rs3s4s?s@ssHtItTtttttt)u*uIu /=m_[F?(Iuaubuuuuuuuuvv,vHvIvcvvvvvvvqwrwwwwxx,x-xjyyyyyyy6{b{c{|?FKm /=)|"}#}4}5}}~~~~~~~~~Gst݀ހ/TUlz $0=m0_[?F(EFST߄8\]^҆ :S߇ LjȈlj x/_[ $0=m0?F&lj)YnȊɊ./׋ˌ EĎŎ@wxE  /=m0_[?F's͖3<JKTcdn}~;<IJ՘֘ݘޘ$.irɛ W/=m0_[E(ɛʝ˝ם؝Mxygܢ-.89t7eE[_,efopcdtu:;CDĨSwL̪ͪӪ۪ܪݪުߪ $<0 0 &  0 $<$<tE-mnëݫޫ'CDX}~Ĭ%OPfíĭԭ $<0  0$<0'<=Pghx׮خ "=>QnoϯЯ./Elm}۰ܰ $<0  0$<0'  :;Ono-[\mȲɲڲ ();KL] $<0  0$<0'ճ G!#2ƿ׿M?@P=m00s<pCO  0$<0 -3>GHIJKLr(f f f s  f ,0<p=m  0"   =S6||@b{2l\wm  f ,0=(BKWXYZ[`ijovw},-.N=m00s 0<p%  #$)ghn -.3=m00s 0&$%&'(*KLNnoqi !!#/$w=m00s 0<p#w_ ,i )   ]}Joq+lE<q(*GI+ KuBxJGn bd2Yz /Pr, ILx{ & n "b""A#c%%[&&&((q*,-0 0!0>0Y0{053335_7z8CO_[*z8V:{:r;z;;;;;;;;;;;;<+<,<5<L<M<\<i<j<<<<<<<<<<<<<<==,=C=D= /=m*D=J=U=V=h================?Z@m@;AB=CTDjDZEqFG IIJKLNP6PQTVX /=m*XYCZ[?\V\]]^7^^_``a&anaaaaabccKcTceeceeeeefIfUffffffghh_[W+h0icipiiiiij;kDk[krkkkk lHlSlZllllmemzmmmRn[npnnnnooppp]pfpqqq`^_[W+qqrUrbrrrrssIs[s~ssssssqtttt5uMuuuuuHvWvvvvv8wNwwwx$xxxxx`^_[W+xyXyayzz {|{{|||Y|g|||||||S}^}}}}}~,~i~~~~ ݁`^W_[+ %+VaʃӃR[sքBMRƅЅ6@ن%fɇ·Ɉ`^W[_+#Vcozˊ܊HČ ȍYjڎ,5ˏԏSِ̐(3`^_[W+3:ّ-<0;S\ SEMx×ϗQZȘ&W`^_[+ӚܚY,:,<ɞ֞ڞ.3^e(Kuܡʣ`^[W_+ANco8IW{ )IhҨ<WvΩ*9`E_[W+ɪ۪"12:AakDLԬ`it ]hЯٯ#0#4<K$`^_[WE,$\h˲ӲTj׳N_%:)?9IQeи5JRiĹչ [^`,ͺݺ;J ɼ׼˽ 6Mvɾ+x #I` -50E[_-(B]d}+G-GTh3?,8H\rPWE`^_[+P\S[-Vj^o-;QlWE`^_[+@H&6rCI}  mz JX.E`^_[+./7>em,-?#@Pf|0EZ[cjIQ_[WE,:I# k$Q8G '4X&p(7_p~E`^[_+%M^l2:fq 0GHPWU`^_[WE+U`$5Caf,68Lau +K_rWE_[+r /ZiL^<Kp ;Z3Eo _[WE, 7-^{;X'y@\z{|}4^6LCO_[W+\. / J u  * = N f |          #ETU6|3Ns  p0<pE( 3(TYZp3  p0=m(000s%123G"LMNl:;<W     N!O!`!!!!"x"=m  p0+x"""""H$$%e&3'w''(R)S)-*+,x,y,.{//s011D222233457Q882999::F?D  p0=):;q<]==Z>>???@ABBDlFRGGWHI JSJJJ@KAKKZLLLLMOOPQQQ RDSESTUWaXD?F,aXXX!YYYYZZ[#[8[M[b[x[[[[[[[\$\9\N\c\d\\]Y]^)^*^\_t_______`$`9`:`E?D,:``+a)b[bbccc"d7ewfxfWgh`h@ij>k%l&lWlnnRnncodooJpZqsrsPt>u?uuu wDxxkyJz{F?D+{{{O}]}~zLM„ׅD߇ڈ+ \=_G,ܘњ:T3DF?,;éK;ڰOPα  ߵTָ׸ؼiʿ?FE,$J,1KLQklq$%')L   /=m0_[&LMOQpqsuLf 6MWyE_[=m0  '"23!Bwawq RB m0_[E* &',FGLghl:LMAFKE_[m0 /=(^c458LMPabewx{ /=m0_[))*-<=@FGJRSV\]`pqt=>Am0 /=*A`abi1dYb"bj7<VW\vw| /m0E_[ /=&?E HIKM KE  _[ /=m0&Vr~{Y \  D X x    ! ) * 4 O P X w x         /=m0_[dE'        9 : C b c p       n0./1_[  /=m0' @W59%-9\iTUn%     !!E0./1[_*!!S"W"""######$$$,%R%%%(&5&6&{&''-'''1(E(()f*++8,[, --l.../&P?dE_[*/0/;/Y/o///01 23y344,6>6P7a7b77P:_:`::=)=*=u== >>->C>>>>>>>???0@`^E&?[_*0@@@@@AA[B\BBBBC ClCCCXDiD/E:EEE FFFFFFFFF'GHI7I=IJK_KKKKKdE_[+KLDMNNNOOOPPJRYRpR8SESvSSSSSTTTUUUUVVV_[?FE+>lmyz^i67EF/3:   Q!R![FE_+R!_!`!!!9":"?""####$S$$$$W%b%%%&&%&&&&&<'='B'''@(H(((2)3)D)E))**_[?FE+***+,+++++X,`,,,J-K-X-Y---t.u.z...Y/a/////M0N0]0^0011112-2222FE_[+223333P4d4%55565X5x5666B6C6R6S666g7h7m77788S8\88888999y:z::::?FE_[*:(;2;;;X<e<|<<<=w==S>>>>>?8????@@@@@@@@:AjAAAAABLBBBC#CCCFE[_+CCC`DD6E7Ebobc\ffK?FCO=m  /(SummaryInformation   (, !"#$%&'()*+,-./056789:;<=>?@ABCDEFGHIJKLMNOPUVWXYZ[\]^_`abcdefghijklmnopuvwxyz{|}~Microsoft CorporationMicrosoft Corporation@80RD@Y@PU=Edn@GMicrosoft Word 6.014 fkXlln#q@qtuw?wRwwwwwwwww x'xCxDxzxxxxxy=y>yz{4{@{R{a{{{{{||*|9|f|E-f|||}}}~~0~J~p~q~~~~~FG͂h> )BE,BPdeg{}:;Okl؊-.?Yt/gόь1E-13QSoqˍ͍  ')GIikÎڎ܎  02kl89:YOE,Y}>?D͓̓GHM_yhm%+aϢۢ^&'vyE?F0./1C*  45`p˦"UV~Ƨ^Xgi˩6HI UVqܫݫ&8G_E-_~Ӭլ %&n­ǭ45}ծDz{|ܯ$%U˰  Ms}E-бGqsƲyӳ'}Ǵ-cfgԵ"ARSv%YƷE-#d͸θ*|ɹڹ۹ p}w0A¿-._[?FE*#04;%(/t+blS_ 09X;xE_[,T_CL6f]j01234>?@AB00`U#_[E+Bcde:;<=>HIJKLlmn9:;00`00`000`0U#-;<=GHIJKklm=>?@AKLMNOopqU#-EFGHISTUVWwxy$%&'(HIJU#-U# K$@$Normal a c6@6 Heading 1HP U]a c(*@* Heading 2 <c",@, Heading 3P(c,@, Heading 4<(c,@, Heading 5((c8@8 Heading 6 (1-c$@b$ Heading 7Vc$@b$ Heading 8Vc$ @b$ Heading 9 Vc"A@"Default Paragraph Font"'@"Annotation Referenceb *@*Annotation Textb c&@&TOC 8X !&@&TOC 7X !&@&TOC 6X !&@&TOC 5@ X !&@&TOC 4pX !@bTOC 30@rTOC 2"@r"TOC 1(0 @Index 7p@Index 6@Index 5 @Index 48 @Index 3 @Index 2h @Index 1(@ Line Number!@ Index Heading!* @"*Footer"o9a c 2@R2Header#.0 U]a c$&@A$Footnote Referencece"@R" Footnote Text%c"@b" Normal Indent&OWh+b.O.Ws,((a bc *O*We-8&bcONp1.(4O4Nh/ (1- U]a c,O,Ne0t(& a bc *O*Ns1( a bc OBNhi2O"Nsi36ORNp1i4OBNei56OrWsi66O!BWhi7b"O"Sbre 8a c OB Wei 96tc 4O4Sbrh:( U]a c(O2(Tt;$<Ua c(O(Th<$<Uc.O.Tp=$<0c,O,Te>LPP& c O Le ?`c OH6p@(O2TtwA.O.IhB  U]a c06O6ChC`@%- U]a c0(OB(Ln1DHPXORXEx>E$5 $ 0 <HT` ]a c$Ob$Lb1FP6OB6ProchGPPUa cOHn1HO!Hn2I.O.MpJ$1 ]a cOALp1KONp2LP&O&ErmMd(UOErpNd,O2,CnO [`xa c Oa Lb2P00pOQpExl^QW $ 0 <HT`$0< H T`lx.O.CapR$0Ua c(OA2(Ln2S0 0OBLp2T04O4 header ruleU2&a c 6Or6Rh1VHU]a c(e8O8RmhW$10 U]a cOErmnX<O1Hn3Y*O*SbrpZa c$O$Term1 [a cOaLbp\ORNp2i]OTerm2^ODef1_PODef2`0OQExwmaf $ 0 <HT`~(4 @ LXdp|2Ob2Ruleb(a bc:O:Synw'c (@Xp`O`SynNdJ0H`x  8Ph(@OLeheObLmcfP,O,Pbg 1a c OBProcphP&O&Tpii 0OTpr j0OQTexfk<*O*Tflt8(0cOTpfmOTew n0O0ArtoP 0a cOThfp O Tpifq(O1(Ph r1 U]bc<$O$Trs& a c&O&indextP \]bc0O!0CapSdu1 06O6ArtSd"v1 0pOrpTex^wW $ 0 <HT`v ,8DPJObJ*hb2)x`x& "' "( ") "-/$ U]bce FOABF*hb1.y& ' ( ) 1%-/$be$O$Tartz.OB.Tei{6PP& c6O6Sbrh2|(( U]a c,O,SbrLb}0P0nOnExl2[~0T$0< H T`lx<H T `lx OSbrLpbObSbrExC$2$0< H T`lx ]a cOQTeh$OA"$Tsyn $<c,O,SbrLe`c "O"Tes tc $O$Sbrs a c:Ob:*Cbx.d ]a cOa2*Cbxed(O( endnote text c     E >-%y35ACf=?KMo<>JLn@BNPrHJVXz')K8GqB0g<FS]fo"zI-T6.'0<F QhȀ~ޫ=VkIn`JSZ m$1:CQQZeq~zE)8JU0;PV- 8Hv[n9v~jh}Up$39@ I&T \.cjszkXժnL8-s f_#x+2-:BKRWA\S`bmIu|ljɛewz8D=Xhqx3$P.Ur x":aX:`{L A !/0@K/Zwfp+x}ϴ;q>R!*2:C{JQNff|B1Y_B;      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnoM^`>U&1H B Y )+&&')'?'V'n''555"696{666666=7T777??????<@S@a@x@@@@@AAA B.BEBgB~BBBBBCCDDDDE5EGE^Ehi"i9iLicin/nFn]nmnnnnnnuۂ.ECZߞCZ~:Q}+Bd{0$&RR!W8W\\bcff(j?jlmmmnnpppptujvv6xMxzz{{G|^|}}z0҃džކ׈ˉE\ѰӰ)-:-<-(()2)./D/[///0011225526I688q99]:t:::Z;q;;<SGjGGGGHIJJ K"a9a7bNbRkikkk{{z||}}߲2Tkǵ%&&&f'}'Ʈ۰rWhjo|    ._v0G/FS!j!##'1'**.2.x2233678<O<j>>AA8LJLMLwNN5OLOOOPPwPPP QTUAXXXBTW_vyh 99999:9999 9999999999999999999999999999999999999999999999999 9999999999999999999999999   999999999999999999999999999999999999 99  99999999999999999999 99999999 99999999(-/6;=CHKgs}/279@EGMRTp| .168?DFLQSo{ 25:<CHJPUWs :=BDKPRX]_{!#).0LXcht!!!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!!!!  !!,Microsoft CorporationC:\DDK\DDPR\PNP.DOC@QMS-PS 810LPT1:PSCRIPTQMS-PS 810g od,,` +1XdCustom page 1BBCustom page 2BBCustom page 3BBQMS-PS 810g od,,` +1XdCustom page 1BBCustom page 2BBCustom page 3BBTimes New Roman Symbol &Arial5Courier NewTimes Roman 1Courier&Arial Narrow5Lucida Sans Typewriter#V h4Eedn$B    Microsoft CorporationMicrosoft Corporationࡱ>  usqywq