SCHOOL.C
Upload User: linklycbj
Upload Date: 2009-11-12
Package Size: 447k
Code Size: 13k
Category:

Windows Develop

Development Platform:

WINDOWS

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. //   SCHOOL.C -- Bus Enumerator for the School Bus
  4. //
  5. ///////////////////////////////////////////////////////////////////////////////
  6. #define WANTVXDWRAPS
  7. #include <basedef.h>
  8. #include <vmm.h>
  9. #include <debug.h>
  10. #include <vmmreg.h>
  11. #include <vwin32.h>
  12. #include <vxdwraps.h>
  13. #include <configmg.h>
  14. #include <regstr.h>
  15. #ifdef DEBUG
  16. #define ASSERT(e) if(!(e)){Debug_Printf("Assertion failure in " __FILE__ ", line %d: " #e "rn", __LINE__);
  17. _asm int 1
  18. }
  19. #else
  20. #define ASSERT(e)
  21. #endif
  22. // Dummy private resource identifier. This would be appropriate for the fifth
  23. // resource created by an OEM to whom Microsoft had assigned OEM ID 0x10.
  24. // DON'T JUST USE THIS ID FOR YOUR OWN PRIVATE RESOURCE!
  25. #define ResType_Telepath ((0x10 << 5) | 5)
  26. typedef struct
  27. { // telepath resource description
  28. int allocated; // index of allocated channel (-1 means none)
  29. ULONG requested; // mask for requested channels
  30. } TELEPATH_RESOURCE; // telepath resource description
  31. #pragma CM_PAGEABLE_DATA
  32. #pragma CM_PAGEABLE_CODE
  33. CONFIGRET CM_HANDLER OnEnumerate(CONFIGFUNC cf, SUBCONFIGFUNC scf, DEVNODE tonode, DEVNODE aboutnode, ULONG flags);
  34. CONFIGRET CM_HANDLER OnArbitrateTelepath(ARBFUNC af, ULONG refdata, DEVNODE devnode,
  35. NODELIST_HEADER h);
  36. REGISTERID arbid;
  37. BOOL OnSysDynamicDeviceInit()
  38. { // OnSysDynamicDeviceInit
  39. CM_Register_Arbitrator(&arbid, ResType_Telepath,
  40. OnArbitrateTelepath, 0, NULL, ARB_GLOBAL);
  41. return TRUE;
  42. } // OnSysDynamicDeviceInit
  43. BOOL OnSysDynamicDeviceExit()
  44. { // OnSysDynamicDeviceExit
  45. if (arbid)
  46. CM_Deregister_Arbitrator(arbid, 0);
  47. return TRUE;
  48. } // OnSysDynamicDeviceExit
  49. CONFIGRET OnPnpNewDevnode(DEVNODE devnode, DWORD loadtype)
  50. { // OnPnpNewDevnode
  51. CONFIGRET code;
  52. switch (loadtype)
  53. { // select function to perform
  54. case DLVXD_LOAD_DEVLOADER: // loadtype == 1
  55. code = CM_Register_Enumerator(devnode, OnEnumerate,
  56. CM_REGISTER_ENUMERATOR_HARDWARE);
  57. if (code != CR_SUCCESS)
  58. return code;
  59. return CM_Register_Device_Driver(devnode, NULL, 0,
  60. CM_REGISTER_DEVICE_DRIVER_REMOVABLE);
  61. } // select function to perform
  62. return CR_DEFAULT;
  63. } // OnPnpNewDevnode
  64. CONFIGRET CM_HANDLER OnEnumerate(CONFIGFUNC cf, SUBCONFIGFUNC scf,
  65. DEVNODE tonode, DEVNODE aboutnode, ULONG flags)
  66. { // OnEnumerate
  67. CONFIGRET code;
  68. #ifdef DEBUG
  69. char toid[MAX_DEVICE_ID_LEN], aboutid[MAX_DEVICE_ID_LEN];
  70. DEBUG_CONFIG_NAMES
  71. char *subfunc = "";
  72. static char *substart[] = {"DYNAMIC_START", "FIRST_START"};
  73. static char *substop[] = {"DYNAMIC_STOP", "HAS_PROBLEM"};
  74. static char *subremove[] = {"DYNAMIC", "SHUTDOWN", "REBOOT"};
  75. static char *subtest[] = {"CAN_STOP", "CAN_REMOVE"};
  76. static char *subapm[] = {"TEST_STANDBY", "TEST_SUSPEND",
  77. "TEST_STANDBY_FAILED", "TEST_SUSPEND_FAILED",
  78. "TEST_STANDBY_SUCCEEDED", "TEST_SUSPEND_SUCCEEDED",
  79. "RESUME_STANDBY", "RESUME_SUSPEND", "RESUME_CRITICAL",
  80. "UI_ALLOWED"};
  81. CM_Get_Device_ID(tonode, toid, sizeof(toid), 0);
  82. CM_Get_Device_ID(aboutnode, aboutid, sizeof(aboutid), 0);
  83. switch (cf)
  84. { // get subfunction name
  85. case CONFIG_START:
  86. subfunc = substart[scf];
  87. break;
  88. case CONFIG_STOP:
  89. subfunc = substop[scf];
  90. break;
  91. case CONFIG_REMOVE:
  92. subfunc = subremove[scf];
  93. break;
  94. case CONFIG_TEST:
  95. subfunc = subtest[scf];
  96. break;
  97. case CONFIG_APM:
  98. subfunc = subapm[scf];
  99. break;
  100. } // get subfunction name
  101. if (cf < NUM_CONFIG_COMMANDS)
  102. Debug_Printf("SCHOOL ENUMERATOR: %s(%s), to %s, about %srn", lpszConfigName[cf], subfunc, toid, aboutid);
  103. else
  104. Debug_Printf("SCHOOL ENUMERATOR: %X(%X), to %s, about %srn", cf, toid, aboutid);
  105. #endif
  106. switch (cf)
  107. { // select on function code
  108. case CONFIG_SETUP:
  109. { // CONFIG_SETUP
  110. ULONG length; // length of class name
  111. char class[64]; // device class
  112. // The very first time we add the device to the hardware
  113. // tree, CONFIGMG will launch the device installer to load
  114. // a driver. To avoid having the initial dialog say the
  115. // device class is "Unknown", force the class in the
  116. // registry key to be "System" instead. Similarly force
  117. // the hardware ID so the installer knows which driver to
  118. // install. This knowledge is similar to what you'd discover
  119. // from a real Plug and Play device.
  120. length = sizeof(class);
  121. code = CM_Read_Registry_Value(aboutnode, NULL, "Class",
  122. REG_SZ, class, &length, CM_REGISTRY_HARDWARE);
  123. if (code == CR_NO_SUCH_VALUE)
  124. { // new device
  125. CM_Write_Registry_Value(aboutnode, NULL, "Class",
  126. REG_SZ, "System", 6, CM_REGISTRY_HARDWARE);
  127. CM_Write_Registry_Value(aboutnode, NULL, "HardwareID",
  128. REG_SZ, "WCO1234", 6, CM_REGISTRY_HARDWARE);
  129. } // new device
  130. return CR_SUCCESS;
  131. } // CONFIG_SETUP
  132. case CONFIG_ENUMERATE: // cf == 5
  133. { // CONFIG_ENUMERATE
  134. DEVNODE device; // DEVNODE for device
  135. LOG_CONF logconf; // logical configuration
  136. RES_DES resource; // resource descriptor handle
  137. static IRQ_RESOURCE irq = {{0, 0, 0xFFFF, 0}};
  138. static TELEPATH_RESOURCE telepath = {-1, 0xFF};
  139. // Create a DEVNODE for one device. In real life, we'd
  140. // either use a hardware detection scheme to enumerate
  141. // devices attached to the bus, or else we'd enumerate
  142. // a subkey of the registry (e.g., ENUMSCHOOL) to locate
  143. // devices.
  144. code = CM_Create_DevNode(&device, "SCHOOL\WCO1234\0000",
  145. tonode, 0);
  146. if (code == CR_ALREADY_SUCH_DEVNODE)
  147. return CR_SUCCESS; // nothing to do on reenumeration
  148. // Create a logical configuration for our one device.
  149. // Pretend the device needs an IRQ and one telepathic channel
  150. CM_Add_Empty_Log_Conf(&logconf, device, LCPRI_NORMAL,
  151. BASIC_LOG_CONF | PRIORITY_EQUAL_LAST);
  152. CM_Add_Res_Des(&resource, logconf, ResType_IRQ,
  153. &irq, sizeof(irq), 0);
  154. CM_Add_Res_Des(&resource, logconf, ResType_Telepath,
  155. &telepath, sizeof(telepath), 0);
  156. return CR_SUCCESS;
  157. } // CONFIG_ENUMERATE
  158. default:
  159. return CR_DEFAULT;
  160. } // select on function code
  161. } // OnEnumerate
  162. DWORD OnDeviceIoControl(PDIOCPARAMETERS p)
  163. { // OnDeviceIoControl
  164. switch (p->dwIoControlCode)
  165. { // select on function code
  166. case 1:
  167. Debug_Printf("Issuing CM_Callback_Enumerator callrn");
  168. CM_CallBack_Enumerator(OnEnumerate, 0);
  169. break;
  170. } // select on function code
  171. return 0;
  172. } // OnDeviceIoControl
  173. ///////////////////////////////////////////////////////////////////////
  174. // Telepathic I/O channel resource arbitrator
  175. typedef struct nodelistheader_s *NODELISTHEADER;
  176. typedef struct nodelist_s *PNODE;
  177. typedef struct
  178. { // allocation placeholder
  179. PNODE node; // current node
  180. TELEPATH_RESOURCE* pres; // current resource descriptor
  181. } ALLOCPLACE, *PALLOCPLACE; // allocation placeholder
  182. // SORTNODES sorts the node list into increasing order by flexibility of
  183. // allocation demands.
  184. int bitcount(ULONG mask)
  185. { // bitcount
  186. int nbits = 0;
  187. while (mask)
  188. { // count bits
  189. if (mask & 1)
  190. ++nbits;
  191. mask >>= 1;
  192. } // count bits
  193. return nbits;
  194. } // bitcount
  195. void sortnodes(NODELISTHEADER h)
  196. { // sortnodes
  197. PNODE node = h->nlh_Head;
  198. while (node)
  199. { // for each node
  200. RES_DES hres = (RES_DES) node->nl_Test_Req;
  201. #define pres ((TELEPATH_RESOURCE *) hres)
  202. node->nl_ulSortDWord = 0;
  203. while (CM_Get_Next_Res_Des(&hres, hres, ResType_Telepath, NULL, 0) == CR_SUCCESS)
  204. node->nl_ulSortDWord += bitcount(pres->requested);
  205. node = node->nl_Next;
  206. #undef pres
  207. } // for each node
  208. CM_Sort_NodeList((NODELIST_HEADER) h, 0);
  209. } // sortnodes
  210. // RELEASE walks through the node list to release assigned resources
  211. void release(NODELISTHEADER h, PULONG pmap)
  212. { // release
  213. PNODE node = h->nlh_Head;
  214. while (node)
  215. { // for each node
  216. LOG_CONF logconf;
  217. // Find the allocated configuration (if any) for this devnode. Then loop over
  218. // its resource descriptors to find the ones for our resource and release
  219. // the assignment(s)
  220. if (CM_Get_First_Log_Conf(&logconf, (DEVNODE) node->nl_ItsDevNode, ALLOC_LOG_CONF) == CR_SUCCESS)
  221. { // release this device's channel(s)
  222. RES_DES hres = (RES_DES) logconf;
  223. #define pres ((TELEPATH_RESOURCE *) hres)
  224. while (CM_Get_Next_Res_Des(&hres, hres, ResType_Telepath, NULL, 0) == CR_SUCCESS)
  225. if (pres->allocated >= 0)
  226. *pmap |= 1 << pres->allocated; // release the one assigned to this log conf
  227. #undef pres
  228. } // release this device's channel(s)
  229. node = node->nl_Next;
  230. } // for each node
  231. } // release
  232. // ALLOCATE attempts to allocate resources to devices using the requested possibilities
  233. // recorded in the logical configurations.
  234. BOOL nextres(PALLOCPLACE p)
  235. { // nextres
  236. ASSERT(p->node && p->node->nl_Test_Req);
  237. if (!p->pres)
  238. p->pres = (TELEPATH_RESOURCE *) p->node->nl_Test_Req;
  239. while (CM_Get_Next_Res_Des((RES_DES*) &p->pres, (RES_DES) p->pres, ResType_Telepath, NULL, 0) != CR_SUCCESS)
  240. { // no more descriptors of our resource
  241. if (!(p->node = p->node->nl_Next))
  242. return FALSE; // no more nodes in the list
  243. p->pres = (TELEPATH_RESOURCE *) p->node->nl_Test_Req;
  244. } // no more descriptors of our resource
  245. return TRUE;
  246. } // nextres
  247. BOOL allocate(ALLOCPLACE place, PULONG pmap)
  248. { // allocate
  249. int channel; // next channel to try allocating
  250. if (!nextres(&place))
  251. return TRUE; // no more of our resource needed, so we've succeeded
  252. for (place.pres->allocated = -1, channel = 0; channel < 8; ++channel)
  253. { // try to allocate a channel
  254. ULONG mask = 1 << channel;
  255. ULONG tempmap = *pmap;
  256. if ((tempmap & mask) && (place.pres->requested & mask))
  257. { // do trial allocation
  258. tempmap &= ~mask;
  259. if (allocate(place, &tempmap))
  260. { // successful allocation
  261. *pmap = tempmap;
  262. place.pres->allocated = channel;
  263. return TRUE;
  264. } // successful allocation
  265. } // do trial allocation
  266. } // try to allocate a channel
  267. return FALSE; // all channels in use
  268. } // allocate
  269. // REALLOCATE attempts to reallocate the same resources without regard to which
  270. // alternative possibilities exist
  271. BOOL reallocate(NODELISTHEADER h, PULONG pmap, BOOL forced)
  272. { // reallocate
  273. PNODE node = h->nlh_Head;
  274. while (node)
  275. { // for each node
  276. RES_DES hres = (RES_DES) node->nl_Test_Req;
  277. #define pres ((TELEPATH_RESOURCE *) hres)
  278. while (CM_Get_Next_Res_Des(&hres, hres, ResType_Telepath, NULL, 0) == CR_SUCCESS)
  279. { // requires our resource
  280. ULONG mask;
  281. ASSERT(pres->allocated >= 0);
  282. mask = 1 << pres->allocated;
  283. if ((*pmap & mask) && !forced)
  284. return FALSE; // one or more still in use
  285. *pmap &= ~mask;
  286. } // requires our resource
  287. node = node->nl_Next;
  288. #undef pres
  289. } // for each node
  290. return TRUE;
  291. } // reallocate
  292. // OnArbitrateTelepath is the resource arbitrator for telepathic I/O channels
  293. CONFIGRET CM_HANDLER OnArbitrateTelepath(ARBFUNC af, ULONG refdata, DEVNODE devnode,
  294. NODELIST_HEADER h)
  295. { // OnArbitrateTelepath
  296. static ULONG free_map = 0xFF; // real allocation map
  297. static ULONG free_copy = 0xDEADBEEF; // copy of allocation map
  298. switch (af)
  299. { // select on arbitration function
  300. // TEST function: Examine each of our resource descriptors in the node list and
  301. // try to allocated one of the possible choices
  302. case ARB_TEST_ALLOC: // af == 0
  303. { // ARB_TEST_ALLOC
  304. ALLOCPLACE place = {((NODELISTHEADER)h)->nlh_Head, NULL};
  305. sortnodes((NODELISTHEADER) h);
  306. free_copy = free_map;
  307. release((NODELISTHEADER) h, &free_copy);
  308. if (allocate(place, &free_copy))
  309. return CR_SUCCESS;
  310. else
  311. return CR_FAILURE;
  312. } // ARB_TEST_ALLOC
  313. // RETEST and FORCE functions: Examine each of our resource descriptors in the node
  314. // list and allocate the one which is marked allocated in the test config. This
  315. // differs from TEST by (a) not sorting the node list because it makes no difference,
  316. // and (b) not even looking at the possible alternative allocations
  317. case ARB_RETEST_ALLOC: // af == 1
  318. case ARB_FORCE_ALLOC: // af == 6
  319. free_copy = free_map;
  320. release((NODELISTHEADER) h, &free_copy);
  321. if (reallocate((NODELISTHEADER) h, &free_copy, af == ARB_FORCE_ALLOC))
  322. return CR_SUCCESS;
  323. else
  324. return CR_FAILURE;
  325. // SET commits the previous trial allocation
  326. case ARB_SET_ALLOC: // af == 2
  327. ASSERT(free_copy != 0xDEADBEEF);
  328. free_map = free_copy;
  329. free_copy = 0xDEADBEEF;
  330. return CR_SUCCESS;
  331. // RELEASE discards the previous trial allocation
  332. case ARB_RELEASE_ALLOC: // af == 3
  333. free_copy = 0xDEADBEEF;
  334. return CR_SUCCESS;
  335. // QUERY_FREE returns free resource information in our internal format. The
  336. // caller has to know what to expect.
  337. case ARB_QUERY_FREE: // af == 4
  338. { // ARB_QUERY_FREE
  339. struct arbitfree_s *p = (struct arbitfree_s *) h; // ugh!
  340. p->af_SizeOfInfo = sizeof(ULONG);
  341. p->af_PointerToInfo = (PVOID*) &free_map;
  342. return CR_SUCCESS;
  343. } // ARB_QUERY_FREE
  344. case ARB_REMOVE: // af == 5
  345. return CR_SUCCESS;
  346. default:
  347. return CR_DEFAULT;
  348. } // select on arbitration function
  349. } // OnArbitrateTelepath