Service (CM_Xxx) | Description |
Add_Empty_Log_Conf | Creates an empty logical configuration for a given DEVNODE. First step in defining resource requirements for a device. |
Add_ID | Used during CONFIG_SETUP to add a hardware ID or compatible ID to a DEVNODE. |
Add_Range | Expand a memory range list by adding one more range description. |
Add_Res_Des | Add a resource descriptor to a growing logical configuration. |
Call_At_Appy_Time | Arrange an application time callback. |
Call_Enumerator_Function | Call the enumerator for a given DEVNODE. |
CallBack_Device_Driver | Call a device driver once for each device it manages, passing CONFIG_CALLBACK as the function code. |
CallBack_Enumerator | Call an enumerator function once for each device it enumerates, passing CONFIG_CALLBACK as the function code. This makes calls for each bus or controller rather than for each attached device. |
Create_DevNode | Create a new DEVNODE. This is the basic function for enumerators to use in expanding the hardware tree. |
Create_Range_List | Create an empty memory range list. |
Delete_Range | Remove a single memory range description from a range list. |
Deregister_Arbitrator | Deregister a resource arbitrator. |
Disable_DevNode | Disable a device. That is, stop using it. |
Dump_Range_List | Dump a range list for debugging. |
Dup_Range_List | Create a copy of a range list. |
Enable_DevNode | Reverse the effect of a Disable_DevNode call. |
Fail_Change_Config | Used by the Plug and Play BIOS enumerator to cancel a previously planned docking or undocking. |
First_Range | Retrieve the first range element in a range list. |
Free_Log_Conf | Release the memory used by a logical configuration. |
Free_Range_List | Release the memory used by a memory range list. |
Free_Res_Des | Release the memory used by a single resource descriptor. |
Get_Alloc_Log_Conf | Get the resources actually allocated for a device. This is the main service used by a device driver to learn what resources it may use. |
Get_Bus_Info | Retrieve the bus information installed by Set_Bus_Info. |
Get_Child | Get a pointer to the first child of a given DEVNODE. |
Get_CRC_CheckSum | Calculate a cyclic redundancy check for a given byte string. |
Get_DDBs | Locate the device descriptor block(s) for drivers associated with a DEVNODE. This allows the caller to do Directed_Sys_Control calls to those drivers. |
Get_Depth | Determine how deep a DEVNODE is in the hardware tree. |
Get_Device_Driver_Private_DWord | Retrieve the private value stored in the DEVNODE by Set_Device_Driver_Private_Dword. |
Get_Device_ID | Retrieve the ASCII device ID for a DEVNODE. |
Get_Device_ID_Size | Get the byte length of the device ID. This allows the caller to allocate memory for a call to Get_Device_ID. |
Get_DevNode_Key | Retrieve the ASCII name of the hardware or software registry key for a DEVNODE. |
Get_DevNode_Key_Size | Get the byte length of a registry pathname. This allows the caller to allocate memory for a call to Get_DevNode_Key. |
Get_DevNode_Status | Retrieve the current status of a DEVNODE. |
Get_First_Log_Conf | Get a handle to the first logical configuration for a DEVNODE. This is how the caller starts a loop over configurations. |
Get_Hardware_Profile_Info | Retrieve information about a hardware profile. |
Get_HW_Prof_Flags | Get configuration-specific flags for a single DEVNODE in a particular hardware profile. |
Get_Next_Log_Conf | Get a handle for the next logical configuration in a list of configurations. |
Get_Next_Res_Des | Get a handle for the first or next resource descriptor in a logical configuration. |
Get_Parent | Get a pointer to the parent of a DEVNODE. |
Get_Performance_Info | Retrieve performance information for debugging purposes. |
Get_Private_DWord | Retrieve the private DWORD that a driver stored about one DEVNODE in some other DEVNODE. |
Get_Res_Des_Data | Copy a resource descriptor given its handle. Used only by Ring 3 callers. |
Get_Res_Des_Data_Size | Get the byte length of resource data. This allows a Ring 3 caller to allocate memory for a call to Get_Res_Des_Data. |
Get_Sibling | Get the next sibling of a DEVNODE. Used during a loop over children of a given node. |
Get_Version | Get the version number (that is, 0x0400) of the CONFIGMG device driver. |
Intersect_Range_List | Create the intersection of two range lists. |
Invert_Range_List | Create the inversion of a range list. |
ISAPNP_To_CM | Convert a device's resource requirements from the format specified in the ISA Plug and Play specification to Configuration Manager's internal resource descriptor format. |
Load_DLVxDs | Dynamically load one or more VxDs. |
Locate_DevNode | Find a DEVNODE given its ASCII ID. |
Merge_Range_List | Create the union of two range lists. |
Modify_Res_Des | Modify a resource descriptor. Used only by Ring 3 callers. |
Move_DevNode | Used by Device Installer to eliminate duplicate DEVNODEs. |
Next_Range | Get the next range descriptor in a range list. |
Query_Arbitrator_Free_Data | Determine which resources managed by a resource arbitrator are free. |
Query_Arbitrator_Free_Size | Determine the byte length of an arbitrator's free data structure. This allows the caller to allocate memory for a call to Query_Abitrator_Free_Data. |
Query_Change_Config | Determine if it's okay to change from one hardware profile to another. |
Query_Remove_SubTree | Determine if it's okay to remove a DEVNODE and all of its children. |
Read_Registry_Log_Confs | Convert a logical configuration in the registry into Configuration Manager's internal form. Used by the Root Enumerator to configure legacy devices. |
Read_Registry_Value | Read a value from the registry. Used by all sorts of Plug and Play drivers to obtain information beyond normal configuration data. |
Recompute_HW_Prof | Used by the Plug and Play BIOS enumerator after a docking station change. |
Reenumerate_DevNode | Force Configuration Manager to enumerate a DEVNODE. Used, for example, when a bus or controller detects a hot hardware change. |
Register_Arbitrator | Register a function as a resource arbitrator. |
Register_Device_Driver | Register a device driver for a DEVNODE. Every device driver makes this call. |
Register_DevLoader | Indicates that a static VxD that earlier received a PNP_New_DevNode (DEVLOADER) message and returned CR_DEVLOADER_NOT_READY is now ready to be a Device Loader and wants to get the message a second time. Few device loaders make this call. |
Register_Enumerator | Register an enumeration function. Every bus or controller enumerator makes this call. |
Remove_SubTree | Removes a DEVNODE and its children from the hardware tree. This is part of removing a device from the system. |
Remove_Unmarked_Children | Removes DEVNODEs whose preservation marks were cleared by Reset_Children_Marks. |
Reset_Children_Marks | Clears the preservation mark for the children of a given DEVNODE. |
Run_Detection | Spawns the (Ring 3) detection DLL following insertion of a legacy card. |
Set_Bus_Info | Record information about a hardware bus represented by a given DEVNODE. |
Set_Device_Driver_Private_DWord | Set the private value in a DEVNODE. |
Set_HW_Prof | Used by Control Panel to change the current hardware profile. |
Set_HW_Prof_Flags | Set the profile-specific flags for a DEVNODE. |
Set_Private_DWord | Record a private value about one DEVNODE in some other DEVNODE. |
Set_Private_Problem | Record a "problem" in a DEVNODE so the class installer can diagnose it for the user. |
Setup_DevNode | Send a CONFIG_SETUP or CONFIG_READY to a DEVNODE's enumerator. |
Sort_NodeList | Used by a resource arbitrator to sort a list of logical configurations according to how easy their requirements will be to satisfy. |
Test_Range_Available | Determine if a memory range is available given reservations recorded in a range list. |
Write_Registry_Value | Set a value in the registry. |
Yield | Yield control until a time-out expires. Used to satisfy hardware timing requirements. |
Priority | Description |
LCPRI_FORCECONFIG | Configuration manually selected by the user |
LCPRI_BOOTCONFIG | Configuration established at boot-time by BIOS or card |
LCPRI_DESIRED | Preferred configuration giving better performance |
LCPRI_NORMAL | Configuration giving acceptable performance |
LCPRI_SUBOPTIMAL | Workable configuration giving poor performance |
LCPRI_RESTART | Configuration will require restarting Windows |
LCPRI_REBOOT | Configuration will require soft reboot of computer |
LCPRI_POWEROFF | Configuration will require hard reboot of computer |
LPCRI_HARDRECONFIG | Configuration will require user to change a jumper |
LPCRI_HARDWIRED | Only possible configuration |
Figure 3 Creating a Logical Configuration
CONFIGRET CM_HANDLER OnEnumerate(CONFIGFUNC cf,
SUBCONFIGFUNC scf, DEVNODE tonode, DEVNODE aboutnode,
ULONG flags)
{ // OnEnumerate
CONFIGRET code;
switch (cf)
{ // select on function code
case CONFIG_ENUMERATE: // cf == 5
{ // CONFIG_ENUMERATE
DEVNODE device; // DEVNODE for device
LOG_CONF logconf; // logical configuration
RES_DES resource; // resource descriptor handle
static IRQ_DES irq = {{0, 0, 0x00FF, 0}};
code = CM_Create_DevNode(&device, "SCHOOL\\WCO1234\\0000",tonode, 0);
if (code == CR_ALREADY_SUCH_DEVNODE)
return CR_SUCCESS;
CM_Add_Empty_Log_Conf(&logconf, device,
LCPRI_NORMAL,
BASIC_LOG_CONF | PRIORITY_EQUAL_LAST);
CM_Add_Res_Des(&resource, logconf, ResType_IRQ, &irq, sizeof(irq), 0);
return CR_SUCCESS;
} // CONFIG_ENUMERATE
default:
return CR_DEFAULT;
} // select on function code
} // OnEnumerate
Figure 4 Possible Alias/Decode Settings for an I/O Resource
Alias | Decode | Meaning |
0 | 0 | Card decodes all 16 bits of I/O address |
4 | 3 | Card decodes 10 bits of I/O address |
16 | 15 | Card decodes 12 bits of I/O address |
255 | 0 | Card is a PCI card that can use ports that would otherwise be reserved as 10-bit synonyms for ISA card ports |
Figure 5 SCHOOL.VXD
SCHOOL.MAK
all: school.vxd telepath.vxd
.asm.obj:
ml -coff -DBLD_COFF -DIS_32 -W2 -Zd -c -Cx -DMASM6 -Zi \
-DDEBUG $*.asm
.c.obj:
cl -c -Gs -Zdpl -Od -D_X86_ -YX -W3 -DDEBLEVEL=1 \
-DBLD_COFF -DDEBUG -DIS_32 $*.c
school.vxd : s_ctl.obj $*.obj $*.def $*.res
link @<<
-machine:i386 -def:$*.def -out:$@
-debug -debugtype:map
-map:$*.map -vxd vxdwraps.clb -nodefaultlib
s_ctl.obj $*.obj
<<
telepath.vxd: t_ctl.obj $*.obj $*.def
link @<<
-machine:i386 -def:$*.def -out:$@
-debug -debugtype:map
-map:$*.map -vxd vxdwraps.clb -nodefaultlib
t_ctl.obj $*.obj
<<
SCHOOL.DEF
VXD SCHOOL DYNAMIC
DESCRIPTION 'Sample Device'
SEGMENTS
_LPTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LDATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_DATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
CONST CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TLS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_BSS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_MSGTABLE CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_MSGDATA CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_IMSGTABLE CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_IMSGDATA CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_ITEXT CLASS 'ICODE' DISCARDABLE
_IDATA LASS 'ICODE' DISCARDABLE
_PTEXT CLASS 'PCODE' NONDISCARDABLE
_PDATA CLASS 'PDATA' NONDISCARDABLE SHARED
_STEXT CLASS 'SCODE' RESIDENT
_SDATA CLASS 'SCODE' RESIDENT
_DBOSTART CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBOCODE CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
DBODATA CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_16ICODE CLASS '16ICODE' PRELOAD DISCARDABLE
_RCODE CLASS 'RCODE'
EXPORTS
SCHOOL_DDB @1
S_CTL.ASM
.386p
include vmm.inc
include debug.inc
Declare_Virtual_Device SCHOOL, 1, 0, SCHOOL_Control, \
Undefined_Device_ID, Undefined_Init_Order
Begin_Control_Dispatch SCHOOL
Control_Dispatch Sys_Dynamic_Device_Init, \
_OnSysDynamicDeviceInit, cCall
Control_Dispatch Sys_Dynamic_Device_Exit, \
_OnSysDynamicDeviceExit, cCall
Control_Dispatch PNP_New_Devnode, _OnPnpNewDevnode, \
cCall, <ebx, edx>
End_Control_Dispatch SCHOOL
end
SCHOOL.C
#define WANTVXDWRAPS
#include <basedef.h>
#include <vmm.h>
#include <debug.h>
#include <vmmreg.h>
#include <vwin32.h>
#include <vxdwraps.h>
#include <configmg.h>
#include <regstr.h>
#ifdef DEBUG
#define ASSERT(e) if(!(e))\
{Debug_Printf("Assertion failure in " __FILE__ \
", line %d: " #e "\r\n", __LINE__);\
_asm int 1\
}
#else
#define ASSERT(e)
#endif
#define ResType_Telepath ((0x10 << 5) | 5)
typedef struct
{
int allocated; // index of allocated channel (-1 => none)
ULONG requested; // mask for requested channels
} TELEPATH_RESOURCE;
#pragma CM_PAGEABLE_DATA
#pragma CM_PAGEABLE_CODE
CONFIGRET CM_HANDLER OnEnumerate(CONFIGFUNC cf, CONFIGFUNC scf, DEVNODE tonode,
DEVNODE aboutnode, ULONG flags);
CONFIGRET CM_HANDLER OnArbitrateTelepath(ARBFUNC af, ULONG refdata,
DEVNODE devnode, NODELIST_HEADER h);
REGISTERID arbid;
BOOL OnSysDynamicDeviceInit()
{ // OnSysDynamicDeviceInit
CM_Register_Arbitrator(&arbid, ResType_Telepath, OnArbitrateTelepath, 0,
NULL, ARB_GLOBAL);
return TRUE;
} // OnSysDynamicDeviceInit
BOOL OnSysDynamicDeviceExit()
{ // OnSysDynamicDeviceExit
if (arbid)
CM_Deregister_Arbitrator(arbid, 0);
return TRUE;
} // OnSysDynamicDeviceExit
CONFIGRET OnPnpNewDevnode(DEVNODE devnode, DWORD loadtype)
{ // OnPnpNewDevnode
CONFIGRET code;
switch (loadtype)
{ // select function to perform
case DLVXD_LOAD_DEVLOADER: // loadtype == 1
code = CM_Register_Enumerator(devnode, OnEnumerate,
CM_REGISTER_ENUMERATOR_HARDWARE);
if (code != CR_SUCCESS)
return code;
return CM_Register_Device_Driver(devnode, NULL, 0,
CM_REGISTER_DEVICE_DRIVER_REMOVABLE);
} // select function to perform
return CR_DEFAULT;
} // OnPnpNewDevnode
CONFIGRET CM_HANDLER OnEnumerate(CONFIGFUNC cf, SUBCONFIGFUNC scf,
DEVNODE tonode, DEVNODE aboutnode,
ULONG flags)
{ // OnEnumerate
CONFIGRET code;
#ifdef DEBUG
char toid[MAX_DEVICE_ID_LEN], aboutid[MAX_DEVICE_ID_LEN];
DEBUG_CONFIG_NAMES
char *subfunc = "";
static char *substart[] = {"DYNAMIC_START", "FIRST_START"};
static char *substop[] = {"DYNAMIC_STOP", "HAS_PROBLEM"};
static char *subremove[] = {"DYNAMIC", "SHUTDOWN", "REBOOT"};
static char *subtest[] = {"CAN_STOP", "CAN_REMOVE"};
static char *subapm[] = {"TEST_STANDBY", "TEST_SUSPEND",
"TEST_STANDBY_FAILED", "TEST_SUSPEND_FAILED",
"TEST_STANDBY_SUCCEEDED","TEST_SUSPEND_SUCCEEDED",
"RESUME_STANDBY", "RESUME_SUSPEND",
"RESUME_CRITICAL", "UI_ALLOWED"};
CM_Get_Device_ID(tonode, toid, sizeof(toid), 0);
CM_Get_Device_ID(aboutnode, aboutid, sizeof(aboutid), 0);
switch (cf)
{ // get subfunction name
case CONFIG_START:
subfunc = substart[scf];
break;
case CONFIG_STOP:
subfunc = substop[scf];
break;
case CONFIG_REMOVE:
subfunc = subremove[scf];
break;
case CONFIG_TEST:
subfunc = subtest[scf];
break;
case CONFIG_APM:
subfunc = subapm[scf];
break;
} // get subfunction name
if (cf < NUM_CONFIG_COMMANDS)
Debug_Printf("SCHOOL ENUMERATOR: %s(%s), to %s, about %s\r\n",
lpszConfigName[cf], subfunc, toid, aboutid);
else
Debug_Printf("SCHOOL ENUMERATOR: %X(%X), to %s, about %s\r\n",
cf, toid, aboutid);
#endif
switch (cf)
{ // select on function code
case CONFIG_SETUP:
{ // CONFIG_SETUP
ULONG length; // length of class name
char class[64]; // device class
length = sizeof(class);
code = CM_Read_Registry_Value(aboutnode, NULL, "Class", REG_SZ, class,
&length, CM_REGISTRY_HARDWARE);
if (code == CR_NO_SUCH_VALUE)
{ // new device
CM_Write_Registry_Value(aboutnode, NULL, "Class", REG_SZ, "System",
6, CM_REGISTRY_HARDWARE);
CM_Write_Registry_Value(aboutnode, NULL, "HardwareID", REG_SZ,
"WCO1234", 6, CM_REGISTRY_HARDWARE);
} // new device
return CR_SUCCESS;
} // CONFIG_SETUP
case CONFIG_ENUMERATE: // cf == 5
{ // CONFIG_ENUMERATE
DEVNODE device; // DEVNODE for device
ULONG length; // length of class name
char class[64]; // device class
LOG_CONF logconf; // logical configuration
RES_DES resource; // resource descriptor handle
static IRQ_RESOURCE irq = {{0, 0, 0xFFFF, 0}};
static TELEPATH_RESOURCE telepath = {-1, 0xFF};
code = CM_Create_DevNode(&device, "SCHOOL\\WCO1234\\0000", tonode, 0);
if (code == CR_ALREADY_SUCH_DEVNODE)
return CR_SUCCESS;
CM_Add_Empty_Log_Conf(&logconf, device, LCPRI_NORMAL,
BASIC_LOG_CONF | PRIORITY_EQUAL_LAST);
CM_Add_Res_Des(&resource, logconf, ResType_IRQ, &irq, sizeof(irq), 0);
CM_Add_Res_Des(&resource, logconf, ResType_Telepath, &telepath,
sizeof(telepath), 0);
return CR_SUCCESS;
} // CONFIG_ENUMERATE
default:
return CR_DEFAULT;
} // select on function code
} // OnEnumerate
///////////////////////////////////////////////////////////////
// Telepathic I/O channel resource arbitrator
typedef struct nodelistheader_s *NODELISTHEADER;
typedef struct nodelist_s *PNODE;
typedef struct
{ // allocation placeholder
PNODE node; // current node
TELEPATH_RESOURCE* pres; // current resource descriptor
} ALLOCPLACE, *PALLOCPLACE; // allocation placeholder
int bitcount(ULONG mask)
{ // bitcount
int nbits = 0;
while (mask)
{ // count bits
if (mask & 1)
++nbits;
mask >>= 1;
} // count bits
return nbits;
} // bitcount
void sortnodes(NODELISTHEADER h)
{ // sortnodes
PNODE node = h->nlh_Head;
while (node)
{ // for each node
RES_DES hres = (RES_DES) node->nl_Test_Req;
#define pres ((TELEPATH_RESOURCE *) hres)
node->nl_ulSortDWord = 0;
while (CM_Get_Next_Res_Des(&hres, hres, ResType_Telepath, NULL, 0) ==
CR_SUCCESS)
node->nl_ulSortDWord += bitcount(pres->requested);
node = node->nl_Next;
#undef pres
} // for each node
CM_Sort_NodeList((NODELIST_HEADER) h, 0);
} // sortnodes
void release(NODELISTHEADER h, PULONG pmap)
{ // release
PNODE node = h->nlh_Head;
while (node)
{ // for each node
LOG_CONF logconf;
if (CM_Get_First_Log_Conf(&logconf,(DEVNODE) node->nl_ItsDevNode,
ALLOC_LOG_CONF)== CR_SUCCESS)
{ // release channel(s)
RES_DES hres = (RES_DES) logconf;
#define pres ((TELEPATH_RESOURCE *) hres)
while (CM_Get_Next_Res_Des(&hres, hres, ResType_Telepath, NULL, 0)
== CR_SUCCESS)
if (pres->allocated >= 0)
*pmap |= 1 << pres->allocated;
#undef pres
} // release channel(s)
node = node->nl_Next;
} // for each node
} // release
BOOL nextres(PALLOCPLACE p)
{ // nextres
ASSERT(p->node && p->node->nl_Test_Req);
if (!p->pres)
p->pres = (TELEPATH_RESOURCE *) p->node->nl_Test_Req;
while (CM_Get_Next_Res_Des((RES_DES*) &p->pres, (RES_DES) p->pres,
ResType_Telepath, NULL, 0) != CR_SUCCESS)
{ // no more of our resource
if (!(p->node = p->node->nl_Next))
return FALSE; // no more nodes in the list
p->pres = (TELEPATH_RESOURCE *) p->node->nl_Test_Req;
} // no more of our resource
return TRUE;
} // nextres
BOOL allocate(PALLOCPLACE p, PULONG pmap)
{ // allocate
int channel;
if (!nextres(p))
return TRUE;
for (p->pres->allocated = -1, channel = 0; channel < 32; ++channel)
{ // try to allocate a channel
ALLOCPLACE place = *p;
ULONG mask = 1 << channel;
ULONG tempmap = *pmap;
if ( !(tempmap & mask) || !(place.pres->requested & mask) )
continue;
tempmap &= ~mask; // do trial allocation
if (allocate(&place, &tempmap))
{ // successful allocation
*pmap = tempmap;
p->pres->allocated = channel;
return TRUE;
} // successful allocation
} // try to allocate a channel
} // allocate
BOOL reallocate(NODELISTHEADER h, PULONG pmap, BOOL forced)
{ // reallocate
PNODE node = h->nlh_Head;
while (node)
{ // for each node
RES_DES hres = (RES_DES) node->nl_Test_Req;
#define pres ((TELEPATH_RESOURCE *) hres)
while (CM_Get_Next_Res_Des(&hres, hres,ResType_Telepath, NULL, 0) ==
CR_SUCCESS)
{ // requires our resource
ULONG mask;
ASSERT(pres->allocated >= 0);
mask = 1 << pres->allocated;
if ((*pmap & mask) && !forced)
return FALSE; // one or more still in use
*pmap &= ~mask;
} // requires our resource
node = node->nl_Next;
#undef pres
} // for each node
return TRUE;
} // reallocate
CONFIGRET CM_HANDLER OnArbitrateTelepath(ARBFUNC af, ULONG refdata,
DEVNODE devnode, NODELIST_HEADER h)
{ // OnArbitrateTelepath
static ULONG free_map = 0xFF; // real allocation map
static ULONG free_copy = 0xDEADBEEF; // copy of map
switch (af)
{ // select on function
case ARB_TEST_ALLOC: // af == 0
{ // ARB_TEST_ALLOC
ALLOCPLACE place = {((NODELISTHEADER)h)->nlh_Head, NULL};
sortnodes((NODELISTHEADER) h);
free_copy = free_map;
release((NODELISTHEADER) h, &free_copy);
if (allocate(&place, &free_copy))
return CR_SUCCESS;
else
return CR_FAILURE;
} // ARB_TEST_ALLOC
case ARB_RETEST_ALLOC: // af == 1
case ARB_FORCE_ALLOC: // af == 6
free_copy = free_map;
release((NODELISTHEADER) h, &free_copy);
if (reallocate((NODELISTHEADER) h, &free_copy, af == ARB_FORCE_ALLOC))
return CR_SUCCESS;
else
return CR_FAILURE;
case ARB_SET_ALLOC: // af == 2
ASSERT(free_copy != 0xDEADBEEF);
free_map = free_copy;
free_copy = 0xDEADBEEF;
return CR_SUCCESS;
case ARB_RELEASE_ALLOC: // af == 3
free_copy = 0xDEADBEEF;
return CR_SUCCESS;
case ARB_QUERY_FREE: // af == 4
{ // ARB_QUERY_FREE
struct arbitfree_s *p = (struct arbitfree_s *) h;
p->af_SizeOfInfo = sizeof(ULONG);
p->af_PointerToInfo = (PVOID*) &free_map;
return CR_SUCCESS;
} // ARB_QUERY_FREE
case ARB_REMOVE: // af == 5
return CR_SUCCESS;
default:
return CR_DEFAULT;
} // select on function
} // OnArbitrateTelepath
TELEPATH.DEF
T_CTL.ASM
These two files are essentially the same as SCHOOL.DEF and S_CTL.ASM, respectively. SCHOOL.MAK also builds TELEPATH.VXD.
TELEPATH.C
#define WANTVXDWRAPS
#include <basedef.h>
#include <vmm.h>
#include <debug.h>
#include <vmmreg.h>
#include <vxdwraps.h>
#include <configmg.h>
#include <regstr.h>
static BYTE irq; // allocated IRQ
CONFIGRET OnConfigure(CONFIGFUNC cf, SUBCONFIGFUNC scf, DEVNODE devnode,
DWORD refdata, ULONG flags);
BOOL OnSysDynamicDeviceInit()
{ // OnSysDynamicDeviceInit
return TRUE;
} // OnSysDynamicDeviceInit
BOOL OnSysDynamicDeviceExit()
{ // OnSysDynamicDeviceExit
return TRUE;
} // OnSysDynamicDeviceExit
CONFIGRET OnPnpNewDevnode(DEVNODE devnode, DWORD loadtype)
{ // OnPnpNewDevnode
switch (loadtype)
{ // select function to perform
case DLVXD_LOAD_DEVLOADER: // loadtype == 2
return CM_Register_Device_Driver(devnode, OnConfigure, 0,
(CM_REGISTER_DEVICE_DRIVER_REMOVABLE |
CM_REGISTER_DEVICE_DRIVER_DISABLEABLE));
} // select function to perform
return CR_DEFAULT;
} // OnPnpNewDevnode
CONFIGRET OnConfigure(CONFIGFUNC cf, SUBCONFIGFUNC scf, DEVNODE devnode,
DWORD refdata, ULONG flags)
{ // OnConfigure
#ifdef DEBUG
char id[MAX_DEVICE_ID_LEN];
DEBUG_CONFIG_NAMES
char *subfunc = "";
static char *substart[] = {"DYNAMIC_START", "FIRST_START"};
static char *substop[] = {"DYNAMIC_STOP", "HAS_PROBLEM"};
static char *subremove[] = {"DYNAMIC", "SHUTDOWN",
"REBOOT"};
static char *subtest[] = {"CAN_STOP", "CAN_REMOVE"};
static char *subapm[] ={"TEST_STANDBY", "TEST_SUSPEND",
"TEST_STANDBY_FAILED", "TEST_SUSPEND_FAILED",
"TEST_STANDBY_SUCCEEDED", "TEST_SUSPEND_SUCCEEDED",
"RESUME_STANDBY", "RESUME_SUSPEND",
"RESUME_CRITICAL", "UI_ALLOWED"};
switch (cf)
{ // get subfunction name
case CONFIG_START:
subfunc = substart[scf];
break;
case CONFIG_STOP:
subfunc = substop[scf];
break;
case CONFIG_REMOVE:
subfunc = subremove[scf];
break;
case CONFIG_TEST:
subfunc = subtest[scf];
break;
case CONFIG_APM:
subfunc = subapm[scf];
break;
} // get subfunction name
CM_Get_Device_ID(devnode, id, sizeof(id), 0);
if (cf < NUM_CONFIG_COMMANDS)
Debug_Printf("TELEPATH DRIVER: %s(%s), %s\r\n", lpszConfigName[cf],
subfunc, id);
else
Debug_Printf("TELEPATH DRIVER: %X(%X), %s\r\n", cf, scf, id);
#endif
switch (cf)
{ // select on function code
case CONFIG_START: // cf == 1
{ // CONFIG_START
CMCONFIG config;
CM_Get_Alloc_Log_Conf(&config, devnode, CM_GET_ALLOC_LOG_CONF_ALLOC);
irq = config.bIRQRegisters[0];
{
#define ResType_Telepath ((0x10 << 5) | 5)
typedef struct
{ // telepath resource
ULONG allocated; // mask for allocated channel
ULONG requested; // mask for requested channels
} TELEPATH_RESOURCE; // telepath resource
LOG_CONF logconf;
RES_DES hres;
#define pres ((TELEPATH_RESOURCE*) hres)
CM_Get_First_Log_Conf(&logconf, devnode, ALLOC_LOG_CONF);
if (CM_Get_Next_Res_Des(&hres, (RES_DES) logconf, ResType_Telepath,
NULL, 0) == CR_SUCCESS)
{ // has telepath channel
// do something with pres->allocated
} // has telepath channel
#undef pres
}
// Here we would initialize the device, doing things
// like VPICD_Virtualize_IRQ, etc.
return CR_SUCCESS;
} // CONFIG_START
case CONFIG_REMOVE: // cf == 4
case CONFIG_STOP: // cf == 2
irq = 255;
return CR_SUCCESS;
default:
return CR_DEFAULT;
} // select on function code
} // OnConfigure
Figure 6 Arbitrator Function Codes
Function Code | Description |
ARB_TEST_ALLOC | Perform trial allocation of resource |
ARB_RETEST_ALLOC | Verify previous trial allocation |
ARB_FORCE_ALLOC | Retest but don't fail previous trial allocation |
ARG_SET_ALLOC | Commit previous trial allocation |
ARB_RELEASE_ALLOC | Discard previous trial allocation |
ARB_QUERY_FREE | Return information about free resources |
ARB_REMOVE | Prepare for removal of arbitrator |
Figure 7 nodelistheader_s and nodelist_s Structures
struct nodelistheader_s
{ // node list header
struct nodelist_s* nlh_Head; // 00 head of list
struct nodelist_s* nlh_Tail; // 04 tail of list
}; // 08 node list header
struct nodelist_s
{ // node list element
struct nodelist_s* nl_Next; // 00 chain to next element
struct nodelist_s* nl_Prev; // 04 chain to previous element
struct devnode_s* nl_ItsDevNode; // 08 a device node that needs resources
struct Log_Conf* nl_Test_Req; // 0C a logical configuration for that
// DEVNODE
ULONG nl_ulSortDWord; // 10 sort order for CM_Sort_NodeList
}; // 14 node list element
Figure 8 Configuration Functions for Device Drivers
Function | Description |
CONFIG_APM | Power management event is occurring |
CONFIG_CALLBACK | Someone did a CM_CallBack_-Device_Driver |
CONFIG_FILTER | Filter (restrict) logical configurations |
CONFIG_PREREMOVE | Prepare for removal of device |
CONFIG_PREREMOVE2 | Prepare for removal of device |
CONFIG_PRESHUTDOWN | System is about to shut down |
CONFIG_REMOVE | Device is being removed from the system |
CONFIG_SHUTDOWN | System is shutting down |
CONFIG_START | Start using the allocated configuration |
CONFIG_STOP | Stop using the current configuration |
CONFIG_TEST | Can you stop using configuration, or can you be removed? |
CONFIG_TEST_FAILED | Previous CONFIG_TEST failed |
CONFIG_TEST_SUCCEEDED | Previous CONFIG_TEST succeeded |
CONFIG_VERIFY_DEVICE | Is your legacy card present? |
Figure 9 Getting a Device's Configuration
CONFIGRET OnConfigure(CONFIGFUNC cf, SUBCONFIGFUNC scf,
DEVNODE devnode, DWORD refdata, ULONG flags)
{ // OnConfigure
switch (cf)
{ // select on function code
case CONFIG_START: // cf == 1
{ // CONFIG_START
CMCONFIG config;
CM_Get_Alloc_Log_Conf(&config, devnode,
CM_GET_ALLOC_LOG_CONF_ALLOC);
irq = config.bIRQRegisters[0]; // for example
// [virtualize IRQ and do other initialization]
return CR_SUCCESS;
} // CONFIG_START
default:
return CR_DEFAULT;
} // select on function code
} // OnConfigure
Figure 10 CMCONFIG Structure
typedef struct Config_Buff_s {
WORD wNumMemWindows; // 00 Num memory windows
DWORD dMemBase[MAX_MEM_REGISTERS]; // 02 Memory window base [9]
DWORD dMemLength[MAX_MEM_REGISTERS]; // 26 Memory window length [9]
WORD wMemAttrib[MAX_MEM_REGISTERS]; // 4A Memory window Attrib [9]
WORD wNumIOPorts; // 5C Num IO ports
WORD wIOPortBase[MAX_IO_PORTS]; // 5E I/O port base [20]
WORD wIOPortLength[MAX_IO_PORTS]; // 86 I/O port length [20]
WORD wNumIRQs; // AE Num IRQ info
BYTE bIRQRegisters[MAX_IRQS]; // B0 IRQ list [7]
BYTE bIRQAttrib[MAX_IRQS]; // B7 IRQ Attrib list [7]
WORD wNumDMAs; // BE Num DMA channels
BYTE bDMALst[MAX_DMA_CHANNELS]; // C0 DMA list [7]
WORD wDMAAttrib[MAX_DMA_CHANNELS]; // C7 DMA Attrib list [7]
BYTE bReserved1[3]; // D5 Reserved
} CMCONFIG; // D8
Figure 14 SCHOOLUI.DLL
SCHOOLUI.DEF
LIBRARY SCHOOLUI
EXETYPE WINDOWS
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE SINGLE
HEAPSIZE 1024
EXPORTS
WEP PRIVATE
EnumPropPages @1
SCHOOLUI.RC
//Microsoft App Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
///////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_STATUS DIALOG DISCARDABLE 0, 0, 142, 106
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION |
WS_SYSMENU
CAPTION "Status"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Telepathic Channel:",IDC_STATIC,3,9,74,8
LTEXT "(None)",IDC_CHANNEL,93,9,35,7
END
#ifdef APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
///////////////////////////////////////////////////////////////
#endif // APSTUDIO_INVOKED
#ifndef APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
///////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
RESOURCE.H
//{{NO_DEPENDENCIES}}
// App Studio generated include file.
// Used by SCHOOLUI.RC
//
#define SCHOOL 101
#define IDD_STATUS 103
#define IDC_CHANNEL 1000
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
SCHOOLUI.C
#include <windows.h>
#include <commctrl.h>
#include <setupx.h>
#define EXPORT __export
#define Not_VxD // to get ring-3 dcls
#include <vmm.h>
#define MIDL_PASS // suppress 32-bit only #pragma pack(push)
#include <configmg.h>
#include "resource.h"
BOOL WINAPI EXPORT StatusDlgProc(HWND, UINT, WPARAM, LPARAM);
///////////////////////////////////////////////////////////////
BOOL WINAPI EXPORT EnumPropPages(LPDEVICE_INFO pdi,
LPFNADDPROPSHEETPAGE AddPage, LPARAM lParam)
{ // EnumPropPages
PROPSHEETPAGE status; // status property page
HPROPSHEETPAGE hstatus;
status.dwSize = sizeof(PROPSHEETPAGE);
status.dwFlags = PSP_USETITLE;
_asm mov status.hInstance, ds
status.pszTemplate = MAKEINTRESOURCE(IDD_STATUS);
status.hIcon = NULL;
status.pszTitle = "Status";
status.pfnDlgProc = StatusDlgProc;
status.lParam = (LPARAM) pdi->dnDevnode;
status.pfnCallback = NULL;
hstatus = CreatePropertySheetPage(&status);
if (!hstatus)
return TRUE;
if (!AddPage(hstatus, lParam))
DestroyPropertySheetPage(hstatus);
return TRUE;
} // EnumPropPages
///////////////////////////////////////////////////////////////
BOOL WINAPI EXPORT StatusDlgProc(HWND hdlg, UINT msg,
WPARAM wParam, LPARAM lParam)
{ // StatusDlgProc
switch (msg)
{ // process message
case WM_INITDIALOG:
{ // WM_INITDIALOG
#define ResType_Telepath ((0x10 << 5) | 5)
typedef struct
{ // telepath resource
ULONG allocated; // mask for allocated channel
ULONG requested; // mask for requested channels
} TELEPATH_RESOURCE;// telepath resource
LOG_CONF logconf;
RES_DES hres;
DEVNODE devnode = (DEVNODE) ((LPPROPSHEETPAGE) lParam)->lParam;
if (CM_Get_First_Log_Conf(&logconf, devnode, ALLOC_LOG_CONF)== CR_SUCCESS
&& CM_Get_Next_Res_Des(&hres, (RES_DES) logconf,
ResType_Telepath, NULL, 0) == CR_SUCCESS)
{ // has telepath channel
TELEPATH_RESOURCE res;
CM_Get_Res_Des_Data(hres, &res, sizeof(res), 0);
if (res.allocated >= 0)
SetDlgItemInt(hdlg, IDC_CHANNEL, res.allocated, FALSE);
} // has telepath channel
} // WM_INITDIALOG
} // process message
return FALSE;
} // StatusDlgProc