Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

743 lines
20 KiB

  1. //#define UNICODE
  2. #include <windows.h>
  3. #include <tchar.h>
  4. #include <stdlib.h>
  5. #include <malloc.h>
  6. #include <basetyps.h>
  7. #include <regstr.h>
  8. #include <devioctl.h>
  9. #include <initguid.h>
  10. #include <usb.h>
  11. #include <usbuser.h>
  12. #include <setupapi.h>
  13. #include <cfgmgr32.h>
  14. #include <assert.h>
  15. #include "hccoin.h"
  16. #define PSTR LPSTR
  17. BOOL Win2k = FALSE;
  18. #if DBG
  19. #define TEST_TRAP() DebugBreak()
  20. ULONG
  21. _cdecl
  22. KdPrintX(
  23. PCH Format,
  24. ...
  25. )
  26. /*++
  27. Routine Description:
  28. Debug Print function.
  29. Arguments:
  30. Return Value:
  31. --*/
  32. {
  33. va_list list;
  34. int i;
  35. int arg[6];
  36. TCHAR tmp[256];
  37. #ifdef UNICODE
  38. OutputDebugString(L"HCCOIN.DLL:");
  39. #else
  40. OutputDebugString("HCCOIN.DLL:");
  41. #endif
  42. va_start(list, Format);
  43. for (i=0; i<6; i++) {
  44. arg[i] = va_arg(list, int);
  45. wsprintf((PSTR)&tmp[0], Format, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
  46. }
  47. OutputDebugString((PSTR)tmp);
  48. return 0;
  49. }
  50. #define KdPrint(_x_) KdPrintX _x_
  51. #else
  52. #define KdPrint(_x_)
  53. #define TEST_TRAP()
  54. #endif
  55. DWORD
  56. HCCOIN_Win2k (
  57. DI_FUNCTION InstallFunction,
  58. HDEVINFO DeviceInfoSet,
  59. PSP_DEVINFO_DATA DeviceInfoData,
  60. PCOINSTALLER_CONTEXT_DATA Context
  61. )
  62. {
  63. DWORD status = NO_ERROR;
  64. KdPrint(("HCCOIN_Win2k 0x%x\n", InstallFunction));
  65. KdPrint(("Context %08.8x, DeviceInfoData %08.8x\n",
  66. Context, DeviceInfoData));
  67. switch(InstallFunction) {
  68. case DIF_DESTROYPRIVATEDATA:
  69. KdPrint(("DIF_DESTROYPRIVATEDATA\n"));
  70. break;
  71. case DIF_PROPERTYCHANGE:
  72. break;
  73. case DIF_INSTALLDEVICE:
  74. if (Context->PostProcessing) {
  75. KdPrint(("DIF_INSTALLDEVICE, post\n"));
  76. status = HCCOIN_DoWin2kInstall(DeviceInfoSet, DeviceInfoData);
  77. } else {
  78. status = ERROR_DI_POSTPROCESSING_REQUIRED;
  79. }
  80. break;
  81. }
  82. return status;
  83. }
  84. /*
  85. HACTION STATES
  86. (0) companion can enumerate
  87. (1) companion should wait on 2.0 controller, 2.0 is enabled
  88. (2) companion is disabled, needs reenable 2.0 is disabled
  89. (3) companion is disabled, needs reenable 2.0 is enabled
  90. (4) companion is disabled, needs reenable 2.0 is removed
  91. */
  92. #define USB2_DISABLE 1
  93. #define USB2_ENABLE 2
  94. #define USB2_REMOVE 3
  95. #define USB2_INSTALL 4
  96. // Global state of install process
  97. ULONG MyContext = 0;
  98. DWORD
  99. HCCOIN_WinXp (
  100. DI_FUNCTION InstallFunction,
  101. HDEVINFO DeviceInfoSet,
  102. PSP_DEVINFO_DATA DeviceInfoData,
  103. PCOINSTALLER_CONTEXT_DATA Context
  104. )
  105. {
  106. DWORD status = NO_ERROR;
  107. ULONG pd;
  108. KdPrint(("HCCOIN_WinXp 0x%x\n", InstallFunction));
  109. KdPrint(("Context %08.8x, DeviceInfoData %08.8x private %08.8x\n",
  110. Context, DeviceInfoData, Context->PrivateData));
  111. //pd = (ULONG) Context->PrivateData;
  112. pd = MyContext;
  113. KdPrint(("pd %08.8x\n", pd));
  114. switch(InstallFunction) {
  115. case DIF_DESTROYPRIVATEDATA:
  116. KdPrint(("DIF_DESTROYPRIVATEDATA\n"));
  117. switch (pd) {
  118. case USB2_INSTALL:
  119. KdPrint((">(INSTALL)DISABLE 2>0\n"));
  120. // disabling 2.0 hc find current state 2,
  121. // cc need reenable and set to state 0 (ok to enum)
  122. // 2->0
  123. status = HCCOIN_CheckControllers(2, 0, TRUE);
  124. break;
  125. break;
  126. case USB2_DISABLE:
  127. KdPrint((">DISABLE 2>0\n"));
  128. // disabling 2.0 hc find current state 2,
  129. // cc need reenable and set to state 0 (ok to enum)
  130. // 2->0
  131. status = HCCOIN_CheckControllers(2, 0, FALSE);
  132. break;
  133. case USB2_ENABLE:
  134. KdPrint((">ENABLE 3>1\n"));
  135. // enabling 2.0 hc find state 3
  136. // cc need reenable and set to state 1 (wait to enum)
  137. // 3->1
  138. status = HCCOIN_CheckControllers(3, 1, FALSE);
  139. break;
  140. case USB2_REMOVE:
  141. // removing 2.0 hc find state 4
  142. // cc need reenumerate and set to state 0 (ok to enum)
  143. // 3->1
  144. KdPrint((">REMOVE 4>0\n"));
  145. status = HCCOIN_CheckControllers(4, 0, TRUE);
  146. break;
  147. }
  148. break;
  149. case DIF_PROPERTYCHANGE:
  150. {
  151. SP_PROPCHANGE_PARAMS propChange;
  152. // get the private data
  153. propChange.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  154. propChange.ClassInstallHeader.InstallFunction = InstallFunction;
  155. if (SetupDiGetClassInstallParams(DeviceInfoSet,
  156. DeviceInfoData,
  157. &propChange.ClassInstallHeader,
  158. sizeof(propChange),
  159. NULL)) {
  160. switch (propChange.StateChange) {
  161. case DICS_ENABLE:
  162. pd = USB2_ENABLE;
  163. break;
  164. case DICS_DISABLE:
  165. pd = USB2_DISABLE;
  166. break;
  167. default:
  168. pd = 0;
  169. }
  170. //Context->PrivateData = (PVOID) pd;
  171. MyContext = pd;
  172. KdPrint(("DIF_PROPERTYCHANGE %x\n", pd));
  173. if (pd == USB2_ENABLE) {
  174. KdPrint((">ENABLE\n"));
  175. if (Context->PostProcessing) {
  176. KdPrint(("DIF_PROPERTYCHANGE, post 0>3\n"));
  177. // enabling 2.0 hc. find state 0 and disable
  178. // set to state 3 need reenable
  179. // 0->3
  180. status = HCCOIN_CheckControllers(0, 3, FALSE);
  181. } else {
  182. status = ERROR_DI_POSTPROCESSING_REQUIRED;
  183. }
  184. }
  185. } else {
  186. TEST_TRAP();
  187. return GetLastError();
  188. }
  189. }
  190. break;
  191. case DIF_INSTALLDEVICE:
  192. // two options here, force a reboot or attempt to locate all
  193. // companion controllers and cycle them
  194. KdPrint(("DIF_INSTALLDEVICE\n"));
  195. // set all controllers to 'wait mode'
  196. MyContext = USB2_INSTALL;
  197. status = HCCOIN_CheckControllers(0, 1, FALSE);
  198. break;
  199. case DIF_REMOVE:
  200. if (Context->PostProcessing) {
  201. KdPrint(("DIF_REMOVE, post\n"));
  202. MyContext = USB2_REMOVE;
  203. status = HCCOIN_CheckControllers(2, 4, FALSE);
  204. } else {
  205. status = ERROR_DI_POSTPROCESSING_REQUIRED;
  206. }
  207. break;
  208. }
  209. return status;
  210. }
  211. DWORD
  212. HCCOIN_CopyFile(
  213. PSTR SrcPath,
  214. PSTR DestPath,
  215. PSTR FileName
  216. )
  217. {
  218. TCHAR src[MAX_PATH];
  219. TCHAR dest[MAX_PATH];
  220. ULONG fileNameLen, pathlen;
  221. KdPrint(("SrcPath <%s>\n", SrcPath));
  222. KdPrint(("DstPath <%s>\n", DestPath));
  223. KdPrint(("File <%s>\n", FileName));
  224. // validate that we do not go beyond
  225. // maxpath length
  226. pathlen = _tcslen(SrcPath);
  227. fileNameLen = _tcslen(FileName);
  228. if (pathlen+fileNameLen+sizeof(TCHAR)*2 > MAX_PATH) {
  229. TEST_TRAP();
  230. return ERROR_INVALID_PARAMETER;
  231. }
  232. wsprintf(src,"%s\\%s", SrcPath, FileName);
  233. pathlen = _tcslen(DestPath);
  234. fileNameLen = _tcslen(FileName);
  235. if (pathlen+fileNameLen+sizeof(TCHAR)*2 > MAX_PATH) {
  236. TEST_TRAP();
  237. return ERROR_INVALID_PARAMETER;
  238. }
  239. wsprintf(dest,"%s\\%s", DestPath, FileName);
  240. if (CopyFile(src, dest, FALSE)) {
  241. return NO_ERROR;
  242. } else {
  243. return GetLastError();
  244. }
  245. }
  246. // global string buffers
  247. TCHAR Usb2Path[MAX_PATH];
  248. TCHAR Usb2Inf[MAX_PATH];
  249. TCHAR SourcePath[MAX_PATH];
  250. TCHAR Usb2Section[MAX_PATH];
  251. DWORD
  252. HCCOIN_DoWin2kInstall(
  253. HDEVINFO DeviceInfoSet,
  254. PSP_DEVINFO_DATA DeviceInfoData
  255. )
  256. {
  257. DWORD status = NO_ERROR;
  258. SP_DRVINFO_DATA driverInfoData;
  259. SP_DRVINFO_DETAIL_DATA driverInfoDetailData;
  260. TCHAR tmp[MAX_PATH+1];
  261. TCHAR fileName[MAX_PATH];
  262. HINF infHandle;
  263. INFCONTEXT infContext;
  264. BOOL findFirst, found;
  265. UINT len;
  266. // Destination
  267. // get our strings, localize?
  268. len = GetWindowsDirectory(tmp, MAX_PATH+1);
  269. assert(sizeof(tmp) == sizeof(TCHAR) * (MAX_PATH+1));
  270. // make sure there is enough room to tack on our directory
  271. // minus 6 TCHARs
  272. if (len && len < MAX_PATH-6) {
  273. wsprintf((PSTR)Usb2Path, "%s\\USB2", tmp);
  274. wsprintf((PSTR)Usb2Inf, "USB2.INF");
  275. KdPrint(("Usb2Path <%s>\n", Usb2Path));
  276. } else {
  277. status = ERROR_INVALID_NAME;
  278. return status;
  279. }
  280. wsprintf((PSTR)Usb2Section, "USB2COINSTALLER");
  281. // create our USB2 directory
  282. if (!CreateDirectory((PSTR)Usb2Path, NULL)) {
  283. status = GetLastError();
  284. if (status != ERROR_ALREADY_EXISTS) {
  285. KdPrint(("CreateDirectory status %d\n", status));
  286. return status;
  287. }
  288. }
  289. // Source
  290. // get setup info from PnP
  291. driverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  292. if (!SetupDiGetSelectedDriver(DeviceInfoSet,
  293. DeviceInfoData,
  294. &driverInfoData)) {
  295. status = GetLastError();
  296. KdPrint(("SetupDiGetSelectedDriver status %d\n", status));
  297. return status;
  298. }
  299. driverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  300. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  301. DeviceInfoData,
  302. &driverInfoData,
  303. &driverInfoDetailData,
  304. sizeof(driverInfoDetailData),
  305. NULL)) {
  306. status = GetLastError();
  307. KdPrint(("SetupDiGetDriverInfoDetail status %d\n", status));
  308. if (status == ERROR_INSUFFICIENT_BUFFER) {
  309. // don't need extended info
  310. status = NO_ERROR;
  311. } else {
  312. return status;
  313. }
  314. }
  315. KdPrint(("driverInfoData %08.8x driverInfoDetailData %08.8x\n",
  316. &driverInfoData, &driverInfoDetailData));
  317. assert(sizeof(driverInfoDetailData.InfFileName) == sizeof(SourcePath));
  318. memcpy(SourcePath,
  319. driverInfoDetailData.InfFileName,
  320. sizeof(driverInfoDetailData.InfFileName));
  321. // strip the file name
  322. // note that this won't work with DBCS so either compile as
  323. // UNICODE or convert the source string to unicode and back
  324. // again
  325. {
  326. PTCHAR pStart, pEnd;
  327. pEnd = pStart = &SourcePath[0];
  328. #ifdef UNICODE
  329. pEnd = pStart + wstrlen(SourcePath);
  330. #else
  331. pEnd = pStart + strlen(SourcePath);
  332. #endif
  333. while (*pEnd != '\\' && pEnd != pStart) {
  334. pEnd--;
  335. }
  336. if (*pEnd == '\\') {
  337. *pEnd = UNICODE_NULL;
  338. }
  339. }
  340. KdPrint(("SourcePath <%s>\n", SourcePath));
  341. // copy files to our directory
  342. status = HCCOIN_CopyFile(SourcePath, Usb2Path, Usb2Inf);
  343. if (status != NO_ERROR) {
  344. return status;
  345. }
  346. // now open the source inf
  347. infHandle = SetupOpenInfFile(driverInfoDetailData.InfFileName,
  348. NULL,
  349. INF_STYLE_WIN4,
  350. NULL);
  351. if (INVALID_HANDLE_VALUE == infHandle) {
  352. status = ERROR_INVALID_NAME;
  353. return status;
  354. }
  355. findFirst = TRUE;
  356. // read the inf for files to copy
  357. do {
  358. if (findFirst) {
  359. found = SetupFindFirstLine(infHandle,
  360. Usb2Section,
  361. NULL,
  362. &infContext);
  363. findFirst = FALSE;
  364. } else {
  365. found = SetupFindNextLine(&infContext,
  366. &infContext);
  367. }
  368. if (found) {
  369. if (SetupGetLineText(&infContext,
  370. infHandle,
  371. Usb2Section, //Section
  372. NULL, //Key
  373. fileName, //ReturnBuffer
  374. sizeof(fileName), //ReturnBufferLength
  375. NULL)) {
  376. status = HCCOIN_CopyFile(SourcePath, Usb2Path, fileName);
  377. if (status != NO_ERROR) {
  378. SetupCloseInfFile(infHandle);
  379. return status;
  380. }
  381. }
  382. }
  383. } while (found);
  384. SetupCloseInfFile(infHandle);
  385. wsprintf((PSTR)tmp, "%s\\%s", Usb2Path, Usb2Inf);
  386. // tell setup about our inf
  387. if (!SetupCopyOEMInf(tmp, //SourceInfFileName
  388. Usb2Path, //OEMSourceMediaLocation
  389. SPOST_PATH, //OEMSourceMediaType
  390. 0, //CopyStyle
  391. NULL, //DestinationInfFileName
  392. 0, //DestinationInfFileNameSize
  393. NULL, //RequiredSize
  394. NULL)) { //DestinationInfFileNameComponent
  395. status = GetLastError();
  396. KdPrint(("SetupCopyOEMInf status %d\n", status));
  397. }
  398. return status;
  399. }
  400. DEVINST
  401. HCCOIN_FindUSBController(
  402. DWORD Haction,
  403. DWORD NextHaction
  404. )
  405. /*++
  406. do a depth first search of the device tree looking for any
  407. usb controllers that need attention
  408. --*/
  409. {
  410. DEVINST devInst;
  411. DEVINST devInstNext;
  412. CONFIGRET cr;
  413. BOOL walkDone = FALSE;
  414. ULONG len = 0;
  415. ULONG status = 0, problemNumber = 0;
  416. HKEY devKey;
  417. DWORD haction = 0;
  418. TCHAR buf[MAX_PATH];
  419. //
  420. // Get Root DevNode
  421. //
  422. cr = CM_Locate_DevNode(&devInst, NULL, 0);
  423. if (cr != CR_SUCCESS) {
  424. return 0;
  425. }
  426. //
  427. // Do a depth first search for the DevNode
  428. //
  429. while (!walkDone) {
  430. //
  431. // check for our key
  432. //
  433. if (cr == CR_SUCCESS) {
  434. //KdPrint(("devInst %08.8x - ", devInst));
  435. len = sizeof(buf);
  436. // CM_Api takes length in bytes
  437. if (CM_Get_DevNode_Registry_Property(devInst,
  438. CM_DRP_DRIVER,
  439. NULL,
  440. buf,
  441. &len,
  442. 0) == CR_SUCCESS) {
  443. //KdPrint(("<%s>\n",buf));
  444. } else {
  445. //KdPrint(("<no driver>\n"));
  446. }
  447. if (CM_Open_DevNode_Key(devInst,
  448. KEY_ALL_ACCESS,
  449. CM_REGISTRY_HARDWARE,
  450. RegDisposition_OpenExisting,
  451. &devKey,
  452. 0) == CR_SUCCESS) {
  453. len = sizeof(DWORD);
  454. if (RegQueryValueEx(devKey,
  455. "haction",
  456. NULL,
  457. NULL,
  458. (LPBYTE) &haction,
  459. &len) == ERROR_SUCCESS) {
  460. KdPrint(("Found Key %d\n", haction));
  461. if (haction == Haction) {
  462. LONG err;
  463. len = sizeof(DWORD);
  464. haction = NextHaction;
  465. // reset the key
  466. err = RegSetValueEx(devKey,
  467. "haction",
  468. 0,
  469. REG_DWORD,
  470. (LPBYTE) &haction,
  471. len);
  472. RegCloseKey(devKey);
  473. //KdPrint(("Reset Key %x\n", err));
  474. return devInst;
  475. }
  476. }
  477. RegCloseKey(devKey);
  478. }
  479. }
  480. //
  481. // This DevNode didn't match, go down a level to the first child.
  482. //
  483. cr = CM_Get_Child(&devInstNext,
  484. devInst,
  485. 0);
  486. if (cr == CR_SUCCESS) {
  487. devInst = devInstNext;
  488. continue;
  489. }
  490. //
  491. // Can't go down any further, go across to the next sibling. If
  492. // there are no more siblings, go back up until there is a sibling.
  493. // If we can't go up any further, we're back at the root and we're
  494. // done.
  495. //
  496. for (;;) {
  497. cr = CM_Get_Sibling(&devInstNext,
  498. devInst,
  499. 0);
  500. if (cr == CR_SUCCESS) {
  501. devInst = devInstNext;
  502. break;
  503. }
  504. cr = CM_Get_Parent(&devInstNext,
  505. devInst,
  506. 0);
  507. if (cr == CR_SUCCESS) {
  508. devInst = devInstNext;
  509. } else {
  510. walkDone = TRUE;
  511. break;
  512. }
  513. }
  514. }
  515. return 0;
  516. }
  517. DWORD
  518. HCCOIN_CheckControllers(
  519. DWORD Haction,
  520. DWORD NextHaction,
  521. BOOLEAN Setup
  522. )
  523. /*++
  524. --*/
  525. {
  526. DEVINST devInst;
  527. ULONG err;
  528. do {
  529. if (devInst = HCCOIN_FindUSBController(Haction, NextHaction)) {
  530. KdPrint((">Take Haction %08.8x\n", devInst));
  531. switch(Haction) {
  532. // 0->3
  533. // 0->1
  534. case 0:
  535. if (NextHaction != 1) {
  536. err = CM_Disable_DevNode(devInst, CM_DISABLE_UI_NOT_OK |
  537. CM_DISABLE_ABSOLUTE);
  538. KdPrint(("<Take Haction %d->%d - disable %x\n",
  539. Haction,
  540. NextHaction,
  541. err));
  542. }
  543. break;
  544. // 3->1
  545. // 2->0
  546. // 2->4
  547. case 3:
  548. case 2:
  549. if (NextHaction != 4) {
  550. if (Setup) {
  551. err = CM_Setup_DevNode(devInst, CM_SETUP_DEVNODE_READY);
  552. } else {
  553. err = CM_Enable_DevNode(devInst, 0);
  554. }
  555. }
  556. KdPrint(("<Take Haction %d->%d - enable %x\n",
  557. Haction,
  558. NextHaction,
  559. err));
  560. break;
  561. case 4:
  562. if (Setup) {
  563. err = CM_Setup_DevNode(devInst, CM_SETUP_DEVNODE_READY);
  564. } else {
  565. err = CM_Enable_DevNode(devInst, 0);
  566. }
  567. KdPrint(("<Take Haction %d->%d - enumerate %x\n",
  568. Haction,
  569. NextHaction,
  570. err));
  571. break;
  572. }
  573. }
  574. } while (devInst);
  575. return NO_ERROR;
  576. }
  577. DWORD
  578. HCCOIN_Entry (
  579. DI_FUNCTION InstallFunction,
  580. HDEVINFO DeviceInfoSet,
  581. PSP_DEVINFO_DATA DeviceInfoData,
  582. PCOINSTALLER_CONTEXT_DATA Context
  583. )
  584. {
  585. OSVERSIONINFO osVersion;
  586. // parameter validation
  587. if (DeviceInfoSet == NULL ||
  588. DeviceInfoData == NULL ||
  589. Context == NULL) {
  590. TEST_TRAP();
  591. return ERROR_INVALID_PARAMETER;
  592. }
  593. osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  594. GetVersionEx(&osVersion);
  595. if ( osVersion.dwMajorVersion == 5 && osVersion.dwMinorVersion == 0 ) {
  596. Win2k = TRUE;
  597. }
  598. if (Win2k) {
  599. KdPrint(("Microsoft Windows 2000 "));
  600. return HCCOIN_Win2k(InstallFunction,
  601. DeviceInfoSet,
  602. DeviceInfoData,
  603. Context);
  604. } else {
  605. KdPrint(("Microsoft Windows XP or later "));
  606. return HCCOIN_WinXp(InstallFunction,
  607. DeviceInfoSet,
  608. DeviceInfoData,
  609. Context);
  610. }
  611. }