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.

1168 lines
31 KiB

  1. /*++
  2. Copyright (c) 1995,1996 Microsoft Corporation
  3. :ts=4
  4. Module Name:
  5. roothub.c
  6. Abstract:
  7. The UHC driver for USB, this module contains the root hub
  8. code.
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. 8-13-96 : created
  14. --*/
  15. #include "wdm.h"
  16. #include "stdarg.h"
  17. #include "stdio.h"
  18. #include "usbdi.h"
  19. #include "hcdi.h"
  20. #include "uhcd.h"
  21. #include "dbg.h"
  22. #define RH_STANDARD_REQ 0
  23. #define RH_CLASS_REQ 1
  24. #define MIN(x, y) (((x)<(y)) ? (x) : (y))
  25. #define RH_CHECK_BUFFER(x, y, z)
  26. #define RH_PORT_RESET 0x0200 // Port Reset 1=in reset
  27. #define RH_PORT_ENABLE 0x0004 // Port Enable/Disable 1=enabled
  28. #define RH_PORT_CONNECT 0x0001 // Current Connect Status 1=connect
  29. #define RH_PORT_LS 0x0100 // Low Speed 1=ls device attached
  30. #define RH_PORT_SUSPEND 0x1000 // Suspend 1=in suspend
  31. #define RH_PORT_RESUME 0x0040 // resume port
  32. #define RH_C_PORT_ENABLE 0x0008 // Port Enabled/Disabled Change
  33. #define RH_C_PORT_CONNECT 0x0002 // Port Connect Status Change
  34. //
  35. // HUB feature selectors
  36. //
  37. #define C_HUB_LOCAL_POWER 0
  38. #define C_HUB_OVER_CURRENT 1
  39. #define PORT_CONNECTION 0
  40. #define PORT_ENABLE 1
  41. #define PORT_SUSPEND 2
  42. #define PORT_OVER_CURRENT 3
  43. #define PORT_RESET 4
  44. #define PORT_POWER 8
  45. #define PORT_LOW_SPEED 9
  46. #define C_PORT_CONNECTION 16
  47. #define C_PORT_ENABLE 17
  48. #define C_PORT_SUSPEND 18
  49. #define C_PORT_OVER_CURRENT 19
  50. #define C_PORT_RESET 20
  51. #define HUB_REQUEST_GET_STATUS 0
  52. #define HUB_REQUEST_CLEAR_FEATURE 1
  53. #define HUB_REQUEST_GET_STATE 2
  54. #define HUB_REQUEST_SET_FEATURE 3
  55. #define HUB_REQUEST_GET_DESCRIPTOR 6
  56. #define HUB_REQUEST_SET_DESCRIPTOR 7
  57. UCHAR RH_DeviceDescriptor[] = {0x12, //bLength
  58. 0x01, //bDescrpitorType
  59. 0x00, 0x01, //bcdUSB
  60. 0x09, //bDeviceClass
  61. 0x01, //bDeviceSubClass
  62. 0x00, //bDeviceProtocol
  63. 0x08, //bMaxPacketSize0
  64. 0x86, 0x80, //idVendor
  65. 0x0B, 0x0B, //idProduct
  66. 0x00, 0x00, //bcdDevice
  67. 0x00, //iManufacturer
  68. 0x00, //iProduct
  69. 0x00, //iSerialNumber
  70. 0x01};//bNumConfigurations
  71. UCHAR RH_ConfigurationDescriptor[] =
  72. /* Config Descriptor */
  73. {0x09, //bLength
  74. 0x02, //bDescriptorType
  75. 0x19, 0x00, //wTotalLength
  76. 0x01, //bNumInterfaces
  77. 0x23, //iConfigurationValue
  78. 0x00, //iConfiguration
  79. 0x40, //bmAttributes
  80. 0x00, //MaxPower
  81. /* Interface Descriptor */
  82. 0x09, //bLength
  83. 0x04, //bDescriptorType
  84. 0x00, //bInterfaceNumber
  85. 0x00, //bAlternateSetting
  86. 0x01, //bNumEndpoints
  87. 0x09, //bInterfaceClass
  88. 0x01, //bInterfaceSubClass
  89. 0x00, //bInterfaceProtocol
  90. 0x00, //iInterface
  91. /* Endpoint Descriptor */
  92. 0x07, //bLength
  93. 0x05, //bDescriptorType
  94. 0x81, //bEndpointAddress
  95. 0x03, //bmAttributes
  96. 0x08, 0x00, //wMaxPacketSize
  97. 0x0a};//bInterval
  98. UCHAR RH_HubDescriptor[] =
  99. {0x09, //bLength
  100. 0x00, //bDescriptorType
  101. 0x02, //bNbrPorts
  102. 0x1B, 0x00, //wHubCharacteristics
  103. // D0,D1 (11) - no power switching
  104. // D2 (0) - not compund
  105. // D3,D4 (11) - no overcurrent
  106. // D5, D15 (0)
  107. 0x01, // bPwrOn2PwrGood
  108. 0x00, // bHubContrCurrent
  109. 0x00, // DeviceRemovable
  110. 0x00}; // PortPwrCtrlMask
  111. VOID
  112. RootHub_ResetTimerHandler(
  113. IN PVOID TimerContext
  114. )
  115. /*++
  116. Routine Description:
  117. Called as a result of scheduling a timer event for a root hub port
  118. This function is called 10ms after the reset bit for the port is set,
  119. the reset bit is cleared and the enable bit is set.
  120. Arguments:
  121. TimerContext - supplies hub port structure
  122. Return Value:
  123. None.
  124. --*/
  125. {
  126. PROOTHUB_PORT hubPort = (PROOTHUB_PORT) TimerContext;
  127. USHORT reg;
  128. int i;
  129. //
  130. // BUGBUG this code assumes it is being called as a result
  131. // of a reset_port command being sent to the hub.
  132. //
  133. LOGENTRY(LOG_MISC, 'rRTH', TimerContext, 0, 0);
  134. //
  135. // clear the RESET bit
  136. //
  137. reg = UHCD_RootHub_ReadPort(hubPort);
  138. reg &= (~RH_PORT_RESET);
  139. UHCD_RootHub_WritePort(hubPort, reg);
  140. //
  141. // Reset is complete, enable the port
  142. //
  143. // BUGBUG not sure why we need this loop
  144. // original code from intel has this
  145. //
  146. for (i=1; i<10; i++) {
  147. // Need a delay between clearing the port reset and setting
  148. // the port enable. VIA suggests delaying 64 USB bit times,
  149. // or 43us if those are low-speed bit times.
  150. //
  151. KeStallExecutionProcessor(50);
  152. reg = UHCD_RootHub_ReadPort(hubPort);
  153. if (reg & RH_PORT_ENABLE) {
  154. // port is enabled
  155. break;
  156. }
  157. // enable the port
  158. reg |= RH_PORT_ENABLE;
  159. UHCD_RootHub_WritePort(hubPort, reg);
  160. }
  161. //
  162. // clear port connect & enable change bits
  163. //
  164. reg |= (RH_C_PORT_CONNECT | RH_C_PORT_ENABLE);
  165. UHCD_RootHub_WritePort(hubPort, reg);
  166. //
  167. // Note that we have a change condition
  168. //
  169. hubPort->ResetChange = TRUE;
  170. return;
  171. }
  172. VOID
  173. RootHub_SuspendTimerHandler(
  174. IN PVOID TimerContext
  175. )
  176. /*++
  177. Routine Description:
  178. Arguments:
  179. TimerContext - supplies hub port structure
  180. Return Value:
  181. None.
  182. --*/
  183. {
  184. PROOTHUB_PORT hubPort = (PROOTHUB_PORT) TimerContext;
  185. USHORT reg;
  186. //
  187. // BUGBUG this code assumes it is being called as a result
  188. // of a resume_port command being sent to the hub.
  189. //
  190. LOGENTRY(LOG_MISC, 'rSTH', TimerContext, 0, 0);
  191. //
  192. // clear the SUSPEND bit
  193. //
  194. reg = UHCD_RootHub_ReadPort(hubPort);
  195. reg &= (~RH_PORT_RESUME);
  196. reg &= (~RH_PORT_SUSPEND);
  197. UHCD_RootHub_WritePort(hubPort, reg);
  198. //
  199. // Note that we have a change condition
  200. //
  201. hubPort->SuspendChange = TRUE;
  202. return;
  203. }
  204. PROOTHUB
  205. RootHub_Initialize(
  206. IN PDEVICE_OBJECT DeviceObject,
  207. IN ULONG NumberOfPorts,
  208. IN BOOLEAN DoSelectiveSuspend
  209. )
  210. /*++
  211. Routine Description:
  212. Initialize the root hub:
  213. Arguments:
  214. DeviceObject - HCD device object
  215. Return Value:
  216. ptr to root hub structure.
  217. --*/
  218. {
  219. //
  220. // Perform any Root Hub hardware specific initialization here.
  221. //
  222. UCHAR i;
  223. USHORT base = RH_PORT_SC_BASE;
  224. PROOTHUB rootHub;
  225. #if DBG
  226. PULONG pDisabledPorts;
  227. #endif
  228. rootHub = GETHEAP(NonPagedPool, sizeof(ROOTHUB)+
  229. sizeof(ROOTHUB_PORT)*NumberOfPorts);
  230. #if DBG
  231. pDisabledPorts = GETHEAP(NonPagedPool, sizeof(ULONG) * NumberOfPorts);
  232. #endif
  233. if (rootHub) {
  234. LOGENTRY(LOG_MISC, 'rINI', DeviceObject, rootHub,
  235. DoSelectiveSuspend);
  236. rootHub->Sig = SIG_RH;
  237. // rootHub->DeviceAddress = 0x00;
  238. rootHub->DeviceObject = DeviceObject;
  239. rootHub->NumberOfPorts = (UCHAR) NumberOfPorts;
  240. rootHub->ConfigurationValue = 0;
  241. rootHub->DoSelectiveSuspend =
  242. DoSelectiveSuspend;
  243. for (i=0; i<rootHub->NumberOfPorts; i++) {
  244. rootHub->Port[i].ResetChange = FALSE;
  245. rootHub->Port[i].SuspendChange = FALSE;
  246. rootHub->Port[i].DeviceObject = DeviceObject;
  247. rootHub->Port[i].Address = base;
  248. base+=2;
  249. }
  250. #if DBG
  251. rootHub->DisabledPort = pDisabledPorts;
  252. if (pDisabledPorts != NULL) {
  253. RtlZeroMemory(pDisabledPorts, sizeof(ULONG) * NumberOfPorts);
  254. }
  255. #else
  256. rootHub->DisabledPort = NULL;
  257. #endif
  258. }
  259. return rootHub;
  260. }
  261. RHSTATUS
  262. RootHub_Endpoint0(
  263. IN PROOTHUB RootHub,
  264. IN PRH_SETUP SetupPacket,
  265. IN PUCHAR DeviceAddress,
  266. IN PUCHAR Buffer,
  267. IN OUT PULONG BufferLength
  268. )
  269. /*++
  270. Routine Description:
  271. This routine should be called anytime there is any control transfer to
  272. the RootHub endpoint 0. This procedure behaves like a real device would
  273. in that it parses the command data, performs the requested operation,
  274. using or modifying the data area as appropriate.
  275. The return code is equivalent to the 'status stage' of a normal control
  276. transfer.
  277. Arguments:
  278. Return Value:
  279. root hub transfer status code
  280. --*/
  281. {
  282. RHSTATUS rhStatus;
  283. ASSERT_RH(RootHub);
  284. LOGENTRY(LOG_MISC, 'rEP0', RootHub, SetupPacket, DeviceAddress);
  285. if (SetupPacket->bmRequestType.Type == RH_STANDARD_REQ) {
  286. rhStatus =
  287. RootHub_StandardCommand(RootHub,
  288. SetupPacket,
  289. DeviceAddress,
  290. Buffer,
  291. BufferLength);
  292. } else if (SetupPacket->bmRequestType.Type == RH_CLASS_REQ) {
  293. rhStatus =
  294. RootHub_ClassCommand(RootHub,
  295. SetupPacket,
  296. Buffer,
  297. BufferLength);
  298. } else {
  299. rhStatus = RH_STALL;
  300. // probably a bug in the hub driver
  301. TRAP();
  302. }
  303. return rhStatus;
  304. }
  305. #define RH_DEV_TO_HOST 1
  306. #define RH_HOST_TO_DEV 0
  307. RHSTATUS
  308. RootHub_StandardCommand(
  309. IN PROOTHUB RootHub,
  310. IN PRH_SETUP SetupPacket,
  311. IN OUT PUCHAR DeviceAddress,
  312. IN OUT PUCHAR Buffer,
  313. IN OUT PULONG BufferLength
  314. )
  315. /*++
  316. Routine Description:
  317. Arguments:
  318. DeviceAddress - pointer to HCD address assigned to the
  319. root hub
  320. SetupPacket - pointer to a SetupPacket packet
  321. Return Value:
  322. Root Hub status code.
  323. --*/
  324. {
  325. PVOID descriptor = NULL;
  326. ULONG length;
  327. RHSTATUS rhStatus = RH_STALL;
  328. ASSERT_RH(RootHub);
  329. LOGENTRY(LOG_MISC, 'rSCM', RootHub, SetupPacket, DeviceAddress);
  330. //
  331. // switch on the command
  332. //
  333. switch (SetupPacket->bRequest) {
  334. case USB_REQUEST_SET_ADDRESS:
  335. //
  336. //
  337. //
  338. if (SetupPacket->wIndex == 0 &&
  339. SetupPacket->wLength == 0 &&
  340. SetupPacket->bmRequestType.Dir == RH_HOST_TO_DEV) {
  341. *DeviceAddress =
  342. (UCHAR)SetupPacket->wValue.W;
  343. rhStatus = RH_SUCCESS;
  344. LOGENTRY(LOG_MISC, 'rSAD', *DeviceAddress, 0, 0);
  345. }
  346. break;
  347. case USB_REQUEST_GET_DESCRIPTOR:
  348. {
  349. PVOID descriptor = NULL;
  350. ULONG siz;
  351. UCHAR descriptorIndex, descriptorType;
  352. descriptorType = (UCHAR) SetupPacket->wValue.hiPart;
  353. descriptorIndex = (UCHAR) SetupPacket->wValue.lowPart;
  354. switch (descriptorType) {
  355. case USB_DEVICE_DESCRIPTOR_TYPE:
  356. if (descriptorIndex == 0 &&
  357. SetupPacket->bmRequestType.Dir == RH_DEV_TO_HOST) {
  358. siz = sizeof(RH_DeviceDescriptor);
  359. descriptor = RH_DeviceDescriptor;
  360. LOGENTRY(LOG_MISC, 'rGDS', descriptor, siz, 0);
  361. }
  362. break;
  363. case USB_CONFIGURATION_DESCRIPTOR_TYPE:
  364. if (descriptorIndex == 0 &&
  365. SetupPacket->bmRequestType.Dir == RH_DEV_TO_HOST) {
  366. siz = sizeof(RH_ConfigurationDescriptor);
  367. descriptor = RH_ConfigurationDescriptor;
  368. LOGENTRY(LOG_MISC, 'rGCS', descriptor, siz, 0);
  369. }
  370. break;
  371. //
  372. // BUGBUG these descriptor types not handled
  373. //
  374. case USB_STRING_DESCRIPTOR_TYPE:
  375. default:
  376. TRAP();
  377. } /* descriptorType */
  378. if (descriptor) {
  379. RH_CHECK_BUFFER(SetupPacket->wLength,
  380. *BufferLength,
  381. siz);
  382. length = MIN(*BufferLength, siz);
  383. RtlCopyMemory(Buffer, descriptor, length);
  384. *BufferLength = length;
  385. rhStatus = RH_SUCCESS;
  386. }
  387. }
  388. break;
  389. case USB_REQUEST_GET_STATUS:
  390. //
  391. // get_device_status
  392. //
  393. // report that we are self powered
  394. //
  395. // BUGBUG
  396. // are we self powered?
  397. // are we a remote wakeup source
  398. //
  399. // see section 9.4.5 USB 1.0 spec
  400. //
  401. {
  402. PUSHORT status = (PUSHORT) Buffer;
  403. if (SetupPacket->wValue.W == 0 && //mbz
  404. SetupPacket->wLength == 2 &&
  405. SetupPacket->wIndex == 0 && //device
  406. SetupPacket->bmRequestType.Dir == RH_DEV_TO_HOST) {
  407. *status = USB_GETSTATUS_SELF_POWERED;
  408. *BufferLength = sizeof(*status);
  409. rhStatus = RH_SUCCESS;
  410. }
  411. }
  412. break;
  413. case USB_REQUEST_GET_CONFIGURATION:
  414. //
  415. // get_device_configuration
  416. //
  417. if (SetupPacket->wValue.W == 0 && //mbz
  418. SetupPacket->wIndex == 0 && //mbz
  419. SetupPacket->wLength == 1 &&
  420. SetupPacket->bmRequestType.Dir == RH_DEV_TO_HOST) {
  421. TEST_TRAP();
  422. RH_CHECK_BUFFER(SetupPacket->wLength,
  423. *BufferLength,
  424. sizeof(RootHub->Configuration));
  425. length = MIN(*BufferLength, sizeof(RootHub->ConfigurationValue));
  426. RtlCopyMemory(Buffer, &RootHub->ConfigurationValue, length);
  427. *BufferLength = length;
  428. rhStatus = RH_SUCCESS;
  429. }
  430. break;
  431. case USB_REQUEST_CLEAR_FEATURE:
  432. // bugbug, required
  433. TRAP();
  434. break;
  435. case USB_REQUEST_SET_CONFIGURATION:
  436. {
  437. PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor =
  438. (PUSB_CONFIGURATION_DESCRIPTOR) RH_ConfigurationDescriptor;
  439. if (SetupPacket->wIndex == 0 && // mbz
  440. SetupPacket->wLength == 0 && // mbz
  441. SetupPacket->bmRequestType.Dir == RH_HOST_TO_DEV &&
  442. (SetupPacket->wValue.W ==
  443. configurationDescriptor->bConfigurationValue ||
  444. SetupPacket->wValue.W == 0)) {
  445. RootHub->ConfigurationValue = (UCHAR) SetupPacket->wValue.W;
  446. rhStatus = RH_SUCCESS;
  447. LOGENTRY(LOG_MISC, 'rSEC', RootHub->ConfigurationValue, 0, 0);
  448. }
  449. }
  450. break;
  451. case USB_REQUEST_SET_FEATURE:
  452. // bugbug, required
  453. TRAP();
  454. break;
  455. //
  456. // these commands are optional for the hub
  457. //
  458. case USB_REQUEST_SET_DESCRIPTOR:
  459. case USB_REQUEST_SET_INTERFACE:
  460. case USB_REQUEST_GET_INTERFACE:
  461. case USB_REQUEST_SYNC_FRAME:
  462. default:
  463. // bad command, probably a bug in the
  464. // hub driver
  465. TRAP();
  466. break;
  467. }
  468. return rhStatus;
  469. }
  470. RHSTATUS
  471. RootHub_ClassCommand(
  472. IN PROOTHUB RootHub,
  473. IN PRH_SETUP SetupPacket,
  474. IN OUT PUCHAR Buffer,
  475. IN OUT PULONG BufferLength
  476. )
  477. /*++
  478. Routine Description:
  479. Arguments:
  480. Return Value:
  481. Root Hub status code.
  482. --*/
  483. {
  484. PVOID descriptor = NULL;
  485. ULONG length;
  486. RHSTATUS rhStatus = RH_STALL;
  487. ASSERT_RH(RootHub);
  488. LOGENTRY(LOG_MISC, 'rCCM', RootHub, SetupPacket, 0);
  489. //
  490. // switch on the command
  491. //
  492. switch (SetupPacket->bRequest) {
  493. case HUB_REQUEST_GET_STATUS:
  494. //
  495. //
  496. //
  497. if (SetupPacket->bmRequestType.Recipient == RECIPIENT_PORT) {
  498. //
  499. // get port status
  500. //
  501. PRH_PORT_STATUS portStatus;
  502. //
  503. // see if we have a valid request
  504. //
  505. if (SetupPacket->wIndex > 0 &&
  506. SetupPacket->wIndex <= RH_NUMBER_OF_PORTS &&
  507. SetupPacket->wLength >= sizeof(*portStatus)) {
  508. USHORT reg;
  509. PROOTHUB_PORT hubPort =
  510. &RootHub->Port[SetupPacket->wIndex-1];
  511. ASSERT(sizeof(*portStatus) == 4);
  512. ASSERT(*BufferLength >= sizeof(*portStatus));
  513. portStatus = (PRH_PORT_STATUS) Buffer;
  514. RtlZeroMemory(Buffer, sizeof(*portStatus));
  515. reg = UHCD_RootHub_ReadPort (hubPort);
  516. //
  517. // get port status bits
  518. //
  519. portStatus->Connected = (reg & RH_PORT_CONNECT)
  520. #if DBG
  521. && !(RootHub->DisabledPort[SetupPacket->wIndex - 1]
  522. & UHCD_FAKE_DISCONNECT)
  523. #endif
  524. ? 1:0;
  525. portStatus->Enabled = (reg & RH_PORT_ENABLE) ? 1:0;
  526. portStatus->Suspended = (reg & RH_PORT_SUSPEND) ? 1:0;
  527. portStatus->OverCurrent = 0; // never report overcurrent
  528. portStatus->Reset = (reg & RH_PORT_RESET) ? 1:0;
  529. portStatus->PowerOn = 1; // always on
  530. portStatus->LowSpeed = (reg & RH_PORT_LS) ? 1:0;
  531. //
  532. // get port change bits
  533. //
  534. portStatus->ConnectChange = (reg & RH_C_PORT_CONNECT)
  535. #if DBG
  536. || (RootHub->DisabledPort[SetupPacket->wIndex - 1]
  537. & UHCD_FAKE_CONNECT_CHANGE)
  538. #endif
  539. ? 1:0;
  540. portStatus->EnableChange = (reg & RH_C_PORT_ENABLE) ? 1:0;
  541. portStatus->SuspendChange = hubPort->SuspendChange ? 1:0;;
  542. portStatus->OverCurrentChange = 0;
  543. portStatus->ResetChange = hubPort->ResetChange ? 1:0;
  544. LOGENTRY(LOG_MISC, 'rPST',
  545. portStatus, *((PULONG) (portStatus)), reg);
  546. rhStatus = RH_SUCCESS;
  547. }
  548. } else {
  549. //
  550. // get hub status
  551. //
  552. TRAP();
  553. }
  554. break;
  555. case HUB_REQUEST_CLEAR_FEATURE:
  556. //
  557. // Hub/Port Clear Feature
  558. //
  559. LOGENTRY(LOG_MISC, 'rCFR',
  560. SetupPacket->bmRequestType.Recipient, 0, 0);
  561. if (SetupPacket->bmRequestType.Recipient == RECIPIENT_PORT) {
  562. //
  563. // clear port feature
  564. //
  565. LOGENTRY(LOG_MISC, 'rCPR', SetupPacket->wValue.W, 0, 0);
  566. switch(SetupPacket->wValue.W) {
  567. //
  568. //
  569. //
  570. case PORT_ENABLE:
  571. // BUGBUG
  572. // disable the port
  573. if (SetupPacket->wIndex > 0 &&
  574. SetupPacket->wIndex <= RH_NUMBER_OF_PORTS) {
  575. USHORT reg;
  576. PROOTHUB_PORT hubPort =
  577. &RootHub->Port[SetupPacket->wIndex-1];
  578. reg = UHCD_RootHub_ReadPort (hubPort);
  579. // clear the enable bit
  580. reg &= ~(RH_PORT_ENABLE);
  581. LOGENTRY(LOG_MISC, 'rDsP', SetupPacket->wIndex, 0, 0);
  582. UHCD_RootHub_WritePort(hubPort, reg);
  583. rhStatus = RH_SUCCESS;
  584. }
  585. break;
  586. case PORT_POWER:
  587. // BUGBUG
  588. // this should turn off power, but for now we silently
  589. // ignore it.
  590. //
  591. rhStatus = RH_SUCCESS;
  592. break;
  593. case PORT_CONNECTION:
  594. case PORT_OVER_CURRENT:
  595. case PORT_LOW_SPEED:
  596. case PORT_RESET:
  597. TRAP();
  598. break;
  599. case C_PORT_CONNECTION:
  600. case C_PORT_ENABLE:
  601. // validate the port number
  602. if (SetupPacket->wIndex > 0 &&
  603. SetupPacket->wIndex <= RH_NUMBER_OF_PORTS) {
  604. USHORT reg;
  605. PROOTHUB_PORT hubPort =
  606. &RootHub->Port[SetupPacket->wIndex-1];
  607. reg = UHCD_RootHub_ReadPort (hubPort);
  608. // mask off the change bits
  609. reg &= ~(RH_C_PORT_ENABLE | RH_C_PORT_CONNECT);
  610. if (SetupPacket->wValue.W == C_PORT_CONNECTION) {
  611. #if DBG
  612. RootHub->DisabledPort[SetupPacket->wIndex - 1]
  613. &= ~UHCD_FAKE_CONNECT_CHANGE;
  614. #endif
  615. reg |= RH_C_PORT_CONNECT;
  616. LOGENTRY(LOG_MISC, 'rCPC', SetupPacket->wIndex, 0, 0);
  617. } else {
  618. // C_PORT_ENABLE
  619. reg |= RH_C_PORT_ENABLE;
  620. LOGENTRY(LOG_MISC, 'rCLE', SetupPacket->wIndex, 0, 0);
  621. }
  622. UHCD_RootHub_WritePort(hubPort, reg);
  623. rhStatus = RH_SUCCESS;
  624. }
  625. break;
  626. case C_PORT_RESET:
  627. if (SetupPacket->wIndex >0 &&
  628. SetupPacket->wIndex <= RH_NUMBER_OF_PORTS) {
  629. PROOTHUB_PORT hubPort =
  630. &RootHub->Port[SetupPacket->wIndex-1];
  631. LOGENTRY(LOG_MISC, 'rCLP', SetupPacket->wIndex,
  632. hubPort->ResetChange, 0);
  633. hubPort->ResetChange = FALSE;
  634. LOGENTRY(LOG_MISC, 'rCLR', SetupPacket->wIndex, 0, 0);
  635. rhStatus = RH_SUCCESS;
  636. }
  637. break;
  638. case PORT_SUSPEND:
  639. //
  640. // clearing port suspend triggers a resume
  641. //
  642. if (SetupPacket->wIndex > 0 &&
  643. SetupPacket->wIndex <= RH_NUMBER_OF_PORTS) {
  644. USHORT reg;
  645. PROOTHUB_PORT hubPort =
  646. &RootHub->Port[SetupPacket->wIndex-1];
  647. reg = UHCD_RootHub_ReadPort(hubPort);
  648. //
  649. // signal resume on the port
  650. //
  651. if (RootHub->DoSelectiveSuspend) {
  652. reg |= RH_PORT_RESUME;
  653. UHCD_RootHub_WritePort(hubPort, reg);
  654. UHCD_RootHub_Timer(hubPort->DeviceObject,
  655. RH_RESET_TIMELENGTH, //bugbug
  656. &RootHub_SuspendTimerHandler,
  657. (PVOID)hubPort);
  658. rhStatus = RH_SUCCESS;
  659. LOGENTRY(LOG_MISC, 'rCPS', hubPort, 0, 0);
  660. } else {
  661. rhStatus = RH_SUCCESS;
  662. }
  663. #ifdef MAX_DEBUG
  664. TEST_TRAP();
  665. #endif
  666. }
  667. break;
  668. case C_PORT_SUSPEND:
  669. if (SetupPacket->wIndex > 0 &&
  670. SetupPacket->wIndex <= RH_NUMBER_OF_PORTS) {
  671. PROOTHUB_PORT hubPort =
  672. &RootHub->Port[SetupPacket->wIndex-1];
  673. hubPort->SuspendChange = FALSE;
  674. LOGENTRY(LOG_MISC, 'rCls', SetupPacket->wIndex, 0, 0);
  675. rhStatus = RH_SUCCESS;
  676. #ifdef MAX_DEBUG
  677. TEST_TRAP();
  678. #endif
  679. }
  680. break;
  681. case C_PORT_OVER_CURRENT:
  682. TEST_TRAP();
  683. rhStatus = RH_SUCCESS;
  684. break;
  685. default:
  686. TRAP();
  687. }
  688. } else {
  689. //
  690. // clear hub feature
  691. //
  692. LOGENTRY(LOG_MISC, 'rCHR', SetupPacket->wValue.W, 0, 0);
  693. switch(SetupPacket->wValue.W) {
  694. case C_HUB_LOCAL_POWER:
  695. case C_HUB_OVER_CURRENT:
  696. default:
  697. TRAP();
  698. }
  699. }
  700. break;
  701. case HUB_REQUEST_GET_STATE:
  702. //
  703. //
  704. //
  705. TRAP();
  706. break;
  707. case HUB_REQUEST_SET_FEATURE:
  708. //
  709. // Hub/Port feature request
  710. //
  711. if (SetupPacket->bmRequestType.Recipient == RECIPIENT_PORT) {
  712. //
  713. // set port feature
  714. //
  715. switch(SetupPacket->wValue.W) {
  716. case PORT_RESET:
  717. LOGENTRY(LOG_MISC, 'rRES', SetupPacket->wIndex, 0, 0);
  718. if (SetupPacket->wIndex > 0 &&
  719. SetupPacket->wIndex <= RH_NUMBER_OF_PORTS) {
  720. USHORT reg;
  721. PROOTHUB_PORT hubPort =
  722. &RootHub->Port[SetupPacket->wIndex-1];
  723. reg = UHCD_RootHub_ReadPort(hubPort);
  724. if (reg & RH_PORT_RESET) {
  725. //
  726. // stall if the port is already in reset
  727. //
  728. rhStatus = RH_STALL;
  729. TEST_TRAP();
  730. } else {
  731. //
  732. // drive reset on the port
  733. // for RH_RESET_TIMELENGTH (in ms)
  734. //
  735. reg |= RH_PORT_RESET;
  736. UHCD_RootHub_WritePort(hubPort, reg);
  737. UHCD_RootHub_Timer(hubPort->DeviceObject,
  738. RH_RESET_TIMELENGTH,
  739. &RootHub_ResetTimerHandler,
  740. (PVOID)hubPort);
  741. rhStatus = RH_SUCCESS;
  742. LOGENTRY(LOG_MISC, 'rSTM', hubPort, 0, 0);
  743. }
  744. }
  745. break;
  746. case PORT_SUSPEND:
  747. if (SetupPacket->wIndex > 0 &&
  748. SetupPacket->wIndex <= RH_NUMBER_OF_PORTS) {
  749. USHORT reg;
  750. PROOTHUB_PORT hubPort =
  751. &RootHub->Port[SetupPacket->wIndex-1];
  752. reg = UHCD_RootHub_ReadPort(hubPort);
  753. if ((reg & (RH_PORT_SUSPEND | RH_PORT_ENABLE)) ==
  754. (RH_PORT_SUSPEND | RH_PORT_ENABLE)) {
  755. //
  756. // stall if the port is already in suspended
  757. //
  758. // 9/7/2000: Just ignore this case and return success
  759. //
  760. rhStatus = RH_SUCCESS;
  761. } else {
  762. //
  763. // write the suspend bit
  764. //
  765. #ifdef MAX_DEBUG
  766. TRAP();
  767. #endif
  768. if (RootHub->DoSelectiveSuspend) {
  769. reg |= (RH_PORT_SUSPEND | RH_PORT_ENABLE);
  770. UHCD_RootHub_WritePort(hubPort, reg);
  771. rhStatus = RH_SUCCESS;
  772. } else {
  773. // just pretend we did it for the piix4
  774. rhStatus = RH_SUCCESS;
  775. LOGENTRY(LOG_MISC, 'rSno', hubPort, reg, rhStatus);
  776. }
  777. LOGENTRY(LOG_MISC, 'rSUS', hubPort, reg, rhStatus);
  778. }
  779. }
  780. break;
  781. case PORT_ENABLE:
  782. if (SetupPacket->wIndex > 0 &&
  783. SetupPacket->wIndex <= RH_NUMBER_OF_PORTS) {
  784. USHORT reg;
  785. PROOTHUB_PORT hubPort =
  786. &RootHub->Port[SetupPacket->wIndex-1];
  787. reg = UHCD_RootHub_ReadPort(hubPort);
  788. #ifdef MAX_DEBUG
  789. TRAP();
  790. #endif
  791. reg |= RH_PORT_ENABLE;
  792. UHCD_RootHub_WritePort(hubPort, reg);
  793. rhStatus = RH_SUCCESS;
  794. LOGENTRY(LOG_MISC, 'rPEN', hubPort, 0, 0);
  795. }
  796. break;
  797. case PORT_POWER:
  798. // just return success for a power on request
  799. rhStatus = RH_SUCCESS;
  800. break;
  801. case PORT_CONNECTION:
  802. case PORT_OVER_CURRENT:
  803. case PORT_LOW_SPEED:
  804. case C_PORT_CONNECTION:
  805. case C_PORT_ENABLE:
  806. case C_PORT_SUSPEND:
  807. case C_PORT_OVER_CURRENT:
  808. case C_PORT_RESET:
  809. default:
  810. TRAP();
  811. }
  812. } else {
  813. //
  814. // set hub feature
  815. //
  816. switch(SetupPacket->wValue.W) {
  817. case C_HUB_LOCAL_POWER:
  818. case C_HUB_OVER_CURRENT:
  819. default:
  820. TRAP();
  821. }
  822. }
  823. break;
  824. case HUB_REQUEST_GET_DESCRIPTOR:
  825. //
  826. // return the hub descriptor
  827. //
  828. if (SetupPacket->wValue.W == 0 &&
  829. // we already know it is a class command
  830. SetupPacket->bmRequestType.Dir == RH_DEV_TO_HOST) {
  831. LOGENTRY(LOG_MISC, 'rGHD', SetupPacket, SetupPacket->wLength, 0);
  832. RH_CHECK_BUFFER(SetupPacket->wLength,
  833. *BufferLength,
  834. sizeof(RH_HubDescriptor));
  835. length = MIN(*BufferLength, sizeof(RH_HubDescriptor));
  836. RtlCopyMemory(Buffer, RH_HubDescriptor, length);
  837. *BufferLength = length;
  838. rhStatus = RH_SUCCESS;
  839. }
  840. break;
  841. case HUB_REQUEST_SET_DESCRIPTOR:
  842. //
  843. //
  844. //
  845. TRAP();
  846. break;
  847. default:
  848. // bad command
  849. TRAP();
  850. break;
  851. }
  852. return rhStatus;
  853. }
  854. RHSTATUS
  855. RootHub_Endpoint1(
  856. IN PROOTHUB RootHub,
  857. IN PUCHAR Buffer,
  858. IN OUT PULONG BufferLength
  859. )
  860. /*++
  861. Routine Description:
  862. Arguments:
  863. Return Value:
  864. root hub transfer status code
  865. --*/
  866. {
  867. RHSTATUS rhStatus = RH_NAK;
  868. PROOTHUB_PORT hubPort;
  869. USHORT reg;
  870. PUCHAR bitmap;
  871. ULONG bit = 2, i;
  872. ASSERT_RH(RootHub);
  873. LOGENTRY(LOG_MISC, 'rPOL', RootHub, Buffer, *BufferLength);
  874. if (*BufferLength < sizeof(*bitmap)) {
  875. UHCD_KdTrap(("Bad buffer length passed to root hub\n"));
  876. return RH_STALL;
  877. }
  878. bitmap = (PUCHAR) Buffer;
  879. *bitmap = 0;
  880. // one byte of data returned.
  881. *BufferLength = 1;
  882. UHCD_ASSERT(RootHub->NumberOfPorts < 8);
  883. for (i=0; i< RootHub->NumberOfPorts; i++) {
  884. hubPort = &RootHub->Port[i];
  885. reg = UHCD_RootHub_ReadPort(hubPort);
  886. if (!(reg & RH_PORT_RESET) &&
  887. ((reg & RH_C_PORT_ENABLE) ||
  888. (reg & RH_C_PORT_CONNECT) ||
  889. hubPort->ResetChange ||
  890. hubPort->SuspendChange
  891. #if DBG
  892. || (RootHub->DisabledPort[i] & UHCD_FAKE_CONNECT_CHANGE)
  893. #endif
  894. )) {
  895. //
  896. // note we have a change on this port
  897. //
  898. *bitmap |= bit;
  899. rhStatus = RH_SUCCESS;
  900. LOGENTRY(LOG_MISC, 'rSTA', RootHub, reg, hubPort->ResetChange);
  901. }
  902. bit = bit<<1;
  903. }
  904. return rhStatus;
  905. }
  906. BOOLEAN
  907. RootHub_PortsIdle(
  908. IN PROOTHUB RootHub
  909. )
  910. /*++
  911. Routine Description:
  912. Arguments:
  913. Return Value:
  914. root hub idle detect
  915. --*/
  916. {
  917. PROOTHUB_PORT hubPort;
  918. USHORT reg;
  919. ULONG i;
  920. BOOLEAN idle = TRUE;
  921. for (i=0; i< RootHub->NumberOfPorts; i++) {
  922. hubPort = &RootHub->Port[i];
  923. reg = UHCD_RootHub_ReadPort(hubPort);
  924. #if DBG
  925. if(RootHub->DisabledPort[i] & UHCD_FAKE_DISCONNECT) {
  926. reg &= ~RH_PORT_CONNECT;
  927. }
  928. #endif
  929. if ((reg & (RH_PORT_CONNECT | RH_PORT_SUSPEND)) == RH_PORT_CONNECT) {
  930. idle = FALSE;
  931. }
  932. #if DBG
  933. else {
  934. LOGENTRY(LOG_MISC, 'rIDL', RootHub, reg, 0);
  935. }
  936. #endif
  937. }
  938. return idle;
  939. }