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.

2547 lines
71 KiB

  1. /*++
  2. Copyright (c) 1999, 2000 Microsoft Corporation
  3. Module Name:
  4. async.c
  5. Abstract:
  6. miniport transfer code for control and bulk
  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. 1-1-00 : created, jdunn
  17. --*/
  18. #include "common.h"
  19. //implements the following miniport functions:
  20. //non paged
  21. //EHCI_OpenControlEndpoint
  22. //EHCI_InterruptTransfer
  23. //EHCI_OpenControlEndpoint
  24. //EHCI_InitializeTD
  25. //EHCI_InitializeQH
  26. VOID
  27. EHCI_EnableAsyncList(
  28. PDEVICE_DATA DeviceData
  29. )
  30. /*++
  31. Routine Description:
  32. Arguments:
  33. Return Value:
  34. --*/
  35. {
  36. PHC_OPERATIONAL_REGISTER hcOp;
  37. USBCMD cmd;
  38. hcOp = DeviceData->OperationalRegisters;
  39. cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
  40. cmd.AsyncScheduleEnable = 1;
  41. WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul,
  42. cmd.ul);
  43. LOGENTRY(DeviceData, G, '_enA', cmd.ul, 0, 0);
  44. }
  45. VOID
  46. EHCI_DisableAsyncList(
  47. PDEVICE_DATA DeviceData
  48. )
  49. /*++
  50. Routine Description:
  51. Arguments:
  52. Return Value:
  53. --*/
  54. {
  55. PHC_OPERATIONAL_REGISTER hcOp;
  56. USBCMD cmd;
  57. USBSTS sts;
  58. hcOp = DeviceData->OperationalRegisters;
  59. cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
  60. cmd.AsyncScheduleEnable = 0;
  61. WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul,
  62. cmd.ul);
  63. // Note this just requests the async schedule to disable
  64. // it is not a synchronous function, the list may be running
  65. // on return from this function. We synchronize with the real
  66. // status in the flush function.
  67. //
  68. // The reason is that this function is used to optimize perf
  69. // by turning off the async list when no xfers are availble.
  70. // We don't want to block the diver waititing for the list to
  71. // disable.
  72. LOGENTRY(DeviceData, G, '_dsL', cmd.ul, 0, 0);
  73. }
  74. VOID
  75. EHCI_LinkTransferToQueue(
  76. PDEVICE_DATA DeviceData,
  77. PENDPOINT_DATA EndpointData,
  78. PHCD_TRANSFER_DESCRIPTOR FirstTd
  79. )
  80. /*++
  81. Routine Description:
  82. Arguments:
  83. Return Value:
  84. --*/
  85. {
  86. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  87. BOOLEAN syncWithHw;
  88. qh = EndpointData->QueueHead;
  89. // now link the transfers to the queue.
  90. // Two cases to handle:
  91. //
  92. // case 1: HeadP is pointing to dummy, no transfer
  93. // case 2: HeadP points to possibly active transfer
  94. LOGENTRY(DeviceData, G, '_L2Q', qh, EndpointData, EndpointData->HcdHeadP);
  95. syncWithHw = EHCI_HardwarePresent(DeviceData, FALSE);
  96. EHCI_ASSERT(DeviceData, EndpointData->HcdHeadP != NULL);
  97. if (EndpointData->HcdHeadP == EndpointData->DummyTd) {
  98. // The hardware will be accessing the dummy QH
  99. // link it in
  100. if (syncWithHw) {
  101. EHCI_LockQueueHead(DeviceData,
  102. qh,
  103. EndpointData->Parameters.TransferType);
  104. }
  105. qh->HwQH.CurrentTD.HwAddress = EndpointData->QhChkPhys;
  106. LOGENTRY(DeviceData, G, '_L21', qh, EndpointData, 0);
  107. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress =
  108. FirstTd->HwTD.AltNext_qTD.HwAddress;
  109. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress =
  110. FirstTd->PhysicalAddress;
  111. qh->HwQH.Overlay.qTD.Token.BytesToTransfer = 0;
  112. qh->HwQH.Overlay.qTD.Token.Active = 0;
  113. qh->HwQH.Overlay.qTD.Token.Halted = 0;
  114. if (syncWithHw) {
  115. EHCI_UnlockQueueHead(DeviceData,
  116. qh);
  117. }
  118. EndpointData->HcdHeadP = FirstTd;
  119. } else {
  120. PHCD_TRANSFER_DESCRIPTOR td, lastTd;
  121. PTRANSFER_CONTEXT transfer, tmp;
  122. ULONG i, active;
  123. // new transfer already points to
  124. // dummyTd
  125. // walk the transfer list to the last td
  126. lastTd = td = EndpointData->HcdHeadP;
  127. ASSERT_TD(DeviceData, td);
  128. while (td != EndpointData->DummyTd) {
  129. lastTd = td;
  130. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  131. LOGENTRY(DeviceData, G, '_nx2', qh, td, 0);
  132. ASSERT_TD(DeviceData, td);
  133. }
  134. // note last td should not be dummy, if dummy td were
  135. // head we would not be in this case
  136. EHCI_ASSERT(DeviceData, lastTd != EndpointData->DummyTd);
  137. ASSERT_TD(DeviceData, lastTd);
  138. LOGENTRY(DeviceData, G, '_lst', qh, lastTd, 0);
  139. transfer = TRANSFER_CONTEXT_PTR(lastTd->TransferContext);
  140. // note that we cannot lock the queue head here since
  141. // that might screw up any split transactions we have
  142. // instead we use a write loop to take care of any
  143. // race conditions caused by us accessing the overlay
  144. // concurrently with the controller
  145. // fixup the alt_next pointers in the TDs of the
  146. // last transfer
  147. for (i=0; i<EndpointData->TdCount; i++) {
  148. td = &EndpointData->TdList->Td[i];
  149. tmp = TRANSFER_CONTEXT_PTR(td->TransferContext);
  150. if (tmp == transfer) {
  151. SET_ALTNEXT_TD(DeviceData, td, FirstTd);
  152. }
  153. }
  154. // point the last TD at the first TD
  155. SET_NEXT_TD(DeviceData, lastTd, FirstTd);
  156. // now check the overlay, if the last TD is current
  157. // then we need to update the overlay too
  158. LOGENTRY(DeviceData, G, '_ckk', qh->HwQH.CurrentTD.HwAddress,
  159. lastTd, lastTd->PhysicalAddress);
  160. if (qh->HwQH.CurrentTD.HwAddress == lastTd->PhysicalAddress) {
  161. LOGENTRY(DeviceData, G, '_upo', qh->HwQH.CurrentTD.HwAddress,
  162. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress,
  163. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress);
  164. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress =
  165. FirstTd->PhysicalAddress;
  166. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress =
  167. EHCI_TERMINATE_BIT;
  168. }
  169. }
  170. }
  171. PHCD_QUEUEHEAD_DESCRIPTOR
  172. EHCI_InitializeQH(
  173. PDEVICE_DATA DeviceData,
  174. PENDPOINT_DATA EndpointData,
  175. PHCD_QUEUEHEAD_DESCRIPTOR Qh,
  176. HW_32BIT_PHYSICAL_ADDRESS HwPhysAddress
  177. )
  178. /*++
  179. Routine Description:
  180. Initialize an QH for inserting in to the
  181. schedule
  182. returns a ptr to the QH passed in
  183. Arguments:
  184. --*/
  185. {
  186. RtlZeroMemory(Qh, sizeof(*Qh));
  187. // make double sure we have the prober alignment
  188. // on the TD structures
  189. EHCI_ASSERT(DeviceData, (HwPhysAddress & HW_LINK_FLAGS_MASK) == 0);
  190. Qh->PhysicalAddress = HwPhysAddress;
  191. ENDPOINT_DATA_PTR(Qh->EndpointData) = EndpointData;
  192. Qh->Sig = SIG_HCD_QH;
  193. // init the hw descriptor
  194. Qh->HwQH.EpChars.DeviceAddress = EndpointData->Parameters.DeviceAddress;
  195. Qh->HwQH.EpChars.EndpointNumber = EndpointData->Parameters.EndpointAddress;
  196. switch (EndpointData->Parameters.DeviceSpeed) {
  197. case LowSpeed:
  198. Qh->HwQH.EpChars.EndpointSpeed = HcEPCHAR_LowSpeed;
  199. LOGENTRY(DeviceData, G, '_iLS', EndpointData, 0, 0);
  200. break;
  201. case FullSpeed:
  202. Qh->HwQH.EpChars.EndpointSpeed = HcEPCHAR_FullSpeed;
  203. LOGENTRY(DeviceData, G, '_iFS', EndpointData, 0, 0);
  204. break;
  205. case HighSpeed:
  206. Qh->HwQH.EpChars.EndpointSpeed = HcEPCHAR_HighSpeed;
  207. LOGENTRY(DeviceData, G, '_iHS', EndpointData, 0, 0);
  208. break;
  209. default:
  210. USBPORT_BUGCHECK(DeviceData);
  211. }
  212. Qh->HwQH.EpChars.MaximumPacketLength =
  213. EndpointData->Parameters.MaxPacketSize;
  214. Qh->HwQH.EpCaps.HighBWPipeMultiplier = 1;
  215. if (EndpointData->Parameters.DeviceSpeed == HcEPCHAR_HighSpeed) {
  216. Qh->HwQH.EpCaps.HubAddress = 0;
  217. Qh->HwQH.EpCaps.PortNumber = 0;
  218. } else {
  219. Qh->HwQH.EpCaps.HubAddress =
  220. EndpointData->Parameters.TtDeviceAddress;
  221. Qh->HwQH.EpCaps.PortNumber =
  222. EndpointData->Parameters.TtPortNumber;
  223. if (EndpointData->Parameters.TransferType == Control) {
  224. Qh->HwQH.EpChars.ControlEndpointFlag = 1;
  225. }
  226. LOGENTRY(DeviceData, G, '_iTT',
  227. EndpointData->Parameters.TtPortNumber,
  228. EndpointData->Parameters.TtDeviceAddress,
  229. Qh->HwQH.EpChars.ControlEndpointFlag);
  230. }
  231. // init the overlay are such that we are in the 'advance queue'
  232. // state with the next queue Tds pointing to terminate links
  233. Qh->HwQH.Overlay.qTD.Next_qTD.HwAddress = EHCI_TERMINATE_BIT;
  234. Qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress = EHCI_TERMINATE_BIT;
  235. Qh->HwQH.Overlay.qTD.Token.Active = 0;
  236. Qh->HwQH.Overlay.qTD.Token.Halted = 0;
  237. return Qh;
  238. }
  239. PHCD_TRANSFER_DESCRIPTOR
  240. EHCI_InitializeTD(
  241. PDEVICE_DATA DeviceData,
  242. PENDPOINT_DATA EndpointData,
  243. PHCD_TRANSFER_DESCRIPTOR Td,
  244. HW_32BIT_PHYSICAL_ADDRESS HwPhysAddress
  245. )
  246. /*++
  247. Routine Description:
  248. Initialize an ED for insertin in to the
  249. schedule
  250. returns a ptr to the ED passed in
  251. Arguments:
  252. --*/
  253. {
  254. RtlZeroMemory(Td, sizeof(*Td));
  255. // make double sure we have the prober alignment
  256. // on the TD structures
  257. EHCI_ASSERT(DeviceData, (HwPhysAddress & HW_LINK_FLAGS_MASK) == 0);
  258. Td->PhysicalAddress = HwPhysAddress;
  259. ENDPOINT_DATA_PTR(Td->EndpointData) = EndpointData;
  260. Td->Sig = SIG_HCD_TD;
  261. TRANSFER_CONTEXT_PTR(Td->TransferContext) = FREE_TD_CONTEXT;
  262. return Td;
  263. }
  264. USB_MINIPORT_STATUS
  265. EHCI_ControlTransfer(
  266. PDEVICE_DATA DeviceData,
  267. PENDPOINT_DATA EndpointData,
  268. PTRANSFER_PARAMETERS TransferParameters,
  269. PTRANSFER_CONTEXT TransferContext,
  270. PTRANSFER_SG_LIST TransferSGList
  271. )
  272. /*++
  273. Routine Description:
  274. Initialize a control transfer
  275. NOTES:
  276. HW pointers nextTD and AltNextTD are shadowed in
  277. NextHcdTD and AltNextHcdTD.
  278. Arguments:
  279. --*/
  280. {
  281. PHCD_TRANSFER_DESCRIPTOR prevTd, td, setupTd, statusTd;
  282. ULONG lengthMapped, dataTDCount = 0;
  283. ULONG nextToggle;
  284. // we can do any control transfer with six TDs
  285. if (EndpointData->FreeTds < 6) {
  286. return USBMP_STATUS_BUSY;
  287. }
  288. EndpointData->PendingTransfers++;
  289. DeviceData->PendingControlAndBulk++;
  290. nextToggle = HcTOK_Toggle1;
  291. // we have enough tds, program the transfer
  292. //
  293. // first prepare a TD for the setup packet
  294. //
  295. LOGENTRY(DeviceData, G, '_CTR', EndpointData, TransferParameters, 0);
  296. //
  297. // allocate setup stage
  298. //
  299. TransferContext->PendingTds++;
  300. setupTd = EHCI_ALLOC_TD(DeviceData, EndpointData);
  301. if (!setupTd) {
  302. goto EHCI_ControlTransferNoTds;
  303. }
  304. INITIALIZE_TD_FOR_TRANSFER(setupTd, TransferContext);
  305. //
  306. // Move setup data into TD (8 chars long)
  307. //
  308. RtlCopyMemory(&setupTd->Packet[0],
  309. &TransferParameters->SetupPacket[0],
  310. 8);
  311. // this will set the offset and phys address bits at
  312. // the same time
  313. setupTd->HwTD.BufferPage[0].ul = (ULONG)(((PCHAR) &setupTd->Packet[0])
  314. - ((PCHAR) &setupTd->HwTD)) + setupTd->PhysicalAddress;
  315. setupTd->HwTD.Token.BytesToTransfer = 8;
  316. setupTd->HwTD.Token.Pid = HcTOK_Setup;
  317. setupTd->HwTD.Token.DataToggle = HcTOK_Toggle0;
  318. setupTd->HwTD.Token.Active = 1;
  319. LOGENTRY(DeviceData,
  320. G, '_set',
  321. setupTd,
  322. *((PLONG) &TransferParameters->SetupPacket[0]),
  323. *((PLONG) &TransferParameters->SetupPacket[4]));
  324. // allocate the status phase TD now so we can
  325. // point the data TDs to it
  326. TransferContext->PendingTds++;
  327. statusTd = EHCI_ALLOC_TD(DeviceData, EndpointData);
  328. if (!statusTd) {
  329. goto EHCI_ControlTransferNoTds;
  330. }
  331. INITIALIZE_TD_FOR_TRANSFER(statusTd, TransferContext);
  332. // point setup to status
  333. SET_ALTNEXT_TD(DeviceData, setupTd, statusTd);
  334. //
  335. // now setup the data phase
  336. //
  337. td = prevTd = setupTd;
  338. lengthMapped = 0;
  339. while (lengthMapped < TransferParameters->TransferBufferLength) {
  340. //
  341. // fields for data TD
  342. //
  343. td = EHCI_ALLOC_TD(DeviceData, EndpointData);
  344. if (!td) {
  345. goto EHCI_ControlTransferNoTds;
  346. }
  347. INITIALIZE_TD_FOR_TRANSFER(td, TransferContext);
  348. dataTDCount++;
  349. TransferContext->PendingTds++;
  350. SET_NEXT_TD(DeviceData, prevTd, td);
  351. // use direction specified in transfer
  352. if (TEST_FLAG(TransferParameters->TransferFlags,
  353. USBD_TRANSFER_DIRECTION_IN)) {
  354. td->HwTD.Token.Pid = HcTOK_In;
  355. } else {
  356. td->HwTD.Token.Pid = HcTOK_Out;
  357. }
  358. td->HwTD.Token.DataToggle = nextToggle;
  359. td->HwTD.Token.Active = 1;
  360. SET_ALTNEXT_TD(DeviceData, td, statusTd);
  361. LOGENTRY(DeviceData,
  362. G, '_dta', td, lengthMapped,
  363. TransferParameters->TransferBufferLength);
  364. lengthMapped =
  365. EHCI_MapAsyncTransferToTd(DeviceData,
  366. EndpointData->Parameters.MaxPacketSize,
  367. lengthMapped,
  368. &nextToggle,
  369. TransferContext,
  370. td,
  371. TransferSGList);
  372. // calculate next data toggle
  373. // if number of packets is odd the nextToggle is 0
  374. // otherwise it is 1
  375. prevTd = td;
  376. }
  377. // last td prepared points to status
  378. SET_NEXT_TD(DeviceData, td, statusTd);
  379. //
  380. // now do the status phase
  381. //
  382. LOGENTRY(DeviceData, G, '_sta', statusTd, 0, dataTDCount);
  383. // do the status phase
  384. // no buffer
  385. statusTd->HwTD.BufferPage[0].ul = 0;
  386. statusTd->HwTD.Token.BytesToTransfer = 0;
  387. statusTd->TransferLength = 0;
  388. // status stage is always toggle 1
  389. statusTd->HwTD.Token.DataToggle = HcTOK_Toggle1;
  390. statusTd->HwTD.Token.Active = 1;
  391. statusTd->HwTD.Token.InterruptOnComplete = 1;
  392. // status phase is opposite data dirrection
  393. if (TEST_FLAG(TransferParameters->TransferFlags, USBD_TRANSFER_DIRECTION_IN)) {
  394. statusTd->HwTD.Token.Pid = HcTOK_Out;
  395. } else {
  396. statusTd->HwTD.Token.Pid = HcTOK_In;
  397. }
  398. // put the request on the hardware queue
  399. LOGENTRY(DeviceData, G,
  400. '_Tal', TransferContext->PendingTds, td->PhysicalAddress, td);
  401. // td points to last TD in this transfer, point it at the dummy
  402. SET_NEXT_TD(DeviceData, statusTd, EndpointData->DummyTd);
  403. // set the active bit in the setup Phase TD, this will
  404. // activate the transfer
  405. PCI_TRIGGER(DeviceData->OperationalRegisters);
  406. // tell the hc we have control transfers available
  407. // do this vefore we link in because we will try
  408. // to sync with the hardware
  409. EHCI_EnableAsyncList(DeviceData);
  410. EHCI_LinkTransferToQueue(DeviceData,
  411. EndpointData,
  412. setupTd);
  413. ASSERT_DUMMY_TD(DeviceData, EndpointData->DummyTd);
  414. return USBMP_STATUS_SUCCESS;
  415. EHCI_ControlTransferNoTds:
  416. // Should never get here!
  417. USBPORT_BUGCHECK(DeviceData);
  418. return USBMP_STATUS_BUSY;
  419. }
  420. USB_MINIPORT_STATUS
  421. EHCI_BulkTransfer(
  422. PDEVICE_DATA DeviceData,
  423. PENDPOINT_DATA EndpointData,
  424. PTRANSFER_PARAMETERS TransferUrb,
  425. PTRANSFER_CONTEXT TransferContext,
  426. PTRANSFER_SG_LIST TransferSGList
  427. )
  428. {
  429. PHCD_TRANSFER_DESCRIPTOR firstTd, prevTd, td, tailTd;
  430. ULONG lengthMapped;
  431. ULONG need;
  432. // figure out how many TDs we will need
  433. need = TransferUrb->TransferBufferLength/(16*1024)+1;
  434. if (need > EndpointData->FreeTds) {
  435. LOGENTRY(DeviceData, G, '_BBS', EndpointData, TransferUrb, 0);
  436. return USBMP_STATUS_BUSY;
  437. }
  438. EndpointData->PendingTransfers++;
  439. DeviceData->PendingControlAndBulk++;
  440. // we have enough tds, program the transfer
  441. LOGENTRY(DeviceData, G, '_BIT', EndpointData, TransferUrb, 0);
  442. lengthMapped = 0;
  443. prevTd = NULL;
  444. while (lengthMapped < TransferUrb->TransferBufferLength) {
  445. TransferContext->PendingTds++;
  446. td = EHCI_ALLOC_TD(DeviceData, EndpointData);
  447. INITIALIZE_TD_FOR_TRANSFER(td, TransferContext);
  448. if (TransferContext->PendingTds == 1) {
  449. firstTd = td;
  450. } else {
  451. SET_NEXT_TD(DeviceData, prevTd, td);
  452. }
  453. SET_ALTNEXT_TD(DeviceData, td, EndpointData->DummyTd);
  454. //
  455. // fields for data TD
  456. //
  457. td->HwTD.Token.InterruptOnComplete = 1;
  458. // use direction specified in transfer
  459. if (TEST_FLAG(TransferUrb->TransferFlags, USBD_TRANSFER_DIRECTION_IN)) {
  460. td->HwTD.Token.Pid = HcTOK_In;
  461. } else {
  462. td->HwTD.Token.Pid = HcTOK_Out;
  463. }
  464. td->HwTD.Token.DataToggle = HcTOK_Toggle1;
  465. td->HwTD.Token.Active = 1;
  466. LOGENTRY(DeviceData,
  467. G, '_dta', td, lengthMapped, TransferUrb->TransferBufferLength);
  468. lengthMapped =
  469. EHCI_MapAsyncTransferToTd(DeviceData,
  470. EndpointData->Parameters.MaxPacketSize,
  471. lengthMapped,
  472. NULL,
  473. TransferContext,
  474. td,
  475. TransferSGList);
  476. prevTd = td;
  477. }
  478. // special case the zero length transfer
  479. if (TransferUrb->TransferBufferLength == 0) {
  480. TEST_TRAP();
  481. TransferContext->PendingTds++;
  482. td = EHCI_ALLOC_TD(DeviceData, EndpointData);
  483. INITIALIZE_TD_FOR_TRANSFER(td, TransferContext);
  484. EHCI_ASSERT(DeviceData, TransferContext->PendingTds == 1);
  485. firstTd = td;
  486. SET_ALTNEXT_TD(DeviceData, td, EndpointData->DummyTd);
  487. td->HwTD.Token.InterruptOnComplete = 1;
  488. // use direction specified in transfer
  489. if (TEST_FLAG(TransferUrb->TransferFlags, USBD_TRANSFER_DIRECTION_IN)) {
  490. td->HwTD.Token.Pid = HcTOK_In;
  491. } else {
  492. td->HwTD.Token.Pid = HcTOK_Out;
  493. }
  494. td->HwTD.Token.DataToggle = HcTOK_Toggle1;
  495. td->HwTD.Token.Active = 1;
  496. // point to a dummy buffer
  497. td->HwTD.BufferPage[0].ul =
  498. td->PhysicalAddress;
  499. td->HwTD.Token.BytesToTransfer =
  500. 0;
  501. td->TransferLength = 0;
  502. }
  503. // td points to last TD in this transfer, point it at the dummy
  504. SET_NEXT_TD(DeviceData, td, EndpointData->DummyTd);
  505. // put the request on the hardware queue
  506. LOGENTRY(DeviceData, G,
  507. '_Tal', TransferContext->PendingTds, td->PhysicalAddress, td);
  508. LOGENTRY(DeviceData, G,
  509. '_ftd', 0, 0, firstTd);
  510. // we now have a complete setup of TDs representing this transfer
  511. // (Next) firstTd(1)->{td}(2)->{td}(3)->td(4)->dummyTd(tbit)
  512. // (AltNext) all point to dummyTd (tbit)
  513. //TEST_TRAP();
  514. // tell the hc we have control transfers available
  515. EHCI_EnableAsyncList(DeviceData);
  516. EHCI_LinkTransferToQueue(DeviceData,
  517. EndpointData,
  518. firstTd);
  519. ASSERT_DUMMY_TD(DeviceData, EndpointData->DummyTd);
  520. return USBMP_STATUS_SUCCESS;
  521. }
  522. USB_MINIPORT_STATUS
  523. EHCI_OpenBulkOrControlEndpoint(
  524. PDEVICE_DATA DeviceData,
  525. BOOLEAN Control,
  526. PENDPOINT_PARAMETERS EndpointParameters,
  527. PENDPOINT_DATA EndpointData
  528. )
  529. /*++
  530. Routine Description:
  531. Arguments:
  532. Return Value:
  533. --*/
  534. {
  535. PUCHAR buffer;
  536. HW_32BIT_PHYSICAL_ADDRESS phys, qhPhys;
  537. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  538. ULONG i;
  539. ULONG tdCount, bytes;
  540. PHCD_TRANSFER_DESCRIPTOR dummyTd;
  541. LOGENTRY(DeviceData, G, '_opC', 0, 0, EndpointParameters);
  542. InitializeListHead(&EndpointData->DoneTdList);
  543. buffer = EndpointParameters->CommonBufferVa;
  544. phys = EndpointParameters->CommonBufferPhys;
  545. // how much did we get
  546. bytes = EndpointParameters->CommonBufferBytes;
  547. // 256 byte block used to check for overlay sync
  548. // problems
  549. EndpointData->QhChkPhys = phys;
  550. EndpointData->QhChk = buffer;
  551. RtlZeroMemory(buffer, 256);
  552. phys += 256;
  553. buffer += 256;
  554. bytes -= 256;
  555. // make the Ed
  556. qh = (PHCD_QUEUEHEAD_DESCRIPTOR) buffer;
  557. qhPhys = phys;
  558. // how much did we get
  559. phys += sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
  560. buffer += sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
  561. bytes -= sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
  562. tdCount = bytes/sizeof(HCD_TRANSFER_DESCRIPTOR);
  563. EHCI_ASSERT(DeviceData, tdCount >= TDS_PER_CONTROL_ENDPOINT);
  564. if (EndpointParameters->TransferType == Control) {
  565. SET_FLAG(EndpointData->Flags, EHCI_EDFLAG_NOHALT);
  566. }
  567. EndpointData->TdList = (PHCD_TD_LIST) buffer;
  568. EndpointData->TdCount = tdCount;
  569. for (i=0; i<tdCount; i++) {
  570. EHCI_InitializeTD(DeviceData,
  571. EndpointData,
  572. &EndpointData->TdList->Td[i],
  573. phys);
  574. phys += sizeof(HCD_TRANSFER_DESCRIPTOR);
  575. }
  576. EndpointData->FreeTds = tdCount;
  577. EndpointData->QueueHead =
  578. EHCI_InitializeQH(DeviceData,
  579. EndpointData,
  580. qh,
  581. qhPhys);
  582. if (Control) {
  583. // use data toggle in the TDs for control
  584. qh->HwQH.EpChars.DataToggleControl = HcEPCHAR_Toggle_From_qTD;
  585. EHCI_ASSERT(DeviceData, tdCount >= TDS_PER_CONTROL_ENDPOINT);
  586. EndpointData->HcdHeadP = NULL;
  587. } else {
  588. PHCD_TRANSFER_DESCRIPTOR dummyTd;
  589. qh->HwQH.EpChars.DataToggleControl = HcEPCHAR_Ignore_Toggle;
  590. EHCI_ASSERT(DeviceData, tdCount >= TDS_PER_BULK_ENDPOINT);
  591. //qh->HwQH.EpChars.NakReloadCount = 4;
  592. }
  593. // allocate a dummy TD for short tranfsers
  594. // the dummy TD is usd to mark the end of the cuurent transfer
  595. //
  596. dummyTd = EHCI_ALLOC_TD(DeviceData, EndpointData);
  597. dummyTd->HwTD.Next_qTD.HwAddress = EHCI_TERMINATE_BIT;
  598. TRANSFER_DESCRIPTOR_PTR(dummyTd->NextHcdTD) = NULL;
  599. dummyTd->HwTD.AltNext_qTD.HwAddress = EHCI_TERMINATE_BIT;
  600. TRANSFER_DESCRIPTOR_PTR(dummyTd->AltNextHcdTD) = NULL;
  601. dummyTd->HwTD.Token.Active = 0;
  602. SET_FLAG(dummyTd->Flags, TD_FLAG_DUMMY);
  603. EndpointData->DummyTd = dummyTd;
  604. EndpointData->HcdHeadP = dummyTd;
  605. // endpoint is not active, set up the overlay
  606. // so that the currentTD is the Dummy
  607. qh->HwQH.CurrentTD.HwAddress = dummyTd->PhysicalAddress;
  608. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress = EHCI_TERMINATE_BIT;
  609. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress = EHCI_TERMINATE_BIT;
  610. qh->HwQH.Overlay.qTD.Token.BytesToTransfer = 0;
  611. qh->HwQH.Overlay.qTD.Token.Active = 0;
  612. // we now have an inactive QueueHead and a Dummy
  613. // tail TD
  614. return USBMP_STATUS_SUCCESS;
  615. }
  616. VOID
  617. EHCI_InsertQueueHeadInAsyncList(
  618. PDEVICE_DATA DeviceData,
  619. PHCD_QUEUEHEAD_DESCRIPTOR Qh
  620. )
  621. /*++
  622. Routine Description:
  623. Insert an aync endpoint (queue head)
  624. into the HW list
  625. Arguments:
  626. --*/
  627. {
  628. PHCD_QUEUEHEAD_DESCRIPTOR asyncQh, nextQh;
  629. HW_LINK_POINTER newLink;
  630. asyncQh = DeviceData->AsyncQueueHead;
  631. LOGENTRY(DeviceData, G, '_Ain', 0, Qh, asyncQh);
  632. EHCI_ASSERT(DeviceData, !TEST_FLAG(Qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE));
  633. // ASYNC QUEUE looks like this:
  634. //
  635. //
  636. // |- we insert here
  637. //|static QH|<->|xfer QH|<->|xfer QH|<->
  638. // | |
  639. // ---------------<->--------------
  640. // link new qh to the current 'head' ie
  641. // first transfer QH
  642. nextQh = QH_DESCRIPTOR_PTR(asyncQh->NextQh);
  643. Qh->HwQH.HLink.HwAddress =
  644. asyncQh->HwQH.HLink.HwAddress;
  645. QH_DESCRIPTOR_PTR(Qh->NextQh) = nextQh;
  646. QH_DESCRIPTOR_PTR(Qh->PrevQh) = asyncQh;
  647. QH_DESCRIPTOR_PTR(nextQh->PrevQh) = Qh;
  648. // put the new qh at the head of the queue
  649. newLink.HwAddress = Qh->PhysicalAddress;
  650. SET_QH(newLink.HwAddress);
  651. asyncQh->HwQH.HLink.HwAddress = newLink.HwAddress;
  652. QH_DESCRIPTOR_PTR(asyncQh->NextQh) = Qh;
  653. SET_FLAG(Qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE);
  654. }
  655. VOID
  656. EHCI_RemoveQueueHeadFromAsyncList(
  657. PDEVICE_DATA DeviceData,
  658. PHCD_QUEUEHEAD_DESCRIPTOR Qh
  659. )
  660. /*++
  661. Routine Description:
  662. Remove a aync endpoint (queue head)
  663. into the HW list
  664. Arguments:
  665. --*/
  666. {
  667. PHCD_QUEUEHEAD_DESCRIPTOR nextQh, prevQh, asyncQh;
  668. HW_LINK_POINTER newLink;
  669. HW_LINK_POINTER asyncHwQh;
  670. HW_32BIT_PHYSICAL_ADDRESS tmp;
  671. PHC_OPERATIONAL_REGISTER hcOp;
  672. hcOp = DeviceData->OperationalRegisters;
  673. LOGENTRY(DeviceData, G, '_Arm', Qh, 0, 0);
  674. // if already removed bail
  675. if (!TEST_FLAG(Qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE)) {
  676. return;
  677. }
  678. nextQh = QH_DESCRIPTOR_PTR(Qh->NextQh);
  679. prevQh = QH_DESCRIPTOR_PTR(Qh->PrevQh);;
  680. // ASYNC QUEUE looks like this:
  681. //
  682. //|static QH|->|xfer QH|->|xfer QH|->
  683. // | |
  684. // -------------<----------------
  685. asyncQh = DeviceData->AsyncQueueHead;
  686. asyncHwQh.HwAddress = asyncQh->PhysicalAddress;
  687. SET_QH(asyncHwQh.HwAddress);
  688. // unlink
  689. LOGENTRY(DeviceData, G, '_ulk', Qh, prevQh, nextQh);
  690. newLink.HwAddress = nextQh->PhysicalAddress;
  691. SET_QH(newLink.HwAddress);
  692. prevQh->HwQH.HLink.HwAddress =
  693. newLink.HwAddress;
  694. QH_DESCRIPTOR_PTR(prevQh->NextQh) = nextQh;
  695. QH_DESCRIPTOR_PTR(nextQh->PrevQh) = prevQh;
  696. // flush the HW cache after an unlink, the scheduke
  697. // should be enabled if we are removeing a QH
  698. EHCI_AsyncCacheFlush(DeviceData);
  699. // we need to update the async list base address reg in case this
  700. // qh is the current qh, if it is we will just replace it with
  701. // the static version
  702. tmp = READ_REGISTER_ULONG(&hcOp->AsyncListAddr);
  703. if (tmp == Qh->PhysicalAddress) {
  704. WRITE_REGISTER_ULONG(&hcOp->AsyncListAddr,
  705. asyncHwQh.HwAddress);
  706. }
  707. CLEAR_FLAG(Qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE);
  708. }
  709. // figure out which sgentry a particular offset in to
  710. // a client buffer falls
  711. #define GET_SG_INDEX(sg, i, offset)\
  712. for((i)=0; (i) < (sg)->SgCount; (i)++) {\
  713. if ((offset) >= (sg)->SgEntry[(i)].StartOffset &&\
  714. (offset) < (sg)->SgEntry[(i)].StartOffset+\
  715. (sg)->SgEntry[(i)].Length) {\
  716. break;\
  717. }\
  718. }
  719. #define GET_SG_OFFSET(sg, i, offset, sgoffset)\
  720. (sgoffset) = (offset) - (sg)->SgEntry[(i)].StartOffset
  721. ULONG
  722. EHCI_MapAsyncTransferToTd(
  723. PDEVICE_DATA DeviceData,
  724. ULONG MaxPacketSize,
  725. ULONG LengthMapped,
  726. PULONG NextToggle,
  727. PTRANSFER_CONTEXT TransferContext,
  728. PHCD_TRANSFER_DESCRIPTOR Td,
  729. PTRANSFER_SG_LIST SgList
  730. )
  731. /*++
  732. Routine Description:
  733. Maps a data buffer to TDs according to EHCI rules
  734. An EHCI TD can cover up to 20k with 5 page crossing.
  735. Note that 20k is the most data a single td can describe
  736. Each sg entry represents one 4k EHCI 'page'
  737. x = pagebreak
  738. c = current ptr
  739. b = buffer start
  740. e = buffer end
  741. {..sg[sgIdx]..}
  742. b...|---
  743. x--c----
  744. [ ]
  745. \
  746. sgOffset
  747. [ ]
  748. \
  749. LengthMapped
  750. Worst case for 20k transfer has 5 page breaks and requires
  751. but 6 bp entries
  752. {..sg0..}{..sg1..}{..sg2..}{..sg3..}{..sg4..}{..sg5..}
  753. | | | | | | |
  754. x--------x--------x--------x--------x--------x--------x
  755. b-------------------------------------------->e
  756. <..bp0..><..bp1..><..bp2..><..bp3..><..bp4..>
  757. case 1: (<6 sg entries remain)
  758. (A)- transfer < 16k, page breaks (if c=b sgOffset = 0)
  759. {..sg0..}{..sg1..}{..sg2..}{..sg3..}{..sg4..}
  760. | | | | | |
  761. x--------x--------x--------x--------x--------x
  762. b------------------------------------>e
  763. <..bp0..><..bp1..><..bp2..><..bp3..><..bp4..>
  764. [.................iTD.................]
  765. (B)- last part of a transfer
  766. {..sgN..}{.sgN+1.}{.sgN+2.}{.sgN+3.}{.sgN+4.}
  767. | | | | | |
  768. x--------x--------x--------x--------x--------x
  769. b.....|.c------------------------------------->e
  770. <..bp0..><..bp1..><..bp2..><..bp3..><..bp4..>
  771. [..................iTD.................]
  772. case 2: (>5 sg entries remain)
  773. (A)- transfer > 20k, first part of a large transfer
  774. {..sg0..}{..sg1..}{..sg2..}{..sg3..}{..sg4..}{..sg5..}
  775. | | | | | | |
  776. x--------x--------x--------x--------x--------x--------x
  777. b-------------------------------------------->e
  778. <..bp0..><..bp1..><..bp2..><..bp3..><..bp4..>
  779. [....................iTD................]
  780. (B)- continuation of a large transfer
  781. Interesting DMA tests (USBTEST):
  782. length, offset - cases hit
  783. Arguments:
  784. Returns:
  785. LengthMapped
  786. --*/
  787. {
  788. ULONG sgIdx, sgOffset, bp, i;
  789. ULONG lengthThisTd;
  790. PTRANSFER_PARAMETERS tp;
  791. // A TD can have up to 5 page crossing. This means we
  792. // can put 5 sg entries in to one TD.
  793. // point to first entry
  794. LOGENTRY(DeviceData, G, '_Mpr', TransferContext,
  795. 0, LengthMapped);
  796. EHCI_ASSERT(DeviceData, SgList->SgCount != 0);
  797. tp = TransferContext->TransferParameters;
  798. GET_SG_INDEX(SgList, sgIdx, LengthMapped);
  799. LOGENTRY(DeviceData, G, '_Mpp', SgList, 0, sgIdx);
  800. EHCI_ASSERT(DeviceData, sgIdx < SgList->SgCount);
  801. if ((SgList->SgCount-sgIdx) < 6) {
  802. // first case, <6 entries left
  803. // ie <20k, we can fit this in
  804. // a single TD.
  805. #if DBG
  806. if (sgIdx == 0) {
  807. // case 1A
  808. // USBT dma test length 4096, offset 0
  809. // will hit this case
  810. // TEST_TRAP();
  811. LOGENTRY(DeviceData, G, '_c1a', SgList, 0, sgIdx);
  812. } else {
  813. // case 1B
  814. // USBT dma test length 8192 offset 512
  815. // will hit this case
  816. LOGENTRY(DeviceData, G, '_c1b', SgList, 0, sgIdx);
  817. //TEST_TRAP();
  818. }
  819. #endif
  820. lengthThisTd = tp->TransferBufferLength - LengthMapped;
  821. // compute offset into this TD
  822. GET_SG_OFFSET(SgList, sgIdx, LengthMapped, sgOffset);
  823. LOGENTRY(DeviceData, G, '_sgO', sgOffset, sgIdx, LengthMapped);
  824. // adjust for the amount of buffer consumed by the
  825. // previous TD
  826. // sets current offset and address at the same time
  827. Td->HwTD.BufferPage[0].ul =
  828. SgList->SgEntry[sgIdx].LogicalAddress.Hw32 + sgOffset;
  829. i = sgIdx+1;
  830. for (bp = 1; bp < 5 && i < SgList->SgCount; bp++,i++) {
  831. Td->HwTD.BufferPage[bp].ul =
  832. SgList->SgEntry[i].LogicalAddress.Hw32;
  833. EHCI_ASSERT(DeviceData, Td->HwTD.BufferPage[bp].CurrentOffset == 0);
  834. }
  835. LOGENTRY(DeviceData, G, '_sg1', Td->HwTD.BufferPage[0].ul, 0,
  836. 0);
  837. } else {
  838. // second case, >=6 entries left
  839. // we will need more than one TD
  840. ULONG adjust, packetCount;
  841. #if DBG
  842. if (sgIdx == 0) {
  843. // case 2A
  844. // USBT dma test length 8192 offset 512
  845. // will hit this case
  846. LOGENTRY(DeviceData, G, '_c2a', SgList, 0, sgIdx);
  847. //TEST_TRAP();
  848. } else {
  849. // case 2B
  850. // USBT dma test length 12288 offset 1
  851. // will hit this case
  852. LOGENTRY(DeviceData, G, '_c2b', SgList, 0, sgIdx);
  853. //TEST_TRAP();
  854. }
  855. #endif
  856. // sg offset is the offset in to the current TD to start
  857. // using
  858. // ie it is the number of bytes already consumed by the
  859. // previous td
  860. GET_SG_OFFSET(SgList, sgIdx, LengthMapped, sgOffset);
  861. LOGENTRY(DeviceData, G, '_sgO', sgOffset, sgIdx, LengthMapped);
  862. #if DBG
  863. if (sgIdx == 0) {
  864. EHCI_ASSERT(DeviceData, sgOffset == 0);
  865. }
  866. #endif
  867. //
  868. // consume the next 4 sgEntries
  869. //
  870. // sets currentOffset at the same time
  871. Td->HwTD.BufferPage[0].ul =
  872. SgList->SgEntry[sgIdx].LogicalAddress.Hw32+sgOffset;
  873. lengthThisTd = EHCI_PAGE_SIZE - Td->HwTD.BufferPage[0].CurrentOffset;
  874. i = sgIdx+1;
  875. for (bp = 1; bp < 5; bp++,i++) {
  876. Td->HwTD.BufferPage[bp].ul =
  877. SgList->SgEntry[i].LogicalAddress.Hw32;
  878. EHCI_ASSERT(DeviceData, Td->HwTD.BufferPage[bp].CurrentOffset == 0);
  879. EHCI_ASSERT(DeviceData, i < SgList->SgCount);
  880. lengthThisTd += EHCI_PAGE_SIZE;
  881. }
  882. // round TD length down to the highest multiple
  883. // of max_packet size
  884. packetCount = lengthThisTd/MaxPacketSize;
  885. LOGENTRY(DeviceData, G, '_sg2', MaxPacketSize, packetCount, lengthThisTd);
  886. adjust = lengthThisTd - packetCount*MaxPacketSize;
  887. if (adjust) {
  888. lengthThisTd-=adjust;
  889. LOGENTRY(DeviceData, G, '_adj', adjust, lengthThisTd, 0);
  890. }
  891. if (NextToggle) {
  892. // calculate next data toggle if requested
  893. // two cases
  894. // case 1: prev NextToggle is 1
  895. // if number of packets is odd the nextToggle is 0
  896. // otherwise it is 1
  897. // case 2: prev NextToggle is 0
  898. // if number of packets is odd the nextToggle is 1
  899. // otherwise it is 0
  900. // so if packet count is even the value remains unchanged
  901. // otherwise we have to toggle it.
  902. if (packetCount % 2) {
  903. // packet count this TD is odd
  904. *NextToggle = (*NextToggle) ? 0 : 1;
  905. }
  906. }
  907. EHCI_ASSERT(DeviceData, lengthThisTd != 0);
  908. EHCI_ASSERT(DeviceData, lengthThisTd >= SgList->SgEntry[sgIdx].Length);
  909. }
  910. LengthMapped += lengthThisTd;
  911. Td->HwTD.Token.BytesToTransfer =
  912. lengthThisTd;
  913. Td->TransferLength = lengthThisTd;
  914. LOGENTRY(DeviceData, G, '_Mp1', LengthMapped, lengthThisTd, Td);
  915. return LengthMapped;
  916. }
  917. VOID
  918. EHCI_SetAsyncEndpointState(
  919. PDEVICE_DATA DeviceData,
  920. PENDPOINT_DATA EndpointData,
  921. MP_ENDPOINT_STATE State
  922. )
  923. /*++
  924. Routine Description:
  925. Arguments:
  926. Return Value:
  927. --*/
  928. {
  929. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  930. PHC_OPERATIONAL_REGISTER hcOp;
  931. ENDPOINT_TRANSFER_TYPE epType;
  932. qh = EndpointData->QueueHead;
  933. epType = EndpointData->Parameters.TransferType;
  934. switch(State) {
  935. case ENDPOINT_ACTIVE:
  936. if (epType == Interrupt) {
  937. // now insert the qh in the schedule
  938. EHCI_InsertQueueHeadInPeriodicList(DeviceData,
  939. EndpointData);
  940. } else {
  941. // put queue head in the schedule
  942. EHCI_InsertQueueHeadInAsyncList(DeviceData,
  943. EndpointData->QueueHead);
  944. }
  945. break;
  946. case ENDPOINT_PAUSE:
  947. // remove queue head from the schedule
  948. if (epType == Interrupt) {
  949. EHCI_RemoveQueueHeadFromPeriodicList(DeviceData,
  950. EndpointData);
  951. } else {
  952. EHCI_RemoveQueueHeadFromAsyncList(DeviceData,
  953. EndpointData->QueueHead);
  954. }
  955. break;
  956. case ENDPOINT_REMOVE:
  957. qh->QhFlags |= EHCI_QH_FLAG_QH_REMOVED;
  958. if (epType == Interrupt) {
  959. EHCI_RemoveQueueHeadFromPeriodicList(DeviceData,
  960. EndpointData);
  961. } else {
  962. EHCI_RemoveQueueHeadFromAsyncList(DeviceData,
  963. EndpointData->QueueHead);
  964. }
  965. // generate a cache flush after we remove so the the HW
  966. // does not have the QH cached
  967. EHCI_InterruptNextSOF(DeviceData);
  968. break;
  969. default:
  970. TEST_TRAP();
  971. }
  972. EndpointData->State = State;
  973. }
  974. MP_ENDPOINT_STATUS
  975. EHCI_GetAsyncEndpointStatus(
  976. PDEVICE_DATA DeviceData,
  977. PENDPOINT_DATA EndpointData
  978. )
  979. /*++
  980. Routine Description:
  981. Arguments:
  982. Return Value:
  983. --*/
  984. {
  985. MP_ENDPOINT_STATUS status;
  986. status = ENDPOINT_STATUS_RUN;
  987. if (TEST_FLAG(EndpointData->Flags, EHCI_EDFLAG_HALTED)) {
  988. status = ENDPOINT_STATUS_HALT;
  989. }
  990. LOGENTRY(DeviceData, G, '_gps', EndpointData, status, 0);
  991. return status;
  992. }
  993. VOID
  994. EHCI_SetAsyncEndpointStatus(
  995. PDEVICE_DATA DeviceData,
  996. PENDPOINT_DATA EndpointData,
  997. MP_ENDPOINT_STATUS Status
  998. )
  999. /*++
  1000. Routine Description:
  1001. Arguments:
  1002. Return Value:
  1003. --*/
  1004. {
  1005. PHC_OPERATIONAL_REGISTER hc;
  1006. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  1007. qh = EndpointData->QueueHead;
  1008. LOGENTRY(DeviceData, G, '_set', EndpointData, Status, 0);
  1009. switch(Status) {
  1010. case ENDPOINT_STATUS_RUN:
  1011. CLEAR_FLAG(EndpointData->Flags, EHCI_EDFLAG_HALTED);
  1012. qh->HwQH.Overlay.qTD.Token.Halted = 0;
  1013. break;
  1014. case ENDPOINT_STATUS_HALT:
  1015. TEST_TRAP();
  1016. break;
  1017. }
  1018. }
  1019. VOID
  1020. EHCI_ProcessDoneAsyncTd(
  1021. PDEVICE_DATA DeviceData,
  1022. PHCD_TRANSFER_DESCRIPTOR Td
  1023. )
  1024. /*++
  1025. Routine Description:
  1026. process a completed TD
  1027. Parameters
  1028. --*/
  1029. {
  1030. PTRANSFER_CONTEXT transferContext;
  1031. PENDPOINT_DATA endpointData;
  1032. PTRANSFER_PARAMETERS tp;
  1033. USBD_STATUS usbdStatus;
  1034. ULONG byteCount;
  1035. transferContext = TRANSFER_CONTEXT_PTR(Td->TransferContext);
  1036. ASSERT_TRANSFER(DeviceData, transferContext);
  1037. tp = transferContext->TransferParameters;
  1038. transferContext->PendingTds--;
  1039. endpointData = transferContext->EndpointData;
  1040. if (TEST_FLAG(Td->Flags, TD_FLAG_SKIP)) {
  1041. LOGENTRY(DeviceData, G, '_Ktd', transferContext,
  1042. 0,
  1043. Td);
  1044. goto free_it;
  1045. }
  1046. // completion status for this TD?
  1047. // since the endpoint halts on error the error
  1048. // bits should have been written back to the TD
  1049. // we use these bits to dermine the error
  1050. if (Td->HwTD.Token.Halted == 1) {
  1051. usbdStatus = EHCI_GetErrorFromTD(DeviceData,
  1052. endpointData,
  1053. Td);
  1054. } else {
  1055. usbdStatus = USBD_STATUS_SUCCESS;
  1056. }
  1057. LOGENTRY(DeviceData, G, '_Dtd', transferContext,
  1058. usbdStatus,
  1059. Td);
  1060. byteCount = Td->TransferLength -
  1061. Td->HwTD.Token.BytesToTransfer;
  1062. LOGENTRY(DeviceData, G, '_tln', byteCount,
  1063. Td->TransferLength, Td->HwTD.Token.BytesToTransfer);
  1064. if (Td->HwTD.Token.Pid != HcTOK_Setup) {
  1065. // data or status phase of a control transfer or a bulk/int
  1066. // data transfer
  1067. LOGENTRY(DeviceData, G, '_Idt', Td, transferContext, byteCount);
  1068. transferContext->BytesTransferred += byteCount;
  1069. }
  1070. // note that we only set transferContext->UsbdStatus
  1071. // if we find a TD with an error this will cause us to
  1072. // record the last TD with an error as the error for
  1073. // the transfer.
  1074. if (USBD_STATUS_SUCCESS != usbdStatus) {
  1075. // map the error to code in USBDI.H
  1076. transferContext->UsbdStatus =
  1077. usbdStatus;
  1078. LOGENTRY(DeviceData, G, '_tER', transferContext->UsbdStatus, 0, 0);
  1079. }
  1080. free_it:
  1081. // mark the TD free
  1082. EHCI_FREE_TD(DeviceData, endpointData, Td);
  1083. if (transferContext->PendingTds == 0) {
  1084. // all TDs for this transfer are done
  1085. // clear the HAVE_TRANSFER flag to indicate
  1086. // we can take another
  1087. endpointData->PendingTransfers--;
  1088. if (endpointData->Parameters.TransferType == Bulk ||
  1089. endpointData->Parameters.TransferType == Control) {
  1090. USBCMD cmd;
  1091. PHC_OPERATIONAL_REGISTER hcOp;
  1092. hcOp = DeviceData->OperationalRegisters;
  1093. DeviceData->PendingControlAndBulk--;
  1094. cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
  1095. if (DeviceData->PendingControlAndBulk == 0 &&
  1096. cmd.IntOnAsyncAdvanceDoorbell == 0 &&
  1097. TEST_FLAG(DeviceData->Flags, EHCI_DD_EN_IDLE_EP_SUPPORT)) {
  1098. EHCI_DisableAsyncList(DeviceData);
  1099. }
  1100. }
  1101. //if (transferContext->BytesTransferred == 0 &&
  1102. // endpointData->Parameters.TransferType == Bulk) {
  1103. // TEST_TRAP();
  1104. //}
  1105. LOGENTRY(DeviceData, G, '_cpt',
  1106. transferContext->UsbdStatus,
  1107. transferContext,
  1108. transferContext->BytesTransferred);
  1109. USBPORT_COMPLETE_TRANSFER(DeviceData,
  1110. endpointData,
  1111. tp,
  1112. transferContext->UsbdStatus,
  1113. transferContext->BytesTransferred);
  1114. }
  1115. }
  1116. USBD_STATUS
  1117. EHCI_GetErrorFromTD(
  1118. PDEVICE_DATA DeviceData,
  1119. PENDPOINT_DATA EndpointData,
  1120. PHCD_TRANSFER_DESCRIPTOR Td
  1121. )
  1122. /*++
  1123. Routine Description:
  1124. Maps the error bits in the TD to a USBD_STATUS code
  1125. Arguments:
  1126. Return Value:
  1127. --*/
  1128. {
  1129. LOGENTRY(DeviceData, G, '_eTD', Td->HwTD.Token.ul, Td, 0);
  1130. EHCI_ASSERT(DeviceData, Td->HwTD.Token.Halted == 1);
  1131. //ULONG MissedMicroFrame:1; // 2
  1132. //ULONG XactErr:1; // 3
  1133. //ULONG BabbleDetected:1; // 4
  1134. //ULONG DataBufferError:1; // 5
  1135. if (Td->HwTD.Token.XactErr) {
  1136. LOGENTRY(DeviceData, G, '_mp1', 0, 0, 0);
  1137. return USBD_STATUS_XACT_ERROR;
  1138. }
  1139. if (Td->HwTD.Token.BabbleDetected) {
  1140. LOGENTRY(DeviceData, G, '_mp2', 0, 0, 0);
  1141. return USBD_STATUS_BABBLE_DETECTED;
  1142. }
  1143. if (Td->HwTD.Token.DataBufferError) {
  1144. LOGENTRY(DeviceData, G, '_mp3', 0, 0, 0);
  1145. return USBD_STATUS_DATA_BUFFER_ERROR;
  1146. }
  1147. if (Td->HwTD.Token.MissedMicroFrame) {
  1148. LOGENTRY(DeviceData, G, '_mp6', 0, 0, 0);
  1149. return USBD_STATUS_XACT_ERROR;
  1150. }
  1151. // no bit set -- treat as a stall
  1152. LOGENTRY(DeviceData, G, '_mp4', 0, 0, 0);
  1153. return USBD_STATUS_STALL_PID;
  1154. }
  1155. VOID
  1156. EHCI_AbortAsyncTransfer(
  1157. PDEVICE_DATA DeviceData,
  1158. PENDPOINT_DATA EndpointData,
  1159. PTRANSFER_CONTEXT AbortTransferContext
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. Called when the endpoint 'needs attention'
  1164. The goal here is to determine which TDs, if any,
  1165. have completed and complete ant associated transfers
  1166. Arguments:
  1167. Return Value:
  1168. --*/
  1169. {
  1170. PHCD_TRANSFER_DESCRIPTOR td, currentTd;
  1171. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  1172. HW_32BIT_PHYSICAL_ADDRESS abortTdPhys;
  1173. PTRANSFER_CONTEXT currentTransfer;
  1174. ULONG byteCount;
  1175. qh = EndpointData->QueueHead;
  1176. // The endpoint should not be in the schedule
  1177. LOGENTRY(DeviceData, G, '_abr', qh, AbortTransferContext, EndpointData->HcdHeadP);
  1178. EHCI_ASSERT(DeviceData, !TEST_FLAG(qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE));
  1179. // one less pending transfer
  1180. EndpointData->PendingTransfers--;
  1181. // our mission now is to remove all TDs associated with
  1182. // this transfer
  1183. // get the last known head, we update the head when we process
  1184. // (AKA poll) the enopoint.
  1185. // walk the list to the tail (dummy) TD
  1186. // find the transfer we wish to cancel...
  1187. // walk the list and find the first TD belonging
  1188. // to this transfer
  1189. // cases to handle
  1190. // case 1 this is the first transfer in the list
  1191. // case 2 this is a middle transfer in the list
  1192. // case 3 this is the last transfer in the list
  1193. // case 4 transfer is not in the list
  1194. td = EndpointData->HcdHeadP;
  1195. ASSERT_TD(DeviceData, td);
  1196. if (TRANSFER_CONTEXT_PTR(td->TransferContext) == AbortTransferContext) {
  1197. // case 1
  1198. byteCount = 0;
  1199. while (td != EndpointData->DummyTd &&
  1200. TRANSFER_CONTEXT_PTR(td->TransferContext) == AbortTransferContext) {
  1201. PHCD_TRANSFER_DESCRIPTOR tmp;
  1202. // see if any data has been transferred
  1203. byteCount += (td->TransferLength -
  1204. td->HwTD.Token.BytesToTransfer);
  1205. tmp = td;
  1206. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1207. EHCI_FREE_TD(DeviceData, EndpointData, tmp)
  1208. }
  1209. if (byteCount) {
  1210. AbortTransferContext->BytesTransferred += byteCount;
  1211. }
  1212. // td now points to the 'next transfer TD'
  1213. // this puts us in the 'advance queue' state
  1214. // ie overlay is !active && !halted, update the
  1215. // overlay area as appropriate.
  1216. //
  1217. // NOTE: the hw is not accessing the qh at this time
  1218. // do not zero the queue head because this will
  1219. // trash the state of the data toggle
  1220. //RtlZeroMemory(&qh->HwQH.Overlay.qTD,
  1221. // sizeof(qh->HwQH.Overlay.qTD));
  1222. // point at the waste area to check for sync problems
  1223. qh->HwQH.CurrentTD.HwAddress = EndpointData->QhChkPhys;
  1224. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress =
  1225. td->HwTD.AltNext_qTD.HwAddress;
  1226. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress =
  1227. td->PhysicalAddress;
  1228. qh->HwQH.Overlay.qTD.Token.BytesToTransfer = 0;
  1229. qh->HwQH.Overlay.qTD.Token.Active = 0;
  1230. qh->HwQH.Overlay.qTD.Token.Halted = 0;
  1231. EndpointData->HcdHeadP = td;
  1232. } else {
  1233. PHCD_TRANSFER_DESCRIPTOR prevTd, nextTd;
  1234. // determine the current transfer in the overlay
  1235. EHCI_ASSERT(DeviceData, qh->HwQH.CurrentTD.HwAddress);
  1236. currentTd = (PHCD_TRANSFER_DESCRIPTOR)
  1237. USBPORT_PHYSICAL_TO_VIRTUAL(qh->HwQH.CurrentTD.HwAddress,
  1238. DeviceData,
  1239. EndpointData);
  1240. currentTransfer =
  1241. TRANSFER_CONTEXT_PTR(currentTd->TransferContext);
  1242. LOGENTRY(DeviceData, G, '_Act', currentTransfer,
  1243. currentTd, EndpointData->HcdHeadP);
  1244. // case 2, 3
  1245. // walk from the head to the first td of the transfer
  1246. // we are interested in.
  1247. prevTd = td = EndpointData->HcdHeadP;
  1248. while (td != NULL) {
  1249. PHCD_TRANSFER_DESCRIPTOR tmp;
  1250. if (TRANSFER_CONTEXT_PTR(td->TransferContext) == AbortTransferContext) {
  1251. break;
  1252. }
  1253. prevTd = td;
  1254. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1255. LOGENTRY(DeviceData, G, '_nxt', prevTd, td, 0);
  1256. }
  1257. LOGENTRY(DeviceData, G, '_atd', 0, td, 0);
  1258. abortTdPhys = td->PhysicalAddress;
  1259. // now walk to the first td of the next transfer, free
  1260. // TDs for this transfer as we go
  1261. while (td != NULL &&
  1262. TRANSFER_CONTEXT_PTR(td->TransferContext) == AbortTransferContext) {
  1263. PHCD_TRANSFER_DESCRIPTOR tmp;
  1264. tmp = td;
  1265. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1266. EHCI_FREE_TD(DeviceData, EndpointData, tmp);
  1267. }
  1268. nextTd = td;
  1269. LOGENTRY(DeviceData, G, '_Apn', prevTd,
  1270. nextTd, abortTdPhys);
  1271. // now link prevTd to nextTd
  1272. if (prevTd == NULL) {
  1273. // case 4 transfer not in the list
  1274. // should this happen?
  1275. TEST_TRAP();
  1276. }
  1277. // next TD might be dummy
  1278. EHCI_ASSERT(DeviceData, nextTd != NULL);
  1279. EHCI_ASSERT(DeviceData, prevTd != NULL);
  1280. //SET_NEXT_AND_ALTNEXT_TD
  1281. SET_NEXT_TD(DeviceData, prevTd, nextTd);
  1282. SET_ALTNEXT_TD(DeviceData, prevTd, nextTd);
  1283. // fixup overlay area as needed,
  1284. // if the aborted transfer was current we want to pick
  1285. // up the next transfer
  1286. if (currentTransfer == AbortTransferContext) {
  1287. LOGENTRY(DeviceData, G, '_At1', currentTransfer, 0, 0);
  1288. // aborted transfer is current, prime the
  1289. // overlay with the next transfer
  1290. // catch HW sync problems
  1291. qh->HwQH.CurrentTD.HwAddress = EndpointData->QhChkPhys;
  1292. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress = nextTd->PhysicalAddress;
  1293. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress = EHCI_TERMINATE_BIT;
  1294. qh->HwQH.Overlay.qTD.Token.BytesToTransfer = 0;
  1295. qh->HwQH.Overlay.qTD.Token.Active = 0;
  1296. // preserve halted bit
  1297. } else if (TRANSFER_CONTEXT_PTR(prevTd->TransferContext) ==
  1298. currentTransfer) {
  1299. // previous transfer was current, make sure the overlay
  1300. // area (current transfer) does not point to a deleted td
  1301. LOGENTRY(DeviceData, G, '_At2', currentTransfer, 0, 0);
  1302. // check overlay
  1303. if (qh->HwQH.Overlay.qTD.Next_qTD.HwAddress == abortTdPhys) {
  1304. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress =
  1305. nextTd->PhysicalAddress;
  1306. }
  1307. if (qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress == abortTdPhys) {
  1308. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress =
  1309. nextTd->PhysicalAddress;
  1310. }
  1311. // correct all TDs for the current transfer
  1312. td = EndpointData->HcdHeadP;
  1313. while (td != NULL) {
  1314. // nextTd is firstTd of the NEXT transfer
  1315. if (TRANSFER_CONTEXT_PTR(td->TransferContext) == currentTransfer) {
  1316. // alt next always points to next transfer
  1317. td->HwTD.AltNext_qTD.HwAddress = nextTd->PhysicalAddress;
  1318. SET_ALTNEXT_TD(DeviceData, td, nextTd);
  1319. }
  1320. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1321. }
  1322. }
  1323. }
  1324. }
  1325. USB_MINIPORT_STATUS
  1326. EHCI_PokeAsyncEndpoint(
  1327. PDEVICE_DATA DeviceData,
  1328. PENDPOINT_PARAMETERS EndpointParameters,
  1329. PENDPOINT_DATA EndpointData
  1330. )
  1331. /*++
  1332. Routine Description:
  1333. Arguments:
  1334. Return Value:
  1335. --*/
  1336. {
  1337. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  1338. qh = EndpointData->QueueHead;
  1339. EHCI_ASSERT(DeviceData, qh != NULL);
  1340. EndpointData->Parameters = *EndpointParameters;
  1341. qh->HwQH.EpChars.DeviceAddress =
  1342. EndpointData->Parameters.DeviceAddress;
  1343. qh->HwQH.EpChars.MaximumPacketLength =
  1344. EndpointData->Parameters.MaxPacketSize;
  1345. qh->HwQH.EpCaps.HubAddress =
  1346. EndpointData->Parameters.TtDeviceAddress;
  1347. return USBMP_STATUS_SUCCESS;
  1348. }
  1349. VOID
  1350. EHCI_LockQueueHead(
  1351. PDEVICE_DATA DeviceData,
  1352. PHCD_QUEUEHEAD_DESCRIPTOR Qh,
  1353. ENDPOINT_TRANSFER_TYPE EpType
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. Synchronously update the overlate area, this involves using the
  1358. doorbell to wait for queue head to flush off the HC hardware
  1359. the caller is responisble for resuming
  1360. Arguments:
  1361. Return Value:
  1362. --*/
  1363. {
  1364. PHC_OPERATIONAL_REGISTER hcOp;
  1365. USBCMD cmd;
  1366. PHCD_QUEUEHEAD_DESCRIPTOR nextQh, prevQh;
  1367. HW_32BIT_PHYSICAL_ADDRESS phys;
  1368. ULONG mf, cmf;
  1369. hcOp = DeviceData->OperationalRegisters;
  1370. LOGENTRY(DeviceData, G, '_LKq', Qh, 0, 0);
  1371. EHCI_ASSERT(DeviceData, !TEST_FLAG(Qh->QhFlags, EHCI_QH_FLAG_UPDATING));
  1372. EHCI_ASSERT(DeviceData, DeviceData->LockQh == NULL);
  1373. SET_FLAG(Qh->QhFlags, EHCI_QH_FLAG_UPDATING);
  1374. nextQh = QH_DESCRIPTOR_PTR(Qh->NextQh);
  1375. prevQh = QH_DESCRIPTOR_PTR(Qh->PrevQh);
  1376. ASSERT(prevQh);
  1377. DeviceData->LockPrevQh = prevQh;
  1378. DeviceData->LockNextQh = nextQh;
  1379. DeviceData->LockQh = Qh;
  1380. if (nextQh) {
  1381. phys = nextQh->PhysicalAddress;
  1382. SET_QH(phys);
  1383. } else {
  1384. phys = 0;
  1385. SET_T_BIT(phys);
  1386. }
  1387. // note that we only mess with the HW nextlinks and this
  1388. // is temporary
  1389. // unlink this queue head
  1390. prevQh->HwQH.HLink.HwAddress = phys;
  1391. mf = READ_REGISTER_ULONG(&hcOp->UsbFrameIndex.ul);
  1392. if (EpType == Interrupt) {
  1393. do {
  1394. cmf = READ_REGISTER_ULONG(&hcOp->UsbFrameIndex.ul);
  1395. } while (cmf == mf);
  1396. } else {
  1397. EHCI_AsyncCacheFlush(DeviceData);
  1398. }
  1399. LOGENTRY(DeviceData, G, '_LKx', Qh, 0, 0);
  1400. }
  1401. VOID
  1402. EHCI_AsyncCacheFlush(
  1403. PDEVICE_DATA DeviceData
  1404. )
  1405. /*++
  1406. Routine Description:
  1407. Synchronously flushes the async controller cache by ringing
  1408. the async doorbell and waiting
  1409. Arguments:
  1410. Return Value:
  1411. --*/
  1412. {
  1413. PHC_OPERATIONAL_REGISTER hcOp;
  1414. USBCMD cmd;
  1415. USBSTS sts;
  1416. hcOp = DeviceData->OperationalRegisters;
  1417. cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
  1418. sts.ul = READ_REGISTER_ULONG(&hcOp->UsbStatus.ul);
  1419. // check the real status of the async list. if disabled
  1420. // we should not need to flush the cache.
  1421. // 0
  1422. if (sts.AsyncScheduleStatus == 0 &&
  1423. cmd.AsyncScheduleEnable == 0) {
  1424. return;
  1425. }
  1426. // 1->0 wait for it to go to 0
  1427. if (sts.AsyncScheduleStatus == 1 &&
  1428. cmd.AsyncScheduleEnable == 0) {
  1429. do {
  1430. sts.ul = READ_REGISTER_ULONG(&hcOp->UsbStatus.ul);
  1431. cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
  1432. } while (sts.AsyncScheduleStatus &&
  1433. cmd.ul != 0xFFFFFFFF &&
  1434. cmd.HostControllerRun);
  1435. return;
  1436. }
  1437. // 0->1 wait for it to enable
  1438. if (sts.AsyncScheduleStatus == 0 &&
  1439. cmd.AsyncScheduleEnable == 1) {
  1440. do {
  1441. sts.ul = READ_REGISTER_ULONG(&hcOp->UsbStatus.ul);
  1442. cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
  1443. } while (!sts.AsyncScheduleStatus &&
  1444. cmd.ul != 0xFFFFFFFF &&
  1445. cmd.HostControllerRun);
  1446. }
  1447. EHCI_ASSERT(DeviceData, cmd.AsyncScheduleEnable == 1);
  1448. EHCI_ASSERT(DeviceData, sts.AsyncScheduleStatus == 1);
  1449. // if not enabled enable it, this would be a bug though
  1450. // cmd.AsyncScheduleEnable = 1;
  1451. // cmd.IntOnAsyncAdvanceDoorbell = 1;
  1452. // WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul,
  1453. // cmd.ul);
  1454. // wait for it.
  1455. cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
  1456. while (cmd.IntOnAsyncAdvanceDoorbell &&
  1457. cmd.HostControllerRun &&
  1458. cmd.ul != 0xFFFFFFFF) {
  1459. KeStallExecutionProcessor(1);
  1460. cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
  1461. }
  1462. }
  1463. VOID
  1464. EHCI_UnlockQueueHead(
  1465. PDEVICE_DATA DeviceData,
  1466. PHCD_QUEUEHEAD_DESCRIPTOR Qh
  1467. )
  1468. /*++
  1469. Routine Description:
  1470. compliment to LockQueueHead, this function reactivates the qh after
  1471. modifications are complete
  1472. Arguments:
  1473. Return Value:
  1474. --*/
  1475. {
  1476. PHCD_QUEUEHEAD_DESCRIPTOR nextQh, prevQh;
  1477. HW_32BIT_PHYSICAL_ADDRESS phys;
  1478. LOGENTRY(DeviceData, G, '_UKq', Qh, 0, 0);
  1479. EHCI_ASSERT(DeviceData, TEST_FLAG(Qh->QhFlags, EHCI_QH_FLAG_UPDATING));
  1480. EHCI_ASSERT(DeviceData, DeviceData->LockQh != NULL);
  1481. EHCI_ASSERT(DeviceData, DeviceData->LockQh == Qh);
  1482. CLEAR_FLAG(Qh->QhFlags, EHCI_QH_FLAG_UPDATING);
  1483. DeviceData->LockQh = NULL;
  1484. prevQh = DeviceData->LockPrevQh;
  1485. phys = Qh->PhysicalAddress;
  1486. SET_QH(phys);
  1487. prevQh->HwQH.HLink.HwAddress = phys;
  1488. LOGENTRY(DeviceData, G, '_UKx', Qh, 0, phys);
  1489. }
  1490. VOID
  1491. EHCI_PollActiveAsyncEndpoint(
  1492. PDEVICE_DATA DeviceData,
  1493. PENDPOINT_DATA EndpointData
  1494. )
  1495. /*++
  1496. Routine Description:
  1497. The queue head is in the running state we will just process
  1498. the TDs that are completed up to 'current' if dummy goes
  1499. current then all TDs will be complete
  1500. Arguments:
  1501. Return Value:
  1502. --*/
  1503. {
  1504. PHCD_TRANSFER_DESCRIPTOR td, currentTd;
  1505. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  1506. HW_32BIT_PHYSICAL_ADDRESS tdPhys, curTdPhys;
  1507. PTRANSFER_CONTEXT transfer;
  1508. ULONG cf = 0;
  1509. BOOLEAN syncWithHw;
  1510. #if DBG
  1511. cf = EHCI_Get32BitFrameNumber(DeviceData);
  1512. #endif
  1513. qh = EndpointData->QueueHead;
  1514. curTdPhys = qh->HwQH.CurrentTD.HwAddress & ~HW_LINK_FLAGS_MASK;
  1515. LOGENTRY(DeviceData, G, '_pol', qh, cf, curTdPhys);
  1516. EHCI_ASSERT(DeviceData, curTdPhys != 0);
  1517. currentTd = (PHCD_TRANSFER_DESCRIPTOR)
  1518. USBPORT_PHYSICAL_TO_VIRTUAL(curTdPhys,
  1519. DeviceData,
  1520. EndpointData);
  1521. // walk the soft list of TDs and complete all TDs
  1522. // up to the currentTD
  1523. // get the last known head
  1524. LOGENTRY(DeviceData, G, '_hd1',
  1525. EndpointData->HcdHeadP,
  1526. 0,
  1527. currentTd);
  1528. if (currentTd == EndpointData->QhChk) {
  1529. // endpoint is transitioning to run a transfer or
  1530. // is pointing at the waste area, do not poll at
  1531. // this time
  1532. LOGENTRY(DeviceData, G, '_pl!', 0, 0, currentTd);
  1533. return;
  1534. }
  1535. // only do HW sync if QH is not in schedule
  1536. syncWithHw = TEST_FLAG(qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE) ?
  1537. TRUE : FALSE;
  1538. // skip sync on hot remove
  1539. if (EHCI_HardwarePresent(DeviceData, FALSE) == FALSE) {
  1540. syncWithHw = FALSE;
  1541. }
  1542. ASSERT_TD(DeviceData, currentTd);
  1543. td = EndpointData->HcdHeadP;
  1544. if (td == currentTd &&
  1545. td != EndpointData->DummyTd) {
  1546. // currentTd is head verify that it is not complete
  1547. if (td->HwTD.Token.Active == 0) {
  1548. PHCD_TRANSFER_DESCRIPTOR tmp;
  1549. //currentTd = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1550. LOGENTRY(DeviceData, G, '_cAT', td, currentTd,
  1551. qh->HwQH.CurrentTD.HwAddress & ~HW_LINK_FLAGS_MASK);
  1552. tmp = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1553. if (tmp &&
  1554. td->HwTD.Next_qTD.HwAddress != tmp->PhysicalAddress) {
  1555. td->HwTD.Next_qTD.HwAddress = tmp->PhysicalAddress;
  1556. }
  1557. tmp = TRANSFER_DESCRIPTOR_PTR(td->AltNextHcdTD);
  1558. if (tmp &&
  1559. td->HwTD.AltNext_qTD.HwAddress != tmp->PhysicalAddress) {
  1560. td->HwTD.AltNext_qTD.HwAddress = tmp->PhysicalAddress;
  1561. }
  1562. if (qh->HwQH.CurrentTD.HwAddress == td->PhysicalAddress &&
  1563. td->HwTD.Token.Active == 0 &&
  1564. (qh->HwQH.Overlay.qTD.Next_qTD.HwAddress !=
  1565. td->HwTD.Next_qTD.HwAddress ||
  1566. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress !=
  1567. td->HwTD.AltNext_qTD.HwAddress)) {
  1568. LOGENTRY(DeviceData, G, '_upp', qh, td, 0);
  1569. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress =
  1570. td->HwTD.Next_qTD.HwAddress;
  1571. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress =
  1572. td->HwTD.AltNext_qTD.HwAddress;
  1573. }
  1574. EHCI_InterruptNextSOF(DeviceData);
  1575. }
  1576. }
  1577. while (td != currentTd) {
  1578. EHCI_ASSERT(DeviceData, !TEST_FLAG(td->Flags, TD_FLAG_DUMMY));
  1579. // TDs between head and current should not be active
  1580. transfer = TRANSFER_CONTEXT_PTR(td->TransferContext);
  1581. LOGENTRY(DeviceData, G, '_dt1', td, 0, transfer);
  1582. if (td->HwTD.Token.Active == 1) {
  1583. // if the TD is active then it must have been
  1584. // skipped due to a short xfer condition
  1585. LOGENTRY(DeviceData, G, '_dtS', td, 0, 0);
  1586. SET_FLAG(td->Flags, TD_FLAG_SKIP);
  1587. }
  1588. SET_FLAG(td->Flags, TD_FLAG_DONE);
  1589. InsertTailList(&EndpointData->DoneTdList,
  1590. &td->DoneLink);
  1591. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1592. }
  1593. // now check current TD if next td is the dummy and this td is
  1594. // not active then we need to bump the current TD to dummy and
  1595. // complete this TD. This will only occur if this is the last TD
  1596. // queued
  1597. // also check if this is a short transfer on the last transfer queued,
  1598. // in this case the AltNextHcdTd will point to dummy and we will need
  1599. // to advance passed the skipped TDs.
  1600. if ((TRANSFER_DESCRIPTOR_PTR(currentTd->NextHcdTD) ==
  1601. EndpointData->DummyTd &&
  1602. currentTd->HwTD.Token.Active == 0) ||
  1603. // or a short packet
  1604. (TRANSFER_DESCRIPTOR_PTR(currentTd->AltNextHcdTD) ==
  1605. EndpointData->DummyTd &&
  1606. currentTd->HwTD.Token.Active == 0 &&
  1607. currentTd->HwTD.Token.BytesToTransfer != 0) ) {
  1608. LOGENTRY(DeviceData, G, '_bmp', currentTd, 0, 0);
  1609. // synchronize with hardware in the event this td
  1610. // has not been completely written back
  1611. // since we are about to trash the overlay area there should
  1612. // be no transfer current, we use the async doorbell to wait
  1613. // for an the async TD to be completely flushed.
  1614. //
  1615. // In the event of a periodic transfer the HW may have prefetched
  1616. // the periodic list so we need to wait for the microframe counter
  1617. // to turn over.
  1618. if (syncWithHw) {
  1619. EHCI_LockQueueHead(DeviceData,
  1620. qh,
  1621. EndpointData->Parameters.TransferType);
  1622. }
  1623. qh->HwQH.CurrentTD.HwAddress = EndpointData->QhChkPhys;
  1624. td = currentTd;
  1625. SET_FLAG(td->Flags, TD_FLAG_DONE);
  1626. InsertTailList(&EndpointData->DoneTdList,
  1627. &td->DoneLink);
  1628. if (td->HwTD.Token.BytesToTransfer != 0 &&
  1629. TRANSFER_DESCRIPTOR_PTR(td->AltNextHcdTD) == EndpointData->DummyTd) {
  1630. // start at first alt TD
  1631. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1632. // short xfer
  1633. while (td != EndpointData->DummyTd) {
  1634. SET_FLAG(td->Flags, TD_FLAG_SKIP);
  1635. InsertTailList(&EndpointData->DoneTdList,
  1636. &td->DoneLink);
  1637. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1638. }
  1639. }
  1640. qh->HwQH.CurrentTD.HwAddress = EndpointData->DummyTd->PhysicalAddress;
  1641. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress = EHCI_TERMINATE_BIT;
  1642. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress = EHCI_TERMINATE_BIT;
  1643. qh->HwQH.Overlay.qTD.Token.BytesToTransfer = 0;
  1644. EndpointData->HcdHeadP = EndpointData->DummyTd;
  1645. if (syncWithHw) {
  1646. EHCI_UnlockQueueHead(DeviceData,
  1647. qh);
  1648. }
  1649. // check for sync problems
  1650. EHCI_QHCHK(DeviceData, EndpointData);
  1651. } else {
  1652. EHCI_ASSERT(DeviceData, td != NULL);
  1653. EndpointData->HcdHeadP = td;
  1654. }
  1655. }
  1656. VOID
  1657. EHCI_PollHaltedAsyncEndpoint(
  1658. PDEVICE_DATA DeviceData,
  1659. PENDPOINT_DATA EndpointData
  1660. )
  1661. /*++
  1662. Routine Description:
  1663. Arguments:
  1664. Return Value:
  1665. --*/
  1666. {
  1667. PHCD_TRANSFER_DESCRIPTOR td, currentTd;
  1668. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  1669. HW_QUEUE_ELEMENT_TD overlay;
  1670. HW_32BIT_PHYSICAL_ADDRESS tdPhys, curTdPhys;
  1671. PTRANSFER_CONTEXT transfer, errTransfer;
  1672. BOOLEAN syncWithHw;
  1673. // we are halted probably due to an error and
  1674. // currentTd should be the offending TD
  1675. qh = EndpointData->QueueHead;
  1676. curTdPhys = qh->HwQH.CurrentTD.HwAddress & ~HW_LINK_FLAGS_MASK;
  1677. LOGENTRY(DeviceData, G, '_plH', qh, 0, curTdPhys);
  1678. EHCI_ASSERT(DeviceData, curTdPhys != 0);
  1679. // only do HW sync if QH is not in schedule
  1680. syncWithHw = TEST_FLAG(qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE) ?
  1681. TRUE : FALSE;
  1682. // skip sync on hot remove
  1683. if (EHCI_HardwarePresent(DeviceData, FALSE) == FALSE) {
  1684. syncWithHw = FALSE;
  1685. }
  1686. currentTd = (PHCD_TRANSFER_DESCRIPTOR)
  1687. USBPORT_PHYSICAL_TO_VIRTUAL(curTdPhys,
  1688. DeviceData,
  1689. EndpointData);
  1690. if (currentTd == EndpointData->QhChk) {
  1691. // endpoint is transitioning to run a transfer or
  1692. // is pointing at the waste area, do not poll at
  1693. // this time
  1694. LOGENTRY(DeviceData, G, '_hl!', 0, 0, currentTd);
  1695. return;
  1696. }
  1697. ASSERT_TD(DeviceData, currentTd);
  1698. // we are halted probably due to an error and
  1699. // currentTd should be the offending TD
  1700. // we should not error on the dummy TD
  1701. EHCI_ASSERT(DeviceData, EndpointData->DummyTd != currentTd);
  1702. // walk the soft list of TDs and complete all TDs
  1703. // up to the currentTD
  1704. td = EndpointData->HcdHeadP;
  1705. LOGENTRY(DeviceData, G, '_hed', 0, 0, td);
  1706. while (td != currentTd) {
  1707. EHCI_ASSERT(DeviceData, !TEST_FLAG(td->Flags, TD_FLAG_DUMMY));
  1708. // TDs between head and current should not be active
  1709. transfer = TRANSFER_CONTEXT_PTR(td->TransferContext);
  1710. LOGENTRY(DeviceData, G, '_dt2', td, 0, transfer);
  1711. if (td->HwTD.Token.Active == 1) {
  1712. // if the TD is active then it must have been
  1713. // skipped due to a short xfer condition
  1714. LOGENTRY(DeviceData, G, '_d2S', td, 0, 0);
  1715. SET_FLAG(td->Flags, TD_FLAG_SKIP);
  1716. }
  1717. SET_FLAG(td->Flags, TD_FLAG_DONE);
  1718. InsertTailList(&EndpointData->DoneTdList,
  1719. &td->DoneLink);
  1720. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1721. }
  1722. // adjust 'currentTd' to be the first TD of the NEXT
  1723. // transfer
  1724. td = currentTd;
  1725. errTransfer = TRANSFER_CONTEXT_PTR(td->TransferContext);
  1726. while (TRANSFER_CONTEXT_PTR(td->TransferContext) == errTransfer) {
  1727. LOGENTRY(DeviceData, G, '_d3D', td, 0, 0);
  1728. if (td->HwTD.Token.Active == 1) {
  1729. // if the TD is active then it must have been
  1730. // skipped due to a short xfer condition
  1731. LOGENTRY(DeviceData, G, '_d3S', td, 0, 0);
  1732. SET_FLAG(td->Flags, TD_FLAG_SKIP);
  1733. }
  1734. SET_FLAG(td->Flags, TD_FLAG_DONE);
  1735. InsertTailList(&EndpointData->DoneTdList,
  1736. &td->DoneLink);
  1737. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  1738. }
  1739. EHCI_ASSERT(DeviceData, td != NULL);
  1740. // td is now first td of next transfer
  1741. EndpointData->HcdHeadP = currentTd = td;
  1742. // now fix up the queue head overlay area such that the
  1743. // next transfer will run
  1744. if (syncWithHw) {
  1745. // sync with the HC hardware
  1746. EHCI_LockQueueHead(DeviceData,
  1747. qh,
  1748. EndpointData->Parameters.TransferType);
  1749. }
  1750. qh->HwQH.CurrentTD.HwAddress = EndpointData->QhChkPhys;
  1751. EHCI_ASSERT(DeviceData, qh->HwQH.Overlay.qTD.Token.Halted);
  1752. // currentTD value should be irrelevent
  1753. // we are !active, halted
  1754. // overlay should be !active !halted when the queue head is reset
  1755. // ie Advance Queue state
  1756. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress = td->PhysicalAddress;
  1757. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress = EHCI_TERMINATE_BIT;
  1758. qh->HwQH.Overlay.qTD.Token.BytesToTransfer = 0;
  1759. if (syncWithHw) {
  1760. // queue head can now be aceesed by HW
  1761. EHCI_UnlockQueueHead(DeviceData,
  1762. qh);
  1763. }
  1764. // if this is a control endpoint the we need to clear the
  1765. // halt condition
  1766. if (TEST_FLAG(EndpointData->Flags, EHCI_EDFLAG_NOHALT)) {
  1767. LOGENTRY(DeviceData, G, '_clH', qh, 0, 0);
  1768. CLEAR_FLAG(EndpointData->Flags, EHCI_EDFLAG_HALTED);
  1769. qh->HwQH.Overlay.qTD.Token.Active = 0;
  1770. qh->HwQH.Overlay.qTD.Token.Halted = 0;
  1771. qh->HwQH.Overlay.qTD.Token.ErrorCounter = 0;
  1772. }
  1773. }
  1774. VOID
  1775. EHCI_PollAsyncEndpoint(
  1776. PDEVICE_DATA DeviceData,
  1777. PENDPOINT_DATA EndpointData
  1778. )
  1779. /*++
  1780. Routine Description:
  1781. Called when the endpoint 'needs attention'
  1782. This is where we poll bulk and interrupt endpoins. BI endpoints
  1783. use a 'dummy' TD to denote the end of the current transfer
  1784. Arguments:
  1785. Return Value:
  1786. --*/
  1787. {
  1788. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  1789. HW_QUEUE_ELEMENT_TD overlay;
  1790. BOOLEAN active, halted;
  1791. PHCD_TRANSFER_DESCRIPTOR td;
  1792. PLIST_ENTRY listEntry;
  1793. ULONG cf = 0;
  1794. EHCI_QHCHK(DeviceData, EndpointData);
  1795. #if DBG
  1796. cf = EHCI_Get32BitFrameNumber(DeviceData);
  1797. #endif
  1798. if (EndpointData->PendingTransfers == 0) {
  1799. // if we have no transfers queued then there is
  1800. // nothing to do
  1801. LOGENTRY(DeviceData, G, '_poN', EndpointData, 0, cf);
  1802. return;
  1803. }
  1804. // get the queue head and a snapshot of the overlay
  1805. qh = EndpointData->QueueHead;
  1806. RtlCopyMemory(&overlay,
  1807. &qh->HwQH.Overlay.qTD,
  1808. sizeof(overlay));
  1809. if (TEST_FLAG(qh->QhFlags, EHCI_QH_FLAG_QH_REMOVED)) {
  1810. // don't check endpoint if qh has been removed
  1811. LOGENTRY(DeviceData, G, '_qRM', EndpointData, 0, cf);
  1812. return;
  1813. }
  1814. LOGENTRY(DeviceData, G, '_poo', EndpointData, 0, cf);
  1815. //
  1816. // Active AND Halted -- should never happen
  1817. // !Active AND !Halted -- advance queue head
  1818. // Active AND !Halted -- executing transaction in overlay
  1819. // !Active AND Halted -- queue had is stopped due to an error
  1820. halted = (BOOLEAN) overlay.Token.Halted;
  1821. active = (BOOLEAN) overlay.Token.Active;
  1822. if (!active && halted) {
  1823. // queue is halted
  1824. SET_FLAG(EndpointData->Flags, EHCI_EDFLAG_HALTED);
  1825. EHCI_PollHaltedAsyncEndpoint(DeviceData, EndpointData);
  1826. } else {
  1827. // queue is active
  1828. EHCI_PollActiveAsyncEndpoint(DeviceData, EndpointData);
  1829. }
  1830. // now flush all completed TDs in order of completion from
  1831. // our 'done' List
  1832. while (!IsListEmpty(&EndpointData->DoneTdList)) {
  1833. listEntry = RemoveHeadList(&EndpointData->DoneTdList);
  1834. td = (PHCD_TRANSFER_DESCRIPTOR) CONTAINING_RECORD(
  1835. listEntry,
  1836. struct _HCD_TRANSFER_DESCRIPTOR,
  1837. DoneLink);
  1838. EHCI_ASSERT(DeviceData, (td->Flags & (TD_FLAG_XFER | TD_FLAG_DONE)));
  1839. EHCI_ProcessDoneAsyncTd(DeviceData,
  1840. td);
  1841. }
  1842. }
  1843. VOID
  1844. EHCI_AssertQhChk(
  1845. PDEVICE_DATA DeviceData,
  1846. PENDPOINT_DATA EndpointData
  1847. )
  1848. {
  1849. PULONG p;
  1850. ULONG i;
  1851. p = (PULONG) EndpointData->QhChk;
  1852. for (i=0; i<256/sizeof(*p); i++) {
  1853. EHCI_ASSERT(DeviceData, *p == 0);
  1854. p++;
  1855. }
  1856. }
  1857. VOID
  1858. EHCI_SetNextTd(
  1859. PDEVICE_DATA DeviceData,
  1860. PHCD_TRANSFER_DESCRIPTOR LinkTd,
  1861. PHCD_TRANSFER_DESCRIPTOR NextTd,
  1862. BOOLEAN SetAltNext
  1863. )
  1864. {
  1865. EHCI_ASSERT(DeviceData, LinkTd != NextTd);\
  1866. if (SetAltNext) {
  1867. do {
  1868. LinkTd->HwTD.Next_qTD.HwAddress = NextTd->PhysicalAddress;
  1869. LinkTd->HwTD.AltNext_qTD.HwAddress = NextTd->PhysicalAddress;
  1870. } while (LinkTd->HwTD.Next_qTD.HwAddress !=
  1871. LinkTd->HwTD.AltNext_qTD.HwAddress);
  1872. TRANSFER_DESCRIPTOR_PTR(LinkTd->NextHcdTD) = NextTd;
  1873. TRANSFER_DESCRIPTOR_PTR(LinkTd->AltNextHcdTD) = NextTd;
  1874. } else {
  1875. LinkTd->HwTD.Next_qTD.HwAddress = NextTd->PhysicalAddress;
  1876. TRANSFER_DESCRIPTOR_PTR(LinkTd->NextHcdTD) = NextTd;
  1877. }
  1878. }
  1879. VOID
  1880. EHCI_SetAltNextTd(
  1881. PDEVICE_DATA DeviceData,
  1882. PHCD_TRANSFER_DESCRIPTOR LinkTd,
  1883. PHCD_TRANSFER_DESCRIPTOR NextTd
  1884. )
  1885. {
  1886. EHCI_ASSERT(DeviceData, LinkTd != NextTd);
  1887. LinkTd->HwTD.AltNext_qTD.HwAddress = NextTd->PhysicalAddress;
  1888. TRANSFER_DESCRIPTOR_PTR(LinkTd->AltNextHcdTD) = NextTd;
  1889. }