Source code of Windows XP (NT5)
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.

707 lines
19 KiB

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