|
Figure 1
Configuration Manager Services
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. |
Figure 2
name
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
|