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.

889 lines
23 KiB

  1. /*++
  2. Copyright (c) 1999, 2000 Microsoft Corporation
  3. Module Name:
  4. roothub.c
  5. Abstract:
  6. miniport root hub
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  11. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  12. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  13. PURPOSE.
  14. Copyright (c) 1999, 2000 Microsoft Corporation. All Rights Reserved.
  15. Revision History:
  16. 7-26-00 : created, jsenior
  17. implements the following miniport functions:
  18. MINIPORT_RH_GetStatus
  19. MINIPORT_RH_GetPortStatus
  20. MINIPORT_RH_GethubStatus
  21. MINIPORT_RH_SetFeaturePortReset
  22. MINIPORT_RH_SetFeaturePortSuspend
  23. MINIPORT_RH_SetFeaturePortPower
  24. MINIPORT_RH_ClearFeaturePortEnable
  25. MINIPORT_RH_ClearFeaturePortSuspend
  26. MINIPORT_RH_ClearFeaturePortPower
  27. MINIPORT_RH_ClearFeaturePortConnectChange
  28. MINIPORT_RH_ClearFeaturePortResetChange
  29. MINIPORT_RH_ClearFeaturePortEnableChange
  30. MINIPORT_RH_ClearFeaturePortSuspendChange
  31. MINIPORT_RH_ClearFeaturePortOvercurrentChange
  32. --*/
  33. #include "pch.h"
  34. typedef struct _UHCI_PORT_RESET_CONTEXT {
  35. USHORT PortNumber;
  36. BOOLEAN Completing;
  37. } UHCI_PORT_RESET_CONTEXT, *PUHCI_PORT_RESET_CONTEXT;
  38. VOID
  39. UhciRHGetRootHubData(
  40. IN PDEVICE_DATA DeviceData,
  41. OUT PROOTHUB_DATA HubData
  42. )
  43. /*++
  44. return info about the root hub
  45. --*/
  46. {
  47. HubData->NumberOfPorts = UHCI_NUMBER_PORTS;
  48. // D0,D1 (11) - no power switching
  49. // D2 (0) - not compund
  50. // D5, D15 (0)
  51. HubData->HubCharacteristics.us = 0;
  52. HubData->HubCharacteristics.PowerSwitchType = 3;
  53. HubData->HubCharacteristics.CompoundDevice = 0;
  54. if (DeviceData->ControllerFlavor == UHCI_Piix4) {
  55. // D3,D4 (01) - overcurrent reported per port
  56. HubData->HubCharacteristics.OverCurrentProtection = 1;
  57. } else {
  58. // D3,D4 (11) - no overcurrent reported
  59. HubData->HubCharacteristics.OverCurrentProtection = 11;
  60. }
  61. HubData->PowerOnToPowerGood = 1;
  62. // this value is the current consumed by the hub
  63. // brains, for the embeded hub this doesn't make
  64. // much sense.
  65. //
  66. // so we report zero
  67. HubData->HubControlCurrent = 0;
  68. LOGENTRY(DeviceData, G, '_hub', HubData->NumberOfPorts,
  69. DeviceData->PortPowerControl, 0);
  70. }
  71. ////////////////////////////////////////////////////////////////////////////////
  72. //
  73. // Hub status
  74. //
  75. ////////////////////////////////////////////////////////////////////////////////
  76. USB_MINIPORT_STATUS
  77. UhciRHGetStatus(
  78. IN PDEVICE_DATA DeviceData,
  79. OUT PUSHORT Status
  80. )
  81. /*++
  82. get the device status
  83. --*/
  84. {
  85. // the root hub is self powered
  86. *Status = USB_GETSTATUS_SELF_POWERED;
  87. return USBMP_STATUS_SUCCESS;
  88. }
  89. USB_MINIPORT_STATUS
  90. UhciRHGetHubStatus(
  91. IN PDEVICE_DATA DeviceData,
  92. OUT PRH_HUB_STATUS HubStatus
  93. )
  94. /*++
  95. --*/
  96. {
  97. // nothing intersting for the root
  98. // hub to report
  99. HubStatus->ul = 0;
  100. return USBMP_STATUS_SUCCESS;
  101. }
  102. ////////////////////////////////////////////////////////////////////////////////
  103. //
  104. // Port Enable
  105. //
  106. ////////////////////////////////////////////////////////////////////////////////
  107. USB_MINIPORT_STATUS
  108. UhciRHPortEnable(
  109. PDEVICE_DATA DeviceData,
  110. USHORT PortNumber,
  111. USHORT Value
  112. )
  113. /*++
  114. --*/
  115. {
  116. PHC_REGISTER reg;
  117. PORTSC port;
  118. reg = DeviceData->Registers;
  119. UHCI_ASSERT(DeviceData, PortNumber <= UHCI_NUMBER_PORTS);
  120. port.us = READ_PORT_USHORT(&reg->PortRegister[PortNumber-1].us);
  121. LOGENTRY(DeviceData, G, '_spe', port.us, 0, PortNumber);
  122. MASK_CHANGE_BITS(port);
  123. // writing a 1 enables the port
  124. port.PortEnable = Value;
  125. WRITE_PORT_USHORT(&reg->PortRegister[PortNumber-1].us, port.us);
  126. return USBMP_STATUS_SUCCESS;
  127. }
  128. USB_MINIPORT_STATUS
  129. UhciRHClearFeaturePortEnable (
  130. IN PDEVICE_DATA DeviceData,
  131. IN USHORT PortNumber
  132. )
  133. {
  134. return UhciRHPortEnable(DeviceData, PortNumber, 0);
  135. }
  136. USB_MINIPORT_STATUS
  137. UhciRHSetFeaturePortEnable(
  138. PDEVICE_DATA DeviceData,
  139. USHORT PortNumber
  140. )
  141. /*++
  142. --*/
  143. {
  144. return UhciRHPortEnable(DeviceData, PortNumber, 1);
  145. }
  146. ////////////////////////////////////////////////////////////////////////////////
  147. //
  148. // Port Power
  149. //
  150. ////////////////////////////////////////////////////////////////////////////////
  151. USB_MINIPORT_STATUS
  152. UhciRHClearFeaturePortPower (
  153. IN PDEVICE_DATA DeviceData,
  154. IN USHORT PortNumber
  155. )
  156. {
  157. // not implemented on uhci
  158. return USBMP_STATUS_SUCCESS;
  159. }
  160. USB_MINIPORT_STATUS
  161. UhciRHSetFeaturePortPower(
  162. PDEVICE_DATA DeviceData,
  163. USHORT PortNumber
  164. )
  165. /*++
  166. --*/
  167. {
  168. // not implemented on uhci
  169. return USBMP_STATUS_SUCCESS;
  170. }
  171. ////////////////////////////////////////////////////////////////////////////////
  172. //
  173. // Port Status
  174. //
  175. ////////////////////////////////////////////////////////////////////////////////
  176. USB_MINIPORT_STATUS
  177. UhciRHGetPortStatus(
  178. PDEVICE_DATA DeviceData,
  179. USHORT PortNumber,
  180. PRH_PORT_STATUS portStatus
  181. )
  182. /*++
  183. get the status of a partuclar port
  184. --*/
  185. {
  186. PHC_REGISTER reg;
  187. PORTSC port;
  188. reg = DeviceData->Registers;
  189. port.us = READ_PORT_USHORT(&reg->PortRegister[PortNumber-1].us);
  190. portStatus->ul = 0;
  191. LOGENTRY(DeviceData, G, '_Pp1', PortNumber, port.us, 0);
  192. // map the bits to the port status structure
  193. portStatus->Connected = port.PortConnect;
  194. portStatus->Enabled = port.PortEnable;
  195. // bits 12:2 indicate the true suspend state
  196. // we only want to indiacte the port is suspended
  197. // if a device is attached. If the device is removed
  198. // during suspend the enable bit will be clear
  199. if (port.Suspend && port.PortEnable) {
  200. portStatus->Suspended = 1;
  201. } else {
  202. portStatus->Suspended = 0;
  203. }
  204. if (DeviceData->ControllerFlavor == UHCI_Piix4) {
  205. portStatus->OverCurrent = port.Overcurrent;
  206. portStatus->OverCurrentChange = port.OvercurrentChange;
  207. portStatus->PowerOn = !port.Overcurrent;
  208. } else {
  209. portStatus->OverCurrent = 0;
  210. portStatus->OverCurrentChange = 0;
  211. portStatus->PowerOn = 1; // always on
  212. }
  213. portStatus->Reset = port.PortReset;
  214. portStatus->LowSpeed = port.LowSpeedDevice;
  215. portStatus->HighSpeed = 0; // this is not a 2.0 HC
  216. portStatus->ConnectChange = port.PortConnectChange;
  217. if (TEST_BIT(DeviceData->PortInReset, PortNumber-1)) {
  218. portStatus->EnableChange = 0;
  219. portStatus->ConnectChange = 0;
  220. } else {
  221. portStatus->EnableChange = port.PortEnableChange;
  222. }
  223. // these change bits must be emulated
  224. if (TEST_BIT(DeviceData->PortSuspendChange, PortNumber-1)) {
  225. portStatus->SuspendChange = 1;
  226. }
  227. if (TEST_BIT(DeviceData->PortResetChange, PortNumber-1)) {
  228. portStatus->ResetChange = 1;
  229. }
  230. LOGENTRY(DeviceData, G, '_gps',
  231. PortNumber, portStatus->ul, port.us);
  232. return USBMP_STATUS_SUCCESS;
  233. }
  234. ////////////////////////////////////////////////////////////////////////////////
  235. //
  236. // Port Reset
  237. //
  238. // First, we have the VIA specific routines for REVs 0 thru 4 of the VIA
  239. // USB host controller. Then the regular routines follow that are run for
  240. // all non-broken controllers.
  241. //
  242. ////////////////////////////////////////////////////////////////////////////////
  243. VOID
  244. UhciRHSetFeaturePortResetWorker(
  245. PDEVICE_DATA DeviceData,
  246. PUHCI_PORT_RESET_CONTEXT PortResetContext
  247. );
  248. VOID
  249. UhciViaRHPortResetComplete(
  250. PDEVICE_DATA DeviceData,
  251. PUHCI_PORT_RESET_CONTEXT PortResetContext
  252. )
  253. /*++
  254. VIA specific hack: Restart the controller.
  255. --*/
  256. {
  257. PHC_REGISTER reg;
  258. USBCMD command;
  259. USHORT portNumber;
  260. reg = DeviceData->Registers;
  261. portNumber = PortResetContext->PortNumber;
  262. // This code has been ripped out of the VIA filter driver
  263. // that works on Win2K.
  264. // Re-start the controller.
  265. command.us = READ_PORT_USHORT(&reg->UsbCommand.us);
  266. command.ForceGlobalResume = 0;
  267. command.RunStop = 1;
  268. WRITE_PORT_USHORT(&reg->UsbCommand.us, command.us);
  269. // Continue with the regular port reset completion stuff.
  270. SET_BIT(DeviceData->PortResetChange, portNumber-1);
  271. CLEAR_BIT(DeviceData->PortInReset, portNumber-1);
  272. // indicate the reset change to the hub
  273. USBPORT_INVALIDATE_ROOTHUB(DeviceData);
  274. }
  275. VOID
  276. UhciViaRHSetFeaturePortResetResume(
  277. PDEVICE_DATA DeviceData,
  278. PUHCI_PORT_RESET_CONTEXT PortResetContext
  279. )
  280. /*++
  281. VIA specific hack: Resume the controller.
  282. --*/
  283. {
  284. PHC_REGISTER reg;
  285. USBCMD command;
  286. PMINIPORT_CALLBACK callback;
  287. reg = DeviceData->Registers;
  288. // Resume the controller
  289. command.us = READ_PORT_USHORT(&reg->UsbCommand.us);
  290. command.ForceGlobalResume = 1;
  291. command.EnterGlobalSuspendMode = 0;
  292. WRITE_PORT_USHORT(&reg->UsbCommand.us, command.us);
  293. //
  294. // Depending on whether we're in the completion case or not,
  295. // we'll either be starting the controller or putting the port
  296. // into reset.
  297. //
  298. callback = PortResetContext->Completing ?
  299. UhciViaRHPortResetComplete : UhciRHSetFeaturePortResetWorker;
  300. USBPORT_REQUEST_ASYNC_CALLBACK(DeviceData,
  301. 20, // callback in 20 ms, as in via filter
  302. PortResetContext,
  303. sizeof(UHCI_PORT_RESET_CONTEXT),
  304. callback);
  305. }
  306. VOID
  307. UhciViaRHSetFeaturePortResetSuspend(
  308. PDEVICE_DATA DeviceData,
  309. PUHCI_PORT_RESET_CONTEXT PortResetContext
  310. )
  311. /*++
  312. VIA specific hack: Suspend the controller.
  313. --*/
  314. {
  315. PHC_REGISTER reg;
  316. USBCMD command;
  317. USBSTS status;
  318. reg = DeviceData->Registers;
  319. status.us = READ_PORT_USHORT(&reg->UsbStatus.us);
  320. UHCI_ASSERT(DeviceData, status.HCHalted);
  321. // Suspend the controller
  322. command.us = READ_PORT_USHORT(&reg->UsbCommand.us);
  323. command.ForceGlobalResume = 0;
  324. command.EnterGlobalSuspendMode = 1;
  325. WRITE_PORT_USHORT(&reg->UsbCommand.us, command.us);
  326. USBPORT_REQUEST_ASYNC_CALLBACK(DeviceData,
  327. 20, // callback in 20 ms, as in via filter
  328. PortResetContext,
  329. sizeof(UHCI_PORT_RESET_CONTEXT),
  330. UhciViaRHSetFeaturePortResetResume);
  331. }
  332. VOID
  333. UhciViaRHSetFeaturePortResetStop(
  334. PDEVICE_DATA DeviceData,
  335. PUHCI_PORT_RESET_CONTEXT PortResetContext
  336. )
  337. /*++
  338. VIA specific hack: Stop the controller.
  339. --*/
  340. {
  341. PHC_REGISTER reg;
  342. USBCMD command;
  343. reg = DeviceData->Registers;
  344. // This code has been ripped out of the VIA filter driver
  345. // that works on Win2K.
  346. // Stop the controller
  347. command.us = READ_PORT_USHORT(&reg->UsbCommand.us);
  348. command.RunStop = 0;
  349. WRITE_PORT_USHORT(&reg->UsbCommand.us, command.us);
  350. // Wait for the HC to halt
  351. USBPORT_REQUEST_ASYNC_CALLBACK(DeviceData,
  352. 20, // callback in 20 ms, as in via filter
  353. PortResetContext,
  354. sizeof(UHCI_PORT_RESET_CONTEXT),
  355. UhciViaRHSetFeaturePortResetSuspend);
  356. }
  357. ////////////////////////////////////////////////////////////////////////////////
  358. //
  359. // Port Reset
  360. //
  361. // Generic reset routines.
  362. //
  363. ////////////////////////////////////////////////////////////////////////////////
  364. VOID
  365. UhciRHPortResetComplete(
  366. PDEVICE_DATA DeviceData,
  367. PUHCI_PORT_RESET_CONTEXT PortResetContext
  368. )
  369. /*++
  370. complete a port reset
  371. --*/
  372. {
  373. PHC_REGISTER reg;
  374. PORTSC port;
  375. USHORT portNumber;
  376. int i;
  377. reg = DeviceData->Registers;
  378. portNumber = PortResetContext->PortNumber;
  379. port.us = READ_PORT_USHORT(&reg->PortRegister[portNumber-1].us);
  380. LOGENTRY(DeviceData, G, '_prC', port.us,
  381. DeviceData->PortResetChange, portNumber);
  382. MASK_CHANGE_BITS(port);
  383. // writing a 0 stops reset
  384. port.PortReset = 0;
  385. WRITE_PORT_USHORT(&reg->PortRegister[portNumber-1].us, port.us);
  386. // spin for zero
  387. do {
  388. //
  389. // a driver may not spin in a loop waiting for a status bit change
  390. // without testing for hardware presence inside the loop.
  391. //
  392. if (FALSE == UhciHardwarePresent(DeviceData)) {
  393. return;
  394. }
  395. port.us = READ_PORT_USHORT(&reg->PortRegister[portNumber-1].us);
  396. } while (port.PortReset != 0);
  397. //
  398. // Enable the port
  399. //
  400. for (i=0; i< 10; i++) {
  401. //
  402. // Need a delay between clearing the port reset and setting
  403. // the port enable. VIA suggests delaying 64 USB bit times,
  404. // or 43us if those are low-speed bit times....
  405. // BUT, we can't wait in the DPC...
  406. //
  407. KeStallExecutionProcessor(50);
  408. port.us = READ_PORT_USHORT(&reg->PortRegister[portNumber-1].us);
  409. if (port.PortEnable) {
  410. //
  411. // port is enabled
  412. //
  413. break;
  414. }
  415. port.PortEnable = 1;
  416. WRITE_PORT_USHORT(&reg->PortRegister[portNumber-1].us, port.us);
  417. }
  418. // clear port connect & enable change bits
  419. port.PortEnableChange = 1;
  420. port.PortConnectChange = 1;
  421. WRITE_PORT_USHORT(&reg->PortRegister[portNumber-1].us, port.us);
  422. if (DeviceData->ControllerFlavor >= UHCI_VIA &&
  423. DeviceData->ControllerFlavor <= UHCI_VIA+0x4) {
  424. PortResetContext->Completing = TRUE;
  425. UhciViaRHSetFeaturePortResetSuspend(DeviceData, PortResetContext);
  426. } else {
  427. SET_BIT(DeviceData->PortResetChange, portNumber-1);
  428. CLEAR_BIT(DeviceData->PortInReset, portNumber-1);
  429. // indicate the reset change to the hub
  430. USBPORT_INVALIDATE_ROOTHUB(DeviceData);
  431. }
  432. }
  433. VOID
  434. UhciRHSetFeaturePortResetWorker(
  435. PDEVICE_DATA DeviceData,
  436. PUHCI_PORT_RESET_CONTEXT PortResetContext
  437. )
  438. /*++
  439. Do the actual work to put the port in reset
  440. --*/
  441. {
  442. PHC_REGISTER reg;
  443. PORTSC port;
  444. USHORT portNumber = PortResetContext->PortNumber;
  445. reg = DeviceData->Registers;
  446. port.us = READ_PORT_USHORT(&reg->PortRegister[portNumber-1].us);
  447. LOGENTRY(DeviceData, G, '_prw', port.us, 0, portNumber);
  448. UHCI_ASSERT(DeviceData, !port.PortReset);
  449. // writing a 1 initiates reset
  450. LOGENTRY(DeviceData, G, '_nhs', port.us, 0, portNumber);
  451. MASK_CHANGE_BITS(port);
  452. port.PortReset = 1;
  453. WRITE_PORT_USHORT(&reg->PortRegister[portNumber-1].us, port.us);
  454. // schedule a callback to complete the reset.
  455. USBPORT_REQUEST_ASYNC_CALLBACK(DeviceData,
  456. 10, // callback in 10 ms,
  457. PortResetContext,
  458. sizeof(UHCI_PORT_RESET_CONTEXT),
  459. UhciRHPortResetComplete);
  460. }
  461. USB_MINIPORT_STATUS
  462. UhciRHSetFeaturePortReset(
  463. PDEVICE_DATA DeviceData,
  464. USHORT PortNumber
  465. )
  466. /*++
  467. Put a port in reset
  468. --*/
  469. {
  470. PORTSC port;
  471. UHCI_PORT_RESET_CONTEXT portResetContext;
  472. portResetContext.PortNumber = PortNumber;
  473. portResetContext.Completing = FALSE;
  474. UHCI_ASSERT(DeviceData, PortNumber <= UHCI_NUMBER_PORTS);
  475. LOGENTRY(DeviceData, G, '_spr', 0, 0, PortNumber);
  476. if (!TEST_BIT(DeviceData->PortInReset, PortNumber-1)) {
  477. SET_BIT(DeviceData->PortInReset, PortNumber-1);
  478. if (DeviceData->ControllerFlavor >= UHCI_VIA &&
  479. DeviceData->ControllerFlavor <= UHCI_VIA+0x4) {
  480. UhciViaRHSetFeaturePortResetStop(DeviceData, &portResetContext);
  481. } else {
  482. UhciRHSetFeaturePortResetWorker(DeviceData, &portResetContext);
  483. }
  484. } else {
  485. //
  486. // the port is already in reset
  487. //
  488. UhciKdPrint((DeviceData, 2, "Trying to reset a port already in reset.\n"));
  489. return USBMP_STATUS_BUSY;
  490. }
  491. return USBMP_STATUS_SUCCESS;
  492. }
  493. ////////////////////////////////////////////////////////////////////////////////
  494. //
  495. // Port Suspend
  496. //
  497. ////////////////////////////////////////////////////////////////////////////////
  498. USB_MINIPORT_STATUS
  499. UhciRHSetFeaturePortSuspend(
  500. PDEVICE_DATA DeviceData,
  501. USHORT PortNumber
  502. )
  503. /*++
  504. Put a port in suspend.
  505. --*/
  506. {
  507. PHC_REGISTER reg;
  508. PORTSC port;
  509. reg = DeviceData->Registers;
  510. UHCI_ASSERT(DeviceData, PortNumber <= UHCI_NUMBER_PORTS);
  511. port.us = READ_PORT_USHORT(&reg->PortRegister[PortNumber-1].us);
  512. LOGENTRY(DeviceData, G, '_sps', port.us, 0, PortNumber);
  513. if (!port.Suspend) {
  514. //
  515. // write the suspend bit
  516. //
  517. if (DeviceData->ControllerFlavor == UHCI_Piix4 ||
  518. ANY_VIA(DeviceData)) {
  519. // just pretend we did it for the piix4
  520. LOGENTRY(DeviceData, G, '_spo', port.us, 0, PortNumber);
  521. } else {
  522. MASK_CHANGE_BITS(port);
  523. port.Suspend = 1;
  524. WRITE_PORT_USHORT(&reg->PortRegister[PortNumber-1].us, port.us);
  525. }
  526. LOGENTRY(DeviceData, G, '_sus', port.us, 0, PortNumber);
  527. } else {
  528. //
  529. // stall if the port is already suspended
  530. //
  531. UhciKdPrint((DeviceData, 2, "Trying to suspend an already suspended port.\n"));
  532. }
  533. return USBMP_STATUS_SUCCESS;
  534. }
  535. VOID
  536. UhciRHClearFeaturePortSuspendComplete(
  537. PDEVICE_DATA DeviceData,
  538. PVOID Context
  539. )
  540. /*++
  541. complete a port resume.
  542. --*/
  543. {
  544. PHC_REGISTER reg;
  545. PORTSC port;
  546. PUHCI_PORT_RESET_CONTEXT portResetContext = Context;
  547. USHORT portNumber;
  548. reg = DeviceData->Registers;
  549. portNumber = portResetContext->PortNumber;
  550. port.us = READ_PORT_USHORT(&reg->PortRegister[portNumber-1].us);
  551. LOGENTRY(DeviceData, G, '_prC', port.us,
  552. DeviceData->PortSuspendChange, portNumber);
  553. MASK_CHANGE_BITS(port);
  554. // clear the bits.
  555. port.ResumeDetect = 0;
  556. port.Suspend = 0;
  557. WRITE_PORT_USHORT(&reg->PortRegister[portNumber-1].us, port.us);
  558. SET_BIT(DeviceData->PortSuspendChange, portNumber-1);
  559. DeviceData->PortResuming[portNumber-1] = FALSE;
  560. // indicate the resume change to the hub
  561. USBPORT_INVALIDATE_ROOTHUB(DeviceData);
  562. }
  563. USB_MINIPORT_STATUS
  564. UhciRHClearFeaturePortSuspend(
  565. PDEVICE_DATA DeviceData,
  566. USHORT PortNumber
  567. )
  568. /*++
  569. Resume a port in suspend
  570. --*/
  571. {
  572. PHC_REGISTER reg;
  573. PORTSC port;
  574. UHCI_PORT_RESET_CONTEXT portResetContext;
  575. reg = DeviceData->Registers;
  576. UHCI_ASSERT(DeviceData, PortNumber <= UHCI_NUMBER_PORTS);
  577. port.us = READ_PORT_USHORT(&reg->PortRegister[PortNumber-1].us);
  578. LOGENTRY(DeviceData, G, '_rps', port.us, 0, PortNumber);
  579. if (DeviceData->ControllerFlavor == UHCI_Piix4 ||
  580. ANY_VIA(DeviceData)) {
  581. // just pretend we did it for the piix4
  582. LOGENTRY(DeviceData, G, '_rpo', port.us, 0, PortNumber);
  583. } else {
  584. if (!DeviceData->PortResuming[PortNumber-1]) {
  585. DeviceData->PortResuming[PortNumber-1] = TRUE;
  586. if (!port.ResumeDetect) {
  587. // write the resume detect bit
  588. MASK_CHANGE_BITS(port);
  589. port.ResumeDetect = 1;
  590. WRITE_PORT_USHORT(&reg->PortRegister[PortNumber-1].us, port.us);
  591. }
  592. // Request to be called back so that we can set the resume to zero
  593. portResetContext.PortNumber = PortNumber;
  594. USBPORT_REQUEST_ASYNC_CALLBACK(DeviceData,
  595. 10, // callback in 10 ms,
  596. &portResetContext,
  597. sizeof(portResetContext),
  598. UhciRHClearFeaturePortSuspendComplete);
  599. } else {
  600. // stall if the port is already resuming
  601. UhciKdPrint((DeviceData, 2, "Trying to resume a port already resuming.\n"));
  602. return USBMP_STATUS_BUSY;
  603. }
  604. }
  605. LOGENTRY(DeviceData, G, '_res', port.us, 0, PortNumber);
  606. return USBMP_STATUS_SUCCESS;
  607. }
  608. ////////////////////////////////////////////////////////////////////////////////
  609. //
  610. // Port Change bits
  611. //
  612. ////////////////////////////////////////////////////////////////////////////////
  613. USB_MINIPORT_STATUS
  614. UhciRHClearFeaturePortConnectChange(
  615. PDEVICE_DATA DeviceData,
  616. USHORT PortNumber
  617. )
  618. /*++
  619. --*/
  620. {
  621. PHC_REGISTER reg;
  622. PORTSC port;
  623. reg = DeviceData->Registers;
  624. //
  625. port.us = READ_PORT_USHORT(&reg->PortRegister[PortNumber-1].us);
  626. LOGENTRY(DeviceData, G, '_pcc', port.us,
  627. 0, PortNumber);
  628. // writing a 1 zeros the change bit
  629. if (port.PortConnectChange == 1) {
  630. // mask off other change bits
  631. MASK_CHANGE_BITS(port);
  632. port.PortConnectChange = 1;
  633. WRITE_PORT_USHORT(&reg->PortRegister[PortNumber-1].us, port.us);
  634. }
  635. return USBMP_STATUS_SUCCESS;
  636. }
  637. USB_MINIPORT_STATUS
  638. UhciRHClearFeaturePortEnableChange(
  639. PDEVICE_DATA DeviceData,
  640. USHORT PortNumber
  641. )
  642. /*++
  643. --*/
  644. {
  645. PHC_REGISTER reg;
  646. PORTSC port;
  647. LOGENTRY(DeviceData, G, '_cpe', PortNumber, 0, 0);
  648. reg = DeviceData->Registers;
  649. port.us = READ_PORT_USHORT(&reg->PortRegister[PortNumber-1].us);
  650. MASK_CHANGE_BITS(port);
  651. port.PortEnableChange = 1;
  652. WRITE_PORT_USHORT(&reg->PortRegister[PortNumber-1].us, port.us);
  653. return USBMP_STATUS_SUCCESS;
  654. }
  655. USB_MINIPORT_STATUS
  656. UhciRHClearFeaturePortResetChange(
  657. PDEVICE_DATA DeviceData,
  658. USHORT PortNumber
  659. )
  660. /*++
  661. Clear the port reset condition.
  662. --*/
  663. {
  664. // UHCI doesn't have this.
  665. CLEAR_BIT(DeviceData->PortResetChange, PortNumber-1);
  666. return USBMP_STATUS_SUCCESS;
  667. }
  668. USB_MINIPORT_STATUS
  669. UhciRHClearFeaturePortSuspendChange(
  670. PDEVICE_DATA DeviceData,
  671. USHORT PortNumber
  672. )
  673. /*++
  674. Clear the port suspend condition.
  675. --*/
  676. {
  677. // UHCI doesn't have this.
  678. CLEAR_BIT(DeviceData->PortSuspendChange, PortNumber-1);
  679. return USBMP_STATUS_SUCCESS;
  680. }
  681. USB_MINIPORT_STATUS
  682. UhciRHClearFeaturePortOvercurrentChange(
  683. PDEVICE_DATA DeviceData,
  684. USHORT PortNumber
  685. )
  686. /*++
  687. Clear the port overcurrent condition.
  688. --*/
  689. {
  690. if (DeviceData->ControllerFlavor == UHCI_Piix4) {
  691. PHC_REGISTER reg;
  692. PORTSC port;
  693. reg = DeviceData->Registers;
  694. //
  695. port.us = READ_PORT_USHORT(&reg->PortRegister[PortNumber-1].us);
  696. LOGENTRY(DeviceData, G, '_cOv', port.us, 0, PortNumber);
  697. // writing a 1 zeros the change bit
  698. if (port.OvercurrentChange == 1) {
  699. // mask off other change bits
  700. MASK_CHANGE_BITS(port);
  701. port.OvercurrentChange = 1;
  702. WRITE_PORT_USHORT(&reg->PortRegister[PortNumber-1].us, port.us);
  703. }
  704. }
  705. return USBMP_STATUS_SUCCESS;
  706. }