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.

954 lines
33 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. OHCIroot.c
  5. Abstract:
  6. The module manages the Root Hub of the OpenHCI controller.
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. 03-22-96 : created jfuller
  12. 05-25-96 : reworked kenray
  13. --*/
  14. #include "OpenHCI.h"
  15. // This is the data packet that the upper levels of the stack believe
  16. // are sending to a real hub. We intercept and interpret this packet.
  17. typedef struct _SETUP_PACKET {
  18. union {
  19. struct {
  20. UCHAR Recipient:
  21. 5; // entity to recieve command
  22. UCHAR Type:
  23. 2; // type of command
  24. UCHAR DirectionIn:
  25. 1; // data transfer direction
  26. };
  27. struct {
  28. UCHAR RequestType; // request type code
  29. };
  30. };
  31. UCHAR Request; // command code
  32. USHORT wValue; // parameter
  33. USHORT wIndex; // another parameter
  34. USHORT wLength; // transfer length (same as
  35. // TransferBufferLength?)
  36. } SETUP_PACKET, *PSETUP_PACKET;
  37. #define SPrequest_GetStatus 0x0
  38. #define SPrequest_ClearFeature 0x1
  39. #define SPrequest_SetFeature 0x3
  40. #define SPrequest_SetAddress 0x5
  41. #define SPrequest_GetDescriptor 0x6
  42. #define SPrequest_SetDescriptor 0x7
  43. #define SPrequest_GetConfiguration 0x8
  44. #define SPrequest_SetConfiguration 0x9
  45. #define SPrequest_GetInterface 0xA
  46. #define SPrequest_SetInterface 0xB
  47. #define SPrequest_SyncFrame 0xC
  48. #define SPrecipient_Device 0
  49. #define SPrecipient_Interface 1
  50. #define SPrecipient_Endpoint 2
  51. #define SPrecipient_Other 3
  52. #define SPtype_Standard 0
  53. #define SPtype_Class 1
  54. #define SPtype_Vendor 2
  55. #define SPbmrt_In_Standard_Device 0x80 // 1000 0000
  56. #define SPbmrt_In_Standard_Interface 0x81 // 1000 0001
  57. #define SPbmrt_In_Standard_Endpoint 0x82 // 1000 0010
  58. #define SPbmrt_Out_Standard_Device 0x00 // 0000 0000
  59. #define SPbmrt_Out_Standard_Interface 0x01 // 0000 0001
  60. #define SPbmrt_Out_Standard_Endpoint 0x02 // 0000 0010
  61. #define SPbmrt_In_Class_Device 0xA0 // 1010 0000
  62. #define SPbmrt_In_Class_Other 0xA3 // 1010 0011
  63. #define SPbmrt_Out_Class_Device 0x20 // 0010 0000
  64. #define SPbmrt_Out_Class_Other 0x23 // 0010 0011
  65. //
  66. // Hub Class Feature Selectors, see Table 11-13 in the
  67. // Universal Serial Bus Specification Revision 1.0
  68. //
  69. //
  70. // Recipient Hub
  71. //
  72. #define C_HUB_LOCAL_POWER 0
  73. #define C_HUB_OVER_CURRENT 1
  74. //
  75. // Recipient Port
  76. //
  77. #define PORT_CONNECTION 0
  78. #define PORT_ENABLE 1
  79. #define PORT_SUSPEND 2
  80. #define PORT_OVER_CURRENT 3
  81. #define PORT_RESET 4
  82. #define PORT_POWER 8
  83. #define PORT_LOW_SPEED 9
  84. #define C_PORT_CONNECTION 16
  85. #define C_PORT_ENABLE 17
  86. #define C_PORT_SUSPEND 18
  87. #define C_PORT_OVER_CURRENT 19
  88. #define C_PORT_RESET 20
  89. // default descriptors for root hub
  90. UCHAR RH_DeviceDescriptor[] = {0x12, //bLength
  91. 0x01, //bDescrpitorType
  92. 0x00, 0x01, //bcdUSB
  93. 0x09, //bDeviceClass
  94. 0x01, //bDeviceSubClass
  95. 0x00, //bDeviceProtocol
  96. 0x08, //bMaxPacketSize0
  97. 0x00, 0x00, //idVendor
  98. 0x00, 0x00, //idProduct
  99. 0x00, 0x00, //bcdDevice
  100. 0x00, //iManufacturer
  101. 0x00, //iProduct
  102. 0x00, //iSerialNumber
  103. 0x01};//bNumConfigurations
  104. UCHAR RH_ConfigurationDescriptor[] =
  105. /* Config Descriptor */
  106. {0x09, //bLength
  107. 0x02, //bDescriptorType
  108. 0x19, 0x00, //wTotalLength
  109. 0x01, //bNumInterfaces
  110. 0x01, //iConfigurationValue
  111. 0x00, //iConfiguration
  112. 0x40, //bmAttributes
  113. 0x00, //MaxPower
  114. /* Interface Descriptor */
  115. 0x09, //bLength
  116. 0x04, //bDescriptorType
  117. 0x00, //bInterfaceNumber
  118. 0x00, //bAlternateSetting
  119. 0x01, //bNumEndpoints
  120. 0x09, //bInterfaceClass
  121. 0x01, //bInterfaceSubClass
  122. 0x00, //bInterfaceProtocol
  123. 0x00, //iInterface
  124. /* Endpoint Descriptor */
  125. 0x07, //bLength
  126. 0x05, //bDescriptorType
  127. 0x81, //bEndpointAddress
  128. 0x03, //bmAttributes
  129. 0x08, 0x00, //wMaxPacketSize
  130. 0x0a};//bInterval
  131. UCHAR RH_HubDescriptor[] =
  132. {0x09, //bLength
  133. 0x29, //bDescriptorType
  134. 0x02, //bNbrPorts
  135. 0x00, 0x00, //wHubCharacteristics
  136. 0x00, // bPwrOn2PwrGood
  137. 0x00}; // bHubContrCurrent
  138. void OpenHCI_CancelRootInterrupt(PDEVICE_OBJECT, PIRP);
  139. NTSTATUS
  140. OpenHCI_RootHubStartXfer(
  141. PDEVICE_OBJECT DeviceObject,
  142. PHCD_DEVICE_DATA DeviceData,
  143. PIRP Irp,
  144. PHCD_URB UsbRequest,
  145. PHCD_ENDPOINT Endpoint
  146. )
  147. {
  148. PSETUP_PACKET Pkt;
  149. PCHAR Buffer;
  150. KIRQL oldIrql;
  151. PHC_OPERATIONAL_REGISTER HC = DeviceData->HC;
  152. struct _URB_HCD_COMMON_TRANSFER *trans =
  153. &UsbRequest->HcdUrbCommonTransfer;
  154. ASSERT(NULL == Endpoint->HcdED);
  155. if (Endpoint->Type == USB_ENDPOINT_TYPE_CONTROL
  156. && Endpoint->EndpointNumber == 0) {
  157. //
  158. // This is the default endpoint of the root hub
  159. //
  160. Pkt = (PSETUP_PACKET) & trans->Extension.u.SetupPacket[0];
  161. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_RH_TRACE,
  162. ("'RootHub emulation: %02x %02x %04x %04x %04x\n",
  163. Pkt->RequestType, Pkt->Request,
  164. Pkt->wValue, Pkt->wIndex,
  165. Pkt->wLength));
  166. ASSERT(trans->TransferBufferLength == Pkt->wLength);
  167. if (trans->TransferBufferLength) {
  168. // This is cause an exception if any of the upper levels of the
  169. // USB stack (those that created this MDL) are misbehaving.
  170. Buffer = MmGetSystemAddressForMdl(trans->TransferBufferMDL);
  171. } else {
  172. Buffer = NULL;
  173. }
  174. switch (Pkt->Request) {
  175. case SPrequest_GetStatus:
  176. switch (Pkt->RequestType) {
  177. case SPbmrt_In_Class_Device:
  178. //
  179. // GetHubStatus
  180. //
  181. if (4 != trans->TransferBufferLength) {
  182. TRAP();
  183. break;
  184. }
  185. *((PULONG) Buffer) = ~HcRhS_DeviceRemoteWakeupEnable
  186. & READ_REGISTER_ULONG(&HC->HcRhStatus);
  187. trans->Status = USBD_STATUS_SUCCESS;
  188. return STATUS_SUCCESS;
  189. case SPbmrt_In_Class_Other:
  190. //
  191. // GetPortStatus
  192. //
  193. if (4 != trans->TransferBufferLength) {
  194. TRAP();
  195. break;
  196. }
  197. *((PULONG) Buffer) = ReadPortStatusFix(DeviceData,
  198. Pkt->wIndex - 1);
  199. LOGENTRY(G, 'gPRT', Pkt->wIndex, trans->TransferBufferLength, *((PULONG) Buffer));
  200. trans->TransferBufferLength = 4;
  201. trans->Status = USBD_STATUS_SUCCESS;
  202. return STATUS_SUCCESS;
  203. case SPbmrt_In_Standard_Device:
  204. if (0 == Pkt->wIndex && 2 == trans->TransferBufferLength) {
  205. Buffer[0] = 3; // Remote Wakeup & Self Powered
  206. Buffer[1] = 0;
  207. return STATUS_SUCCESS;
  208. }
  209. break;
  210. case SPbmrt_In_Standard_Interface:
  211. if (0 == Pkt->wIndex && 2 == trans->TransferBufferLength) {
  212. Buffer[0] = Buffer[0] = 0;
  213. return STATUS_SUCCESS;
  214. }
  215. break;
  216. case SPbmrt_In_Standard_Endpoint:
  217. if ((2 == trans->TransferBufferLength)
  218. && ((1 == Pkt->wIndex) || (0 == Pkt->wIndex))) {
  219. Buffer[0] = Buffer[0] = 0;
  220. return STATUS_SUCCESS;
  221. }
  222. break;
  223. }
  224. break;
  225. case SPrequest_ClearFeature:
  226. if (SPbmrt_Out_Class_Other == Pkt->RequestType) {
  227. //
  228. // clear port feature
  229. //
  230. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_RH_TRACE,
  231. ("'Clear Feature wValue = %x index = %x\n",
  232. Pkt->wValue, Pkt->wIndex));
  233. switch (Pkt->wValue) {
  234. case PORT_ENABLE:
  235. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  236. HcRhPS_ClearPortEnable);
  237. break;
  238. case PORT_SUSPEND:
  239. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  240. HcRhPS_ClearPortSuspend);
  241. break;
  242. case PORT_POWER:
  243. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  244. HcRhPS_ClearPortPower);
  245. break;
  246. case C_PORT_CONNECTION:
  247. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  248. HcRhPS_ClearConnectStatusChange);
  249. #if FAKEPORTCHANGE
  250. DeviceData->FakePortChange &= ~(1 << (Pkt->wIndex - 1));
  251. #endif
  252. break;
  253. case C_PORT_ENABLE:
  254. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  255. HcRhPS_ClearPortEnableStatusChange);
  256. break;
  257. case C_PORT_SUSPEND:
  258. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  259. HcRhPS_ClearPortSuspendStatusChange);
  260. break;
  261. case C_PORT_OVER_CURRENT:
  262. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  263. HcRhPS_ClearPortOverCurrentChange);
  264. break;
  265. case C_PORT_RESET:
  266. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  267. HcRhPS_ClearPortResetStatusChange);
  268. break;
  269. default:
  270. break;
  271. }
  272. trans->TransferBufferLength = 0;
  273. trans->Status = USBD_STATUS_SUCCESS;
  274. return STATUS_SUCCESS;
  275. } else if (SPbmrt_Out_Class_Device == Pkt->RequestType) {
  276. //
  277. // clear hub feature
  278. //
  279. switch (Pkt->wValue) {
  280. case C_HUB_LOCAL_POWER:
  281. // The OpenHCI Root Hub does not support the local power
  282. // status feature. The Local Power Status Change bit is
  283. // always read as '0'. See section 7.4.3 hcRhStatus in
  284. // the OpenHCI specification.
  285. break;
  286. case C_HUB_OVER_CURRENT:
  287. WRITE_REGISTER_ULONG(&HC->HcRhStatus, HcRhS_ClearOverCurrentIndicatorChange);
  288. break;
  289. default:
  290. break;
  291. }
  292. trans->TransferBufferLength = 0;
  293. trans->Status = USBD_STATUS_SUCCESS;
  294. return STATUS_SUCCESS;
  295. }
  296. break;
  297. case SPrequest_SetFeature:
  298. if (SPbmrt_Out_Class_Other == Pkt->RequestType) {
  299. //
  300. // set port feature
  301. //
  302. switch (Pkt->wValue) {
  303. case PORT_ENABLE:
  304. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  305. HcRhPS_SetPortEnable);
  306. break;
  307. case PORT_SUSPEND:
  308. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  309. HcRhPS_SetPortSuspend);
  310. break;
  311. case PORT_RESET:
  312. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  313. HcRhPS_SetPortReset);
  314. break;
  315. case PORT_POWER:
  316. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[Pkt->wIndex - 1],
  317. HcRhPS_SetPortPower);
  318. break;
  319. }
  320. trans->TransferBufferLength = 0;
  321. trans->Status = USBD_STATUS_SUCCESS;
  322. return STATUS_SUCCESS;
  323. } else if (SPbmrt_Out_Class_Device == Pkt->RequestType) {
  324. //
  325. // set hub feature (no hub features can be set)
  326. //
  327. switch (Pkt->wValue) {
  328. default:
  329. break;
  330. }
  331. trans->TransferBufferLength = 0;
  332. trans->Status = USBD_STATUS_SUCCESS;
  333. return STATUS_SUCCESS;
  334. }
  335. break;
  336. case SPrequest_SetAddress:
  337. ;
  338. if (SPbmrt_Out_Standard_Device == Pkt->RequestType) {
  339. if (DeviceData->RootHubAddress != (char) Pkt->wValue) {
  340. Endpoint->EpFlags &= ~EP_ROOT_HUB;
  341. ASSERT(NULL == DeviceData->RootHubInterrupt);
  342. //
  343. // If you change the address while there is an open
  344. // endpoint
  345. // to the root hub interrupt than you strand that
  346. // endpoint.
  347. // You really should close this endpoint before changing
  348. // the
  349. // address.
  350. //
  351. // if (DeviceData->RootHubInterrupt)
  352. // {
  353. // ExFreePool (DeviceData->RootHubInterrupt);
  354. // DeviceData->RootHubInterrupt = 0;
  355. // }
  356. }
  357. DeviceData->RootHubAddress = (char) Pkt->wValue;
  358. trans->TransferBufferLength = 0;
  359. trans->Status = USBD_STATUS_SUCCESS;
  360. return STATUS_SUCCESS;
  361. }
  362. break;
  363. case SPrequest_GetDescriptor:
  364. {
  365. union {
  366. UCHAR rc[4];
  367. ULONG rl;
  368. USHORT rs;
  369. } ports;
  370. ULONG length;
  371. switch (Pkt->RequestType) {
  372. case SPbmrt_In_Class_Device:
  373. {
  374. UCHAR scratch[100];
  375. PUSB_HUB_DESCRIPTOR hubDescriptor;
  376. HC_RH_DESCRIPTOR_A descrA;
  377. //
  378. // Get Descriptor, Hub
  379. //
  380. OHCI_ASSERT(sizeof(scratch)>sizeof(RH_HubDescriptor));
  381. hubDescriptor = (PUSB_HUB_DESCRIPTOR) scratch;
  382. RtlCopyMemory(scratch,
  383. RH_HubDescriptor,
  384. sizeof(RH_DeviceDescriptor));
  385. descrA.ul =
  386. READ_REGISTER_ULONG(&HC->HcRhDescriptorA.ul);
  387. // this will set
  388. // bNumberOfPorts, wHubCharacteristics & bPowerOnToPowerGood
  389. RtlCopyMemory(&hubDescriptor->bNumberOfPorts,
  390. &descrA,
  391. sizeof(descrA));
  392. LOGENTRY(G, 'rhCH', DeviceData, descrA.ul, 0);
  393. hubDescriptor->bHubControlCurrent = 0;
  394. ports.rl = READ_REGISTER_ULONG(&HC->HcRhDescriptorB.ul);
  395. if (hubDescriptor->bNumberOfPorts < 8) {
  396. hubDescriptor->bDescriptorLength = 9;
  397. hubDescriptor->bRemoveAndPowerMask[0] = ports.rc[0];
  398. hubDescriptor->bRemoveAndPowerMask[1] = ports.rc[2];
  399. } else {
  400. hubDescriptor->bDescriptorLength = 11;
  401. RtlCopyMemory(&hubDescriptor->bRemoveAndPowerMask[0],
  402. &ports,
  403. sizeof(ports));
  404. }
  405. trans->TransferBufferLength
  406. = MIN(hubDescriptor->bDescriptorLength, trans->TransferBufferLength);
  407. RtlCopyMemory(Buffer, scratch, trans->TransferBufferLength);
  408. trans->Status = USBD_STATUS_SUCCESS;
  409. return STATUS_SUCCESS;
  410. }
  411. case SPbmrt_In_Standard_Device:
  412. {
  413. PUSB_DEVICE_DESCRIPTOR deviceDescriptor;
  414. PUSB_CONFIGURATION_DESCRIPTOR configDescriptor;
  415. UCHAR scratch[100];
  416. OHCI_ASSERT(sizeof(scratch)>sizeof(RH_DeviceDescriptor));
  417. OHCI_ASSERT(sizeof(scratch)>sizeof(RH_ConfigurationDescriptor));
  418. //
  419. // Get Descriptor
  420. //
  421. switch(Pkt->wValue) {
  422. case 0x100:
  423. { // Device Descriptor
  424. deviceDescriptor = (PUSB_DEVICE_DESCRIPTOR) scratch;
  425. RtlCopyMemory(scratch,
  426. RH_DeviceDescriptor,
  427. sizeof(RH_DeviceDescriptor));
  428. length =
  429. MIN(sizeof(RH_DeviceDescriptor), Pkt->wLength);
  430. deviceDescriptor->idVendor =
  431. DeviceData->VendorID;
  432. deviceDescriptor->idProduct =
  433. DeviceData->DeviceID;
  434. // deviceDescriptor->bcdDevice =
  435. // DeviceData->RevisionID;
  436. }
  437. break;
  438. case 0x200:
  439. { // Configuration Descriptor
  440. configDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) scratch;
  441. RtlCopyMemory(scratch,
  442. RH_ConfigurationDescriptor,
  443. sizeof(RH_ConfigurationDescriptor));
  444. length = MIN(sizeof(RH_ConfigurationDescriptor),
  445. Pkt->wLength);
  446. }
  447. break;
  448. default:
  449. TRAP(); // should not get here, if we do then
  450. // it is probably a bug in the hub driver
  451. trans->Status = USBD_STATUS_STALL_PID;
  452. trans->TransferBufferLength = 0; // No data transferred
  453. return STATUS_IO_DEVICE_ERROR;
  454. }
  455. RtlCopyMemory(Buffer, scratch, length);
  456. trans->TransferBufferLength = length;
  457. trans->Status = USBD_STATUS_SUCCESS;
  458. return STATUS_SUCCESS;
  459. }
  460. default:
  461. ;
  462. }
  463. break;
  464. }
  465. case SPrequest_GetConfiguration:
  466. if (SPbmrt_In_Standard_Device == Pkt->RequestType &&
  467. 1 == trans->TransferBufferLength) {
  468. *Buffer = (CHAR) DeviceData->RootHubConfig;
  469. trans->Status = USBD_STATUS_SUCCESS;
  470. return STATUS_SUCCESS;
  471. }
  472. break;
  473. case SPrequest_SetConfiguration:
  474. if (SPbmrt_Out_Standard_Device == Pkt->RequestType &&
  475. 0 == trans->TransferBufferLength &&
  476. 0 == (Pkt->wValue & ~1)) { // Only configs of 0 and 1
  477. // supported.
  478. DeviceData->RootHubConfig = (char) Pkt->wValue;
  479. trans->Status = USBD_STATUS_SUCCESS;
  480. return STATUS_SUCCESS;
  481. }
  482. case SPrequest_SetDescriptor:
  483. case SPrequest_GetInterface: // We support only one interface.
  484. case SPrequest_SetInterface: // We support only one interface.
  485. case SPrequest_SyncFrame:
  486. default:
  487. ;
  488. }
  489. trans->Status = USBD_STATUS_STALL_PID;
  490. trans->TransferBufferLength = 0; // No data transferred
  491. return STATUS_IO_DEVICE_ERROR;
  492. } else if (Endpoint->Type == USB_ENDPOINT_TYPE_INTERRUPT
  493. && Endpoint->EndpointNumber == 1
  494. && DeviceData->RootHubConfig != 0) {
  495. NTSTATUS status;
  496. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_RH_TRACE,
  497. ("'***** Insert REQUEST for Interrupt \n\n"));
  498. ASSERT(DeviceData->RootHubInterrupt == Endpoint);
  499. status = CheckRootHub(DeviceData,
  500. HC,
  501. UsbRequest);
  502. if (status == STATUS_PENDING) {
  503. KeAcquireSpinLock(&Endpoint->QueueLock, &oldIrql);
  504. trans->Status = HCD_PENDING_STATUS_QUEUED;
  505. InsertTailList(&Endpoint->RequestQueue, &trans->hca.HcdListEntry);
  506. KeReleaseSpinLock(&Endpoint->QueueLock, oldIrql);
  507. if (NULL == trans->UrbLink) {
  508. Irp->IoStatus.Status = STATUS_PENDING;
  509. IoMarkIrpPending(Irp);
  510. IoSetCancelRoutine(Irp, OpenHCI_CancelRootInterrupt);
  511. if (Irp->Cancel) {
  512. struct _URB_HCD_COMMON_TRANSFER *nextTrans;
  513. if (IoSetCancelRoutine(Irp, NULL)) {
  514. while (trans) {
  515. nextTrans = &trans->UrbLink->HcdUrbCommonTransfer;
  516. KeAcquireSpinLock(&Endpoint->QueueLock, &oldIrql);
  517. RemoveEntryList(&trans->hca.HcdListEntry);
  518. trans->Status = USBD_STATUS_CANCELED;
  519. KeReleaseSpinLock(&Endpoint->QueueLock, oldIrql);
  520. trans = nextTrans;
  521. }
  522. OpenHCI_CompleteIrp(DeviceObject, Irp, STATUS_CANCELLED);
  523. return STATUS_CANCELLED;
  524. } else {
  525. return STATUS_CANCELLED;
  526. }
  527. }
  528. }
  529. WRITE_REGISTER_ULONG(&HC->HcInterruptEnable, HcInt_RootHubStatusChange);
  530. }
  531. return status;
  532. }
  533. //
  534. // Unknown transfer to root hub
  535. //
  536. trans->Status = USBD_STATUS_DEV_NOT_RESPONDING;
  537. trans->TransferBufferLength = 0;
  538. return STATUS_IO_DEVICE_ERROR;
  539. }
  540. ULONG
  541. OpenHCI_BuildRootHubStatusChange(
  542. PHCD_DEVICE_DATA DeviceData,
  543. PHC_OPERATIONAL_REGISTER HC
  544. )
  545. /*++
  546. Routine Description:
  547. Builds and returns a bitmap of the current root hub status changes.
  548. Bit 0 = Hub change detected
  549. Bit N = Port N change detected, where port N is one-based, not zero-based
  550. --*/
  551. {
  552. ULONG changes;
  553. ULONG portIndex;
  554. ULONG mask;
  555. ULONG portStatus;
  556. // Loop over the ports and build a status change mask for each
  557. // each port that has a current status change.
  558. //
  559. changes = 0;
  560. for (portIndex = 0, mask = (1 << 1);
  561. portIndex < DeviceData->NumberOfPorts;
  562. portIndex++, mask <<= 1)
  563. {
  564. // Read the current port status
  565. //
  566. portStatus = ReadPortStatusFix(DeviceData, portIndex);
  567. // Keep only the current port status change bits
  568. //
  569. portStatus &= (HcRhPS_ConnectStatusChange |
  570. HcRhPS_PortEnableStatusChange |
  571. HcRhPS_PortSuspendStatusChange |
  572. HcRhPS_OverCurrentIndicatorChange |
  573. HcRhPS_PortResetStatusChange);
  574. if (portStatus)
  575. {
  576. changes |= mask;
  577. }
  578. LOGENTRY(G, 'prtS', changes, portStatus, portIndex);
  579. }
  580. // Read the current status of the hub itself
  581. //
  582. portStatus = READ_REGISTER_ULONG(&HC->HcRhStatus);
  583. // Keep only the current hub status change bits
  584. //
  585. portStatus &= (HcRhS_LocalPowerStatusChange |
  586. HcRhS_OverCurrentIndicatorChange);
  587. if (portStatus)
  588. {
  589. changes |= 1; // Bit 0 is for the hub itself.
  590. }
  591. return changes;
  592. }
  593. void
  594. EmulateRootHubInterruptXfer(
  595. PHCD_DEVICE_DATA DeviceData,
  596. PHC_OPERATIONAL_REGISTER HC
  597. )
  598. /*++
  599. Routine Description:
  600. Emulates an interupt pipe to the Root Hubs #1 Endpoint.
  601. We Pop an entry off of the URB request queue and satisfy
  602. it with the current state of the Root hub status registers.
  603. If there is no outstanding request then disable this
  604. interrupt.
  605. --*/
  606. {
  607. PHCD_ENDPOINT Endpoint = DeviceData->RootHubInterrupt;
  608. PLIST_ENTRY entry;
  609. KIRQL oldIrql;
  610. PHCD_URB UsbRequest;
  611. ULONG changes;
  612. PCHAR buffer;
  613. PDRIVER_CANCEL oldCancel;
  614. struct _URB_HCD_COMMON_TRANSFER *trans;
  615. // mask off the interrupt status change
  616. WRITE_REGISTER_ULONG(&HC->HcInterruptStatus, HcInt_RootHubStatusChange);
  617. // Get a bitmap of the current root hub status changes
  618. //
  619. changes = OpenHCI_BuildRootHubStatusChange(DeviceData, HC);
  620. if (0 == changes) {
  621. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_RH_TRACE,
  622. ("'RH Interrupt no change \n\n"));
  623. return;
  624. }
  625. KeAcquireSpinLock(&Endpoint->QueueLock, &oldIrql);
  626. if (IsListEmpty(&Endpoint->RequestQueue)) {
  627. // disable interrupts for rh status change
  628. WRITE_REGISTER_ULONG(&HC->HcInterruptDisable,
  629. HcInt_RootHubStatusChange);
  630. KeReleaseSpinLock(&Endpoint->QueueLock, oldIrql);
  631. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_RH_ERROR,
  632. ("'*******WARNING*****\n"));
  633. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_RH_ERROR,
  634. ("'!!! RH Interrupt no IRP QUEUED \n"));
  635. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_RH_ERROR,
  636. ("'Disable RH interrupt\n"));
  637. return;
  638. }
  639. entry = RemoveHeadList(&Endpoint->RequestQueue);
  640. KeReleaseSpinLock(&Endpoint->QueueLock, oldIrql);
  641. UsbRequest = CONTAINING_RECORD(entry,
  642. HCD_URB,
  643. HcdUrbCommonTransfer.hca.HcdListEntry);
  644. trans = &UsbRequest->HcdUrbCommonTransfer;
  645. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_RH_TRACE,
  646. ("'RH Interrupt completing URB %x\n", UsbRequest));
  647. if (trans->TransferBufferLength &&
  648. (buffer = MmGetSystemAddressForMdl(trans->TransferBufferMDL)) != NULL)
  649. {
  650. RtlCopyMemory(buffer, &changes, trans->TransferBufferLength);
  651. }
  652. else
  653. {
  654. ASSERT(0);
  655. }
  656. trans->Status = USBD_STATUS_SUCCESS;
  657. if (0 == trans->UrbLink) {
  658. oldCancel = IoSetCancelRoutine(trans->hca.HcdIrp, NULL);
  659. if (oldCancel) {
  660. OpenHCI_CompleteIrp(DeviceData->DeviceObject,
  661. trans->hca.HcdIrp,
  662. USBD_STATUS_SUCCESS);
  663. }
  664. }
  665. }
  666. NTSTATUS
  667. CheckRootHub(PHCD_DEVICE_DATA DeviceData,
  668. PHC_OPERATIONAL_REGISTER HC,
  669. PHCD_URB UsbRequest
  670. )
  671. /*++
  672. Routine Description:
  673. before an interrupt transfer is queued this function checks the change
  674. bits in the root hub registers, if any are set the it processes the request
  675. immediately.
  676. --*/
  677. {
  678. PHCD_ENDPOINT Endpoint = DeviceData->RootHubInterrupt;
  679. ULONG changes;
  680. PCHAR buffer;
  681. PDRIVER_CANCEL oldCancel;
  682. struct _URB_HCD_COMMON_TRANSFER *trans;
  683. // Get a bitmap of the current root hub status changes
  684. //
  685. changes = OpenHCI_BuildRootHubStatusChange(DeviceData, HC);
  686. if (0 == changes) {
  687. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_RH_TRACE,
  688. ("'RH Interrupt no change \n\n"));
  689. return STATUS_PENDING;
  690. }
  691. trans = &UsbRequest->HcdUrbCommonTransfer;
  692. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_RH_TRACE,
  693. ("'RH Interrupt completing URB %x\n", UsbRequest));
  694. if (trans->TransferBufferLength &&
  695. (buffer = MmGetSystemAddressForMdl(trans->TransferBufferMDL)) != NULL)
  696. {
  697. RtlCopyMemory(buffer, &changes, trans->TransferBufferLength);
  698. }
  699. else
  700. {
  701. ASSERT(0);
  702. }
  703. trans->Status = USBD_STATUS_SUCCESS;
  704. if (0 == trans->UrbLink) {
  705. oldCancel = IoSetCancelRoutine(trans->hca.HcdIrp, NULL);
  706. // complete the request
  707. return STATUS_SUCCESS;
  708. }
  709. return STATUS_PENDING;
  710. }
  711. void
  712. OpenHCI_CancelRootInterrupt(
  713. PDEVICE_OBJECT DeviceObject,
  714. PIRP Irp
  715. )
  716. /*++
  717. Routine Description:
  718. cancel an Irp queued for Interrupt Transfer.
  719. Args:
  720. DeviceObject the object to which the irp was originally directed.
  721. Irp the poor doomed packet.
  722. --*/
  723. {
  724. PHCD_DEVICE_DATA DeviceData;
  725. PHCD_ENDPOINT Endpoint;
  726. KIRQL oldIrql;
  727. BOOLEAN lastURB;
  728. struct _URB_HCD_COMMON_TRANSFER *Trans;
  729. DeviceData = (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  730. ASSERT(TRUE == Irp->Cancel);
  731. Trans = &((PHCD_URB) URB_FROM_IRP(Irp))->HcdUrbCommonTransfer;
  732. ASSERT(URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER == Trans->Function);
  733. LOGENTRY(G, 'rCan', Irp, Trans, Trans->Status);
  734. Endpoint = Trans->hca.HcdEndpoint;
  735. ASSERT(Endpoint->EpFlags & EP_ROOT_HUB);
  736. ASSERT(URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER == Trans->Function);
  737. ASSERT(Trans->hca.HcdEndpoint == Endpoint);
  738. ASSERT(Trans->UrbLink == NULL);
  739. ASSERT(USBD_STATUS_CANCELING != Trans->Status);
  740. if (USBD_STATUS_CANCELED != Trans->Status)
  741. {
  742. KeAcquireSpinLock(&Endpoint->QueueLock, &oldIrql);
  743. // the item may have already been removed
  744. if (Trans->hca.HcdListEntry.Flink != NULL)
  745. {
  746. OHCI_ASSERT(Trans->hca.HcdListEntry.Blink != NULL);
  747. RemoveEntryList(&Trans->hca.HcdListEntry);
  748. }
  749. Trans->Status = USBD_STATUS_CANCELED;
  750. KeReleaseSpinLock(&Endpoint->QueueLock, oldIrql);
  751. }
  752. IoReleaseCancelSpinLock(Irp->CancelIrql);
  753. OpenHCI_CompleteIrp(DeviceObject, Irp, STATUS_CANCELLED);
  754. }
  755. ULONG
  756. ReadPortStatusFix(
  757. PHCD_DEVICE_DATA DeviceData,
  758. ULONG PortIndex
  759. )
  760. /*++
  761. Routine Description:
  762. Reads a HcRhPortStatus register, working around some known hardware
  763. bugs in early revs of the AMD K7 chipset.
  764. When a Port Status read is performed while Viper is mastering the PCI
  765. bus during ED & TD reads, the Port Status read may return either all
  766. '0's or an address of an ED or TD (upper bits will match the HcHCCA
  767. base address).
  768. Quick & Dirty fix:
  769. If a Port status read data has '1's in its upper reserved bits, the
  770. read is invalid and should be discarded. If a Port status read
  771. returns all '0's, then it is safe to read it a few more times, and if
  772. the status is truly 00h, then the reads should all return 00h.
  773. Otherwise, the 00h was an invalid read and the data which is
  774. subsequently returned (with '0's in its reserved bits) is valid.
  775. --*/
  776. {
  777. PULONG pulRegister;
  778. ULONG ulRegVal;
  779. int x;
  780. pulRegister = &DeviceData->HC->HcRhPortStatus[PortIndex];
  781. for (x = 0; x < 10; x++)
  782. {
  783. ulRegVal = READ_REGISTER_ULONG(pulRegister);
  784. if ((ulRegVal) && (!(ulRegVal & HcRhPS_RESERVED)))
  785. {
  786. break;
  787. }
  788. else
  789. {
  790. KeStallExecutionProcessor(5);
  791. }
  792. }
  793. #if FAKEPORTCHANGE
  794. #pragma message("NOTE: enabling fake port change hack")
  795. if (DeviceData->FakePortChange & (1 << PortIndex))
  796. {
  797. ulRegVal |= HcRhPS_ConnectStatusChange;
  798. }
  799. if (DeviceData->FakePortDisconnect & (1 << PortIndex))
  800. {
  801. ulRegVal &= ~HcRhPS_CurrentConnectStatus;
  802. }
  803. #endif
  804. return ulRegVal;
  805. }