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.

2028 lines
58 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. ohciurb.c
  5. Abstract:
  6. The module manages transactions on the USB.
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. 02-07-96: created jfuller
  12. 03-05-96: in work kenray
  13. --*/
  14. #include "openhci.h"
  15. /*
  16. Private functions to this module
  17. */
  18. NTSTATUS
  19. OpenHCI_OpenEndpoint(
  20. IN PDEVICE_OBJECT,
  21. IN PIRP,
  22. PHCD_DEVICE_DATA,
  23. PHCD_URB);
  24. NTSTATUS
  25. OpenHCI_CloseEndpoint(
  26. IN PDEVICE_OBJECT,
  27. IN PIRP,
  28. PHCD_DEVICE_DATA,
  29. PHCD_URB);
  30. VOID
  31. OpenHCI_CompleteIrp(
  32. IN PDEVICE_OBJECT DeviceObject,
  33. IN PIRP Irp,
  34. IN NTSTATUS ntStatus
  35. )
  36. /*++
  37. Routine Description:
  38. Completes an I/O Request
  39. Arguments:
  40. DeviceObject - pointer to a device object
  41. Irp - pointer to an I/O Request Packet to complete
  42. ntStatus - status code to set int the IRP when completed
  43. Return Value:
  44. --*/
  45. {
  46. PHCD_DEVICE_DATA DeviceData;
  47. DeviceData = DeviceObject->DeviceExtension;
  48. Irp->IoStatus.Status = ntStatus;
  49. Irp->IoStatus.Information = 0;
  50. //
  51. // call IoCompleteRequest thru USBD to give it a chance to do
  52. // cleanup and error mapping
  53. //
  54. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_CALL_TRACE,
  55. ("'Completing IRP %x (%x)\n", Irp, ntStatus));
  56. IRP_OUT(Irp);
  57. LOGENTRY(G, 'Cirp', Irp, 0, ntStatus);
  58. USBD_CompleteRequest(Irp, IO_NO_INCREMENT);
  59. }
  60. NTSTATUS
  61. OpenHCI_URB_Dispatch(
  62. IN PDEVICE_OBJECT DeviceObject,
  63. IN PIRP Irp
  64. )
  65. /*++
  66. Routine Description:
  67. Process URBs from the dispatch routine.
  68. Arguments:
  69. DeviceObject - pointer to a device object
  70. Irp - pointer to an I/O Request Packet
  71. Return Value:
  72. --*/
  73. {
  74. PHCD_URB urb;
  75. NTSTATUS ntStatus = STATUS_SUCCESS;
  76. PHCD_DEVICE_DATA DeviceData;
  77. PHCD_ENDPOINT endpoint;
  78. struct _URB_HCD_ENDPOINT_STATE *state;
  79. PHC_OPERATIONAL_REGISTER HC;
  80. DeviceData = (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  81. OpenHCI_KdPrintDD(DeviceData,
  82. OHCI_DBG_CALL_TRACE, ("'enter URB_Dispatch \n"));
  83. HC = DeviceData->HC;
  84. urb = (PHCD_URB) URB_FROM_IRP(Irp);
  85. switch (urb->UrbHeader.Function) {
  86. //
  87. // Open Endpoint and Close Endpoint IRPs are serialized
  88. // within USBD so we can execute them now.
  89. //
  90. case URB_FUNCTION_HCD_OPEN_ENDPOINT:
  91. ntStatus = OpenHCI_OpenEndpoint(DeviceObject, Irp, DeviceData, urb);
  92. OpenHCI_CompleteIrp(DeviceObject, Irp, ntStatus);
  93. break;
  94. case URB_FUNCTION_HCD_CLOSE_ENDPOINT:
  95. ntStatus = OpenHCI_CloseEndpoint(DeviceObject, Irp, DeviceData, urb);
  96. OpenHCI_CompleteIrp(DeviceObject, Irp, ntStatus);
  97. break;
  98. case URB_FUNCTION_CONTROL_TRANSFER:
  99. case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
  100. case URB_FUNCTION_ISOCH_TRANSFER:
  101. endpoint = urb->HcdUrbCommonTransfer.hca.HcdEndpoint;
  102. ntStatus = OpenHCI_QueueTransfer(DeviceObject, Irp);
  103. if (ntStatus != STATUS_PENDING) {
  104. OpenHCI_CompleteIrp(DeviceObject, Irp, ntStatus);
  105. }
  106. break;
  107. case URB_FUNCTION_GET_CURRENT_FRAME_NUMBER:
  108. urb->UrbGetCurrentFrameNumber.FrameNumber
  109. = Get32BitFrameNumber(DeviceData);
  110. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_CALL_INFO,
  111. ("'Get32BitFrameNumber: %x",
  112. Get32BitFrameNumber(DeviceData)));
  113. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  114. OpenHCI_CompleteIrp(DeviceObject, Irp, ntStatus);
  115. break;
  116. case URB_FUNCTION_SET_FRAME_LENGTH:
  117. {
  118. HC_FM_INTERVAL interval;
  119. //get the current value
  120. interval.ul =
  121. READ_REGISTER_ULONG(&HC->HcFmInterval.ul);
  122. interval.FrameInterval +=
  123. (CHAR) urb->UrbSetFrameLength.FrameLengthDelta;
  124. WRITE_REGISTER_ULONG(&HC->HcFmInterval.ul,
  125. interval.ul);
  126. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  127. OpenHCI_CompleteIrp(DeviceObject, Irp, ntStatus);
  128. }
  129. break;
  130. case URB_FUNCTION_GET_FRAME_LENGTH:
  131. {
  132. HC_FM_INTERVAL interval;
  133. //get the current value
  134. interval.ul =
  135. READ_REGISTER_ULONG(&HC->HcFmInterval.ul);
  136. urb->UrbGetFrameLength.FrameNumber =
  137. Get32BitFrameNumber(DeviceData);
  138. urb->UrbGetFrameLength.FrameLength =
  139. interval.FrameInterval;
  140. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  141. OpenHCI_CompleteIrp(DeviceObject, Irp, ntStatus);
  142. }
  143. break;
  144. case URB_FUNCTION_HCD_GET_ENDPOINT_STATE:
  145. {
  146. KIRQL irql;
  147. BOOLEAN queuedTransfers, activeTransfers;
  148. state = &urb->HcdUrbEndpointState;
  149. endpoint = state->HcdEndpoint;
  150. LOGENTRY(G, 'gEPS', Irp, endpoint, 0);
  151. if (endpoint == ZERO_LOAD_ENDPOINT(DeviceData)) {
  152. state->HcdEndpointState = 0;
  153. } else {
  154. ASSERT_ENDPOINT(endpoint);
  155. OpenHCI_LockAndCheckEndpoint(endpoint,
  156. &queuedTransfers,
  157. &activeTransfers,
  158. &irql);
  159. if (endpoint->EpFlags & EP_ROOT_HUB) {
  160. state->HcdEndpointState =
  161. (queuedTransfers | activeTransfers)
  162. ? HCD_ENDPOINT_TRANSFERS_QUEUED : 0;
  163. } else {
  164. state->HcdEndpointState =
  165. ((endpoint->HcdED->HcED.HeadP & HcEDHeadP_HALT)
  166. ? HCD_ENDPOINT_HALTED : 0)
  167. | ((queuedTransfers | activeTransfers)
  168. ? HCD_ENDPOINT_TRANSFERS_QUEUED : 0);
  169. }
  170. OpenHCI_UnlockEndpoint(endpoint,
  171. irql);
  172. }
  173. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  174. LOGENTRY(G, 'GETs', Irp, endpoint, state->HcdEndpointState);
  175. OpenHCI_CompleteIrp(DeviceObject, Irp, ntStatus);
  176. }
  177. break;
  178. case URB_FUNCTION_HCD_SET_ENDPOINT_STATE:
  179. {
  180. PHC_ENDPOINT_DESCRIPTOR hcED;
  181. state = &urb->HcdUrbEndpointState;
  182. endpoint = state->HcdEndpoint;
  183. ASSERT_ENDPOINT(endpoint);
  184. hcED = &endpoint->HcdED->HcED;
  185. LOGENTRY(G, 'SETs', Irp, endpoint, state->HcdEndpointState);
  186. // reset some endpoint flags
  187. SET_EPFLAG(endpoint, EP_VIRGIN);
  188. // need to reset data toggle on clear halt
  189. if (state->HcdEndpointState & HCD_ENDPOINT_RESET_DATA_TOGGLE) {
  190. //OHCI_ASSERT(hcED->sKip ||
  191. // (hcED->HeadP & HcEDHeadP_HALT));
  192. hcED->HeadP = (endpoint->HcdHeadP->PhysicalAddress
  193. & ~HcEDHeadP_CARRY);
  194. }
  195. if (!(state->HcdEndpointState & HCD_ENDPOINT_HALTED)) {
  196. LOGENTRY(G, 'CLRh', Irp, endpoint, state->HcdEndpointState);
  197. if (hcED->HeadP & HcEDHeadP_HALT) {
  198. // If the endpoint is indeed halted than the hardware will
  199. // not be touching the ED. So we should be able to set this
  200. // flag with impunity.
  201. hcED->HeadP &= ~HcEDHeadP_HALT;
  202. LOGENTRY(G, 'HLTn', Irp, endpoint, state->HcdEndpointState);
  203. }
  204. ENABLE_LIST(DeviceData->HC, endpoint);
  205. }
  206. }
  207. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  208. OpenHCI_CompleteIrp(DeviceObject, Irp, ntStatus);
  209. break;
  210. case URB_FUNCTION_HCD_ABORT_ENDPOINT:
  211. endpoint = urb->HcdUrbAbortEndpoint.HcdEndpoint;
  212. LOGENTRY(G, 'Abrt', Irp, endpoint, 0);
  213. if (ZERO_LOAD_ENDPOINT(DeviceData) == endpoint) {
  214. ntStatus = STATUS_SUCCESS;
  215. } else {
  216. KIRQL oldIrq;
  217. KeAcquireSpinLock(&DeviceData->PausedSpin, &oldIrq);
  218. #if DBG
  219. if (endpoint->EpFlags & EP_ROOT_HUB) {
  220. OHCI_ASSERT(endpoint->AbortIrp == NULL);
  221. }
  222. #endif
  223. if (endpoint->AbortIrp != NULL) {
  224. // if we get an abort while we still have an abort irp
  225. // pending then the driver has a bug, we will just fail
  226. // the request
  227. TRAP();
  228. ntStatus = STATUS_UNSUCCESSFUL;
  229. KeReleaseSpinLock(&DeviceData->PausedSpin, oldIrq);
  230. OpenHCI_CompleteIrp(DeviceObject, Irp, ntStatus);
  231. } else {
  232. KeReleaseSpinLock(&DeviceData->PausedSpin, oldIrq);
  233. ntStatus = OpenHCI_AbortEndpoint(DeviceObject,
  234. Irp,
  235. DeviceData,
  236. urb);
  237. }
  238. }
  239. break;
  240. default:
  241. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_CALL_ERROR,
  242. ("'OpenHCI_URB_Dispatch -- invalid URB function (%x)\n",
  243. urb->UrbHeader.Function));
  244. urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
  245. OpenHCI_CompleteIrp(DeviceObject, Irp, ntStatus);
  246. }
  247. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_CALL_TRACE,
  248. ("'exit OpenHCI_URB_Dispatch (%x)\n", ntStatus));
  249. return ntStatus;
  250. }
  251. NTSTATUS
  252. OpenHCI_GrowDescriptorPool (
  253. IN PHCD_DEVICE_DATA DeviceData,
  254. IN ULONG ReserveLength,
  255. OUT PCHAR *VirtAddr OPTIONAL,
  256. OUT PHYSICAL_ADDRESS *PhysAddr OPTIONAL
  257. )
  258. /*++
  259. Routine Description:
  260. Reserve Transfer/Endpoint Descriptors.
  261. This function allocates a block of common buffer memory for
  262. Transfer and Endpoint Descriptors and puts it on a tracking
  263. list in the device extension.
  264. Arguments:
  265. DeviceData - pointer to a device extension
  266. ReserveLength - amount of space to reserve at the beginning
  267. of the common buffer
  268. VirtAddr - virtual address of space reserved at the beginning
  269. of the common buffer
  270. PhysAddr - physical address of space reserved at the beginning
  271. of the common buffer
  272. Return Value:
  273. NT Status code
  274. --*/
  275. {
  276. ULONG allocLength;
  277. PCHAR pageVirt;
  278. PHYSICAL_ADDRESS pagePhys;
  279. PPAGE_LIST_ENTRY pageList;
  280. PHCD_TRANSFER_DESCRIPTOR td;
  281. // Assert that sizeof(HCD_TRANSFER_DESCRIPTOR) is a power of 2
  282. //
  283. C_ASSERT((sizeof(HCD_TRANSFER_DESCRIPTOR) &
  284. sizeof(HCD_TRANSFER_DESCRIPTOR) - 1) == 0);
  285. // Round up ReserveLength to the next multiple of the
  286. // sizeof(HCD_TRANSFER_DESCRIPTOR).
  287. //
  288. ReserveLength += sizeof(HCD_TRANSFER_DESCRIPTOR) - 1;
  289. ReserveLength &= ~(sizeof(HCD_TRANSFER_DESCRIPTOR) - 1);
  290. // Round up allocLength to the next multiple of PAGE_SIZE
  291. //
  292. allocLength = ReserveLength + PAGE_SIZE;
  293. allocLength &= ~(PAGE_SIZE - 1);
  294. // Now allocate the common buffer
  295. //
  296. pageVirt = HalAllocateCommonBuffer(DeviceData->AdapterObject,
  297. allocLength,
  298. &pagePhys,
  299. CacheCommon);
  300. if (pageVirt == NULL)
  301. {
  302. return STATUS_INSUFFICIENT_RESOURCES;
  303. }
  304. // Zero initialize the whole page
  305. //
  306. RtlZeroMemory(pageVirt, allocLength);
  307. // Allocate a PAGE_LIST_ENTRY to track the page of commom buffer.
  308. //
  309. pageList = ExAllocatePoolWithTag(NonPagedPool,
  310. sizeof(PAGE_LIST_ENTRY),
  311. OpenHCI_TAG);
  312. if (pageList == NULL)
  313. {
  314. HalFreeCommonBuffer(DeviceData->AdapterObject,
  315. allocLength,
  316. pagePhys,
  317. pageVirt,
  318. CacheCommon);
  319. return STATUS_INSUFFICIENT_RESOURCES;
  320. }
  321. LOGENTRY(G, 'GROW', DeviceData, pageList, pagePhys.LowPart);
  322. // Initialize the PAGE_LIST_ENTRY to track the page of commom buffer.
  323. //
  324. pageList->BufferSize = allocLength;
  325. pageList->VirtAddr = pageVirt;
  326. pageList->PhysAddr = pagePhys;
  327. pageList->FirstTDVirt = (PHCD_TRANSFER_DESCRIPTOR)(pageVirt + ReserveLength);
  328. pageList->LastTDVirt = (PHCD_TRANSFER_DESCRIPTOR)(pageVirt + allocLength) - 1;
  329. pageList->FirstTDPhys = pagePhys;
  330. pageList->FirstTDPhys.LowPart += ReserveLength;
  331. pageList->LastTDPhys = pagePhys;
  332. pageList->LastTDPhys.LowPart += allocLength - sizeof(PHCD_TRANSFER_DESCRIPTOR);;
  333. // Add the PAGE_LIST_ENTRY to the device extension
  334. //
  335. ExInterlockedPushEntryList((PSINGLE_LIST_ENTRY)&DeviceData->PageList,
  336. (PSINGLE_LIST_ENTRY)pageList,
  337. &DeviceData->PageListSpin);
  338. // Add all of the TDs in the page of common buffer to the
  339. // Free Descriptor list.
  340. //
  341. pagePhys = pageList->FirstTDPhys;
  342. for (td = pageList->FirstTDVirt; td <= pageList->LastTDVirt; td++)
  343. {
  344. // Initialize the TD PhysicalAddress field to point back to the TD
  345. //
  346. td->PhysicalAddress = pagePhys.LowPart;
  347. pagePhys.LowPart += sizeof(HCD_TRANSFER_DESCRIPTOR);
  348. ExInterlockedPushEntryList(&DeviceData->FreeDescriptorList,
  349. (PSINGLE_LIST_ENTRY)td,
  350. &DeviceData->DescriptorsSpin);
  351. InterlockedIncrement(&DeviceData->FreeDescriptorCount);
  352. }
  353. // Return pointers to the reserved space if desired
  354. //
  355. if (VirtAddr)
  356. {
  357. *VirtAddr = pageList->VirtAddr;
  358. }
  359. if (PhysAddr)
  360. {
  361. *PhysAddr = pageList->PhysAddr;
  362. }
  363. return STATUS_SUCCESS;
  364. }
  365. NTSTATUS
  366. OpenHCI_ReserveDescriptors(
  367. IN PHCD_DEVICE_DATA DeviceData,
  368. IN ULONG DescriptorCount
  369. )
  370. /*++
  371. Routine Description:
  372. Reserve Transfer/Endpoint Descriptors.
  373. NOTE:
  374. This routine is called only by openendpoint so it will never be
  375. rentered.
  376. Arguments:
  377. DeviceData - pointer to a device extension
  378. DescriptorCount - number of descriptors to reserve
  379. Return Value:
  380. NT Status code
  381. --*/
  382. {
  383. NTSTATUS ntStatus = STATUS_SUCCESS;
  384. while (DeviceData->FreeDescriptorCount < DescriptorCount &&
  385. NT_SUCCESS(ntStatus))
  386. {
  387. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_CALL_TRACE,
  388. ("'grow pool by one page\n"));
  389. ntStatus = OpenHCI_GrowDescriptorPool(DeviceData,
  390. 0,
  391. NULL,
  392. NULL);
  393. }
  394. if (NT_SUCCESS(ntStatus))
  395. {
  396. DeviceData->FreeDescriptorCount -= DescriptorCount;
  397. }
  398. LOGENTRY(G, 'rsDS',
  399. DescriptorCount, DeviceData->FreeDescriptorCount, ntStatus);
  400. return ntStatus;
  401. }
  402. NTSTATUS
  403. OpenHCI_UnReserveDescriptors(
  404. IN PHCD_DEVICE_DATA DeviceData,
  405. IN ULONG DescriptorCount
  406. )
  407. /*++
  408. Routine Description:
  409. Free reserved Transfer/Endpoint Descriptors.
  410. NOTE:
  411. This routine is called only by closeendpoint so it will never be
  412. rentered.
  413. Arguments:
  414. DeviceData - pointer to a device extension
  415. DescriptorCount - number of descriptors to reserve
  416. Return Value:
  417. NT Status code
  418. --*/
  419. {
  420. DeviceData->FreeDescriptorCount += DescriptorCount;
  421. LOGENTRY(G, 'urDS', DescriptorCount, DeviceData->FreeDescriptorCount, 0);
  422. return STATUS_SUCCESS;
  423. }
  424. PHCD_TRANSFER_DESCRIPTOR
  425. OpenHCI_Alloc_HcdTD(
  426. PHCD_DEVICE_DATA DeviceData
  427. )
  428. /*++
  429. Routine Description:
  430. allocate a reserved desriptor, this routine can be called at
  431. IRQL >= DISPATCH_LEVEL
  432. Arguments:
  433. DeviceData - pointer to a device extension
  434. Return Value:
  435. NT Status code
  436. --*/
  437. {
  438. PHCD_TRANSFER_DESCRIPTOR td;
  439. td = (PHCD_TRANSFER_DESCRIPTOR)
  440. ExInterlockedPopEntryList(&DeviceData->FreeDescriptorList,
  441. &DeviceData->DescriptorsSpin);
  442. LOGENTRY(G, 'alTD', &DeviceData->FreeDescriptorList, td, DeviceData->FreeDescriptorCount);
  443. OHCI_ASSERT(td != NULL);
  444. OHCI_ASSERT(td->Flags == 0);
  445. OHCI_ASSERT((td->PhysicalAddress & (PAGE_SIZE-1)) ==
  446. ((ULONG_PTR)td & (PAGE_SIZE-1)));
  447. // Initialize the TD NextTD pointer to a non-zero value before setting
  448. // the TD_FLAG_INUSE flag. The only time a TD NextTD pointer should be
  449. // zero when the TD_FLAG_INUSE flag is set is when the TD is the tail
  450. // end of a done list.
  451. //
  452. td->HcTD.NextTD = 0x2BAD2BAD;
  453. td->Flags = TD_FLAG_INUSE;
  454. //
  455. // if we fail to get a td we have a bug since we always reserve
  456. // enough for the worst case scenario when an endpoint is opened
  457. //
  458. return td;
  459. }
  460. VOID
  461. OpenHCI_Free_HcdTD(
  462. PHCD_DEVICE_DATA DeviceData,
  463. PHCD_TRANSFER_DESCRIPTOR Td
  464. )
  465. {
  466. LOGENTRY(G, 'frTD', &DeviceData->FreeDescriptorList, Td, DeviceData->FreeDescriptorCount);
  467. OHCI_ASSERT((Td->PhysicalAddress & (PAGE_SIZE-1)) ==
  468. ((ULONG_PTR)Td & (PAGE_SIZE-1)));
  469. OHCI_ASSERT(Td->Flags == TD_FLAG_INUSE);
  470. Td->Flags = 0;
  471. ExInterlockedPushEntryList(&DeviceData->FreeDescriptorList,
  472. (PSINGLE_LIST_ENTRY) Td,
  473. &DeviceData->DescriptorsSpin);
  474. }
  475. PHCD_ENDPOINT_DESCRIPTOR
  476. OpenHCI_Alloc_HcdED(
  477. PHCD_DEVICE_DATA DeviceData
  478. )
  479. /*++
  480. Routine Description:
  481. allocate a reserved desriptor, this routine can be called at
  482. IRQL >= DISPATCH_LEVEL
  483. Arguments:
  484. DeviceData - pointer to a device extension
  485. Return Value:
  486. NT Status code
  487. --*/
  488. {
  489. PHCD_ENDPOINT_DESCRIPTOR ed;
  490. ed = (PHCD_ENDPOINT_DESCRIPTOR)
  491. ExInterlockedPopEntryList(&DeviceData->FreeDescriptorList,
  492. &DeviceData->DescriptorsSpin);
  493. LOGENTRY(G, 'alED', &DeviceData->FreeDescriptorList, ed, DeviceData->FreeDescriptorCount);
  494. OHCI_ASSERT(ed != NULL);
  495. OHCI_ASSERT(ed->Flags == 0);
  496. OHCI_ASSERT((ed->PhysicalAddress & (PAGE_SIZE-1)) ==
  497. ((ULONG_PTR)ed & (PAGE_SIZE-1)));
  498. ed->Flags = TD_FLAG_INUSE | TD_FLAG_IS_ED;
  499. //
  500. // if we fail to get a td we have a bug since we always reserve
  501. // enough for the worst case scenario when an endpoint is opened
  502. //
  503. return ed;
  504. }
  505. PHCD_TRANSFER_DESCRIPTOR
  506. OpenHCI_LogDesc_to_PhyDesc(
  507. PHCD_DEVICE_DATA DeviceData,
  508. ULONG LogDesc
  509. )
  510. /*++
  511. Routine Description:
  512. This routine scans the list of pages allocated by
  513. HalAllocateCommonBuffer into the list DeviceData->PageList
  514. for the storage of Descriptors.
  515. The first entries describe the virtual and logical
  516. addresses of those pages.
  517. Arguments:
  518. LogDesc is the logical address of a HcTD structure in memory.
  519. Returned Value:
  520. The virtual address of the HCD_Descriptor the (logical) HC_descriptor.
  521. Note that the virtual address of the HC_TRANSFER_DESCRIPTOR
  522. is the same as HCD_TRANSFER_DESCRIPTOR as well as
  523. the HC_ENDPOINT_DESCRIPTOR the same as HCD_TRANSFER_DESCRIPTOR.
  524. If no translation is found this will return NULL.
  525. There are concurrent writes to DeviceData->PageList, but throughout
  526. the life of DeviceData, only new pages will be pushed onto the list.
  527. If these pages are added to the list while this function is running,
  528. these pages cannot contain the logical address for which we are
  529. searching.
  530. --*/
  531. {
  532. PPAGE_LIST_ENTRY PageList;
  533. PHCD_TRANSFER_DESCRIPTOR td;
  534. if (LogDesc & (sizeof(HCD_TRANSFER_DESCRIPTOR)-1))
  535. {
  536. // The address is not properly aligned to be a TD.
  537. // Something bad has happened. Try our best not to
  538. // fault processing a bogus TD.
  539. //
  540. LOGENTRY(G, 'Phy1', DeviceData, LogDesc, 0);
  541. //TEST_TRAP();
  542. return NULL;
  543. }
  544. PageList = (PPAGE_LIST_ENTRY)DeviceData->PageList;
  545. while (PageList)
  546. {
  547. if (LogDesc >= PageList->FirstTDPhys.LowPart &&
  548. LogDesc <= PageList->LastTDPhys.LowPart)
  549. {
  550. td = (PHCD_TRANSFER_DESCRIPTOR)((PCHAR)PageList->FirstTDVirt +
  551. LogDesc - PageList->FirstTDPhys.LowPart);
  552. if (td->Flags == TD_FLAG_INUSE)
  553. {
  554. // Appears to be a valid TD
  555. //
  556. return td;
  557. }
  558. else
  559. {
  560. // The TD is not marked as an in-use TD. Something
  561. // bad has happened. Try our best not to fault
  562. // processing a bogus TD.
  563. //
  564. LOGENTRY(G, 'Phy2', DeviceData, LogDesc, 0);
  565. //TEST_TRAP();
  566. return NULL;
  567. }
  568. }
  569. PageList = PageList->NextPage;
  570. }
  571. return NULL;
  572. }
  573. ULONG
  574. OpenHCI_CheckBandwidth(
  575. IN PHCD_DEVICE_DATA DeviceData,
  576. IN UCHAR List,
  577. OUT PCHAR BestList
  578. )
  579. /*++
  580. Routine Description:
  581. This routine scans all the scheduling lists of frequency
  582. determined by the base List passed in and returns the worst
  583. bandwidth found (i.e., max in use by any given scheduling
  584. list) and the list which had the least bandwidth in use.
  585. All lists of the appropriate frequency are checked
  586. Arguments:
  587. DeviceData - pointer to this controller's data area
  588. List - must be a base scheduling list.
  589. I.e., it must be one of ED_INTERRUPT_1ms, ED_INTERRUPT_2ms,
  590. ED_INTERRUPT_4ms, ..., ED_INTERRUPT_32ms.
  591. BestList - Pointer to a ULONG that recieves the list number of the
  592. list with least bandwidth in use.
  593. Returned Value:
  594. The maximum bandwidth in use by any of the selected lists.
  595. --*/
  596. {
  597. ULONG LastList, Index;
  598. ULONG BestBandwidth, WorstBandwidth, Bandwidth;
  599. WorstBandwidth = 0;
  600. BestBandwidth = ~(ULONG) 0;
  601. for (LastList = List + List; List <= LastList; List++) {
  602. //
  603. // Sum bandwidth in use in this scheduling time
  604. //
  605. Bandwidth = 0;
  606. for (Index = List;
  607. Index != ED_EOF;
  608. Index = DeviceData->EDList[Index].Next) {
  609. Bandwidth += DeviceData->EDList[Index].Bandwidth;
  610. }
  611. //
  612. // Remember best and worst
  613. //
  614. if (Bandwidth < BestBandwidth) {
  615. BestBandwidth = Bandwidth;
  616. if (BestList != NULL) {
  617. *BestList = List;
  618. }
  619. }
  620. if (Bandwidth > WorstBandwidth) {
  621. WorstBandwidth = Bandwidth;
  622. }
  623. }
  624. LOGENTRY(G, 'ckBW', Bandwidth, 0, WorstBandwidth);
  625. return WorstBandwidth;
  626. }
  627. PHCD_ENDPOINT_DESCRIPTOR
  628. InsertEDForEndpoint(
  629. IN PHCD_DEVICE_DATA DeviceData,
  630. IN PHCD_ENDPOINT Endpoint,
  631. IN UCHAR ListIndex,
  632. IN PHCD_TRANSFER_DESCRIPTOR *TailTd
  633. )
  634. /*++
  635. Routine Description:
  636. Insert an endpoint into the h/w schedule, optionally this will
  637. allocate an endpoint descriptor and/or a dummy transfer descriptor.
  638. Arguments:
  639. Endpoint - pointer to the endpoint to be included in schedule
  640. if this parameter is NULL then we are inserting a dummy ED
  641. that has no associted endpoint.
  642. --*/
  643. {
  644. PHCD_ED_LIST list;
  645. PHCD_ENDPOINT_DESCRIPTOR tailED, ed;
  646. PHCD_TRANSFER_DESCRIPTOR td;
  647. KIRQL oldIrql;
  648. UCHAR endpointType;
  649. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_CALL_TRACE,
  650. ("'InsertEDForEndpoint %x\n", Endpoint));
  651. list = &DeviceData->EDList[ListIndex];
  652. LOGENTRY(G, 'inED', Endpoint, ListIndex, list);
  653. if (Endpoint == NULL) {
  654. // this is a dummy ED
  655. td = NULL;
  656. ed = NULL;
  657. } else {
  658. // we have an endpoint
  659. td = Endpoint->HcdHeadP;
  660. ed = Endpoint->HcdED;
  661. }
  662. if (td == NULL) {
  663. //
  664. // no TD,
  665. // get a dummy TD and attach to the endpoint
  666. //
  667. if (td = OpenHCI_Alloc_HcdTD(DeviceData)) {
  668. td->UsbdRequest = TD_NOREQUEST_SIG;
  669. // if an endpoint is specified then we want this TD to be
  670. // the dummy TD that the haed & tail point to for a real
  671. // endpoint
  672. if (Endpoint != NULL) {
  673. Endpoint->HcdHeadP = Endpoint->HcdTailP = td;
  674. }
  675. // return the tail td if asked
  676. if (TailTd) {
  677. *TailTd = td;
  678. }
  679. }
  680. LOGENTRY(G, 'dyTD', Endpoint, td, list);
  681. }
  682. if (ed == NULL) {
  683. //
  684. // Need an ED,
  685. // Get an ED, attach it to endpoint if we have one
  686. //
  687. ed = OpenHCI_Alloc_HcdED(DeviceData);
  688. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_CALL_TRACE,
  689. ("'InsertEDForEndpoint ED = %x\n", ed));
  690. if (Endpoint && ed) {
  691. Endpoint->HcdED = ed;
  692. }
  693. LOGENTRY(G, 'dyED', Endpoint, ed, 0);
  694. }
  695. OHCI_ASSERT(td != 0);
  696. OHCI_ASSERT(ed != 0);
  697. if (ed == NULL || td == NULL) {
  698. // we are probably screwed
  699. OpenHCI_KdTrap(("'failed to alloc dummy TD/ED\n"));
  700. return NULL;
  701. }
  702. //
  703. // Initialize an endpoint descriptor for this endpoint
  704. //
  705. if (Endpoint != NULL) {
  706. //
  707. // This is for a real endpoint
  708. //
  709. ed->HcED.Control = Endpoint->Control;
  710. endpointType = Endpoint->Type;
  711. } else {
  712. //
  713. // no real endpoint exists, this is a dummy ED
  714. // used to work around a hardware bug, we set the skip
  715. // bit so the HC does not process it.
  716. //
  717. ed->HcED.Control = HcEDControl_SKIP;
  718. if (ListIndex == ED_BULK) {
  719. endpointType = USB_ENDPOINT_TYPE_BULK;
  720. } else if (ListIndex == ED_CONTROL) {
  721. endpointType = USB_ENDPOINT_TYPE_CONTROL;
  722. } else if (ListIndex == ED_ISOCHRONOUS) {
  723. endpointType = USB_ENDPOINT_TYPE_ISOCHRONOUS;
  724. } else {
  725. endpointType = USB_ENDPOINT_TYPE_INTERRUPT;
  726. }
  727. }
  728. ed->Endpoint = Endpoint;
  729. ed->ListIndex = ListIndex;
  730. ed->PauseFlag = HCD_ED_PAUSE_NOT_PAUSED;
  731. ed->HcED.TailP = ed->HcED.HeadP = td->PhysicalAddress;
  732. KeAcquireSpinLock(&DeviceData->EDListSpin, &oldIrql);
  733. //
  734. // Link endpoint descriptor into HCD tracking queue
  735. //
  736. if (endpointType != USB_ENDPOINT_TYPE_ISOCHRONOUS ||
  737. IsListEmpty(&list->Head)) {
  738. //
  739. // if it is not an iso ED or there are no EDs in the list
  740. // then link it to the head of the hw queue
  741. //
  742. InsertHeadList(&list->Head, &ed->Link);
  743. if (list->HcRegister) {
  744. // update the hardware register that points to the list head
  745. LOGENTRY(G, 'INH1', list, ed, list->PhysicalHead);
  746. // tail points to old head
  747. ed->HcED.NextED = READ_REGISTER_ULONG(list->PhysicalHead);
  748. // new head is this ed
  749. WRITE_REGISTER_ULONG(list->PhysicalHead, ed->PhysicalAddress);
  750. } else {
  751. LOGENTRY(G, 'INH2', list, ed, list->PhysicalHead);
  752. // tail points to old head
  753. ed->HcED.NextED = *list->PhysicalHead;
  754. // new head is this ed
  755. *list->PhysicalHead = ed->PhysicalAddress;
  756. }
  757. } else {
  758. //
  759. // Something already on the list,
  760. // Link ED into tail of ED list
  761. //
  762. tailED = CONTAINING_RECORD(list->Head.Blink,
  763. HCD_ENDPOINT_DESCRIPTOR,
  764. Link);
  765. LOGENTRY(G, 'INT1', list, ed, 0);
  766. InsertTailList(&list->Head, &ed->Link);
  767. ed->HcED.NextED = 0;
  768. tailED->HcED.NextED = ed->PhysicalAddress;
  769. }
  770. KeReleaseSpinLock(&DeviceData->EDListSpin, oldIrql);
  771. return (ed);
  772. }
  773. VOID
  774. RemoveEDForEndpoint(
  775. IN PHCD_ENDPOINT Endpoint
  776. )
  777. /*++
  778. Routine Description:
  779. Remove an endpoint from the hardware schedule.
  780. Arguments:
  781. Endpouint - the endpoint assocaited with the ED to remove.
  782. An Endpoint pointing to the Endpoint Descriptor to be removed.
  783. if breakEDLink then the link between the Endpoint Descriptor and its
  784. corresponding endpoint is severed.
  785. If this link is severed then the Endpoint Descriptor will be returned
  786. to the descriptor free pool during the next interrupt.
  787. --*/
  788. {
  789. PHCD_DEVICE_DATA DeviceData;
  790. PHCD_ED_LIST list;
  791. PHCD_ENDPOINT_DESCRIPTOR previousED, ed = Endpoint->HcdED;
  792. ULONG listDisable;
  793. KIRQL oldIrql;
  794. UCHAR tmp;
  795. PHC_OPERATIONAL_REGISTER HC;
  796. ASSERT_ENDPOINT(Endpoint);
  797. DeviceData = Endpoint->DeviceData;
  798. list = &DeviceData->EDList[Endpoint->ListIndex];
  799. LOGENTRY(G, 'RMed', Endpoint, ed, list);
  800. // if we are in the active list we need to remove ourselves
  801. KeAcquireSpinLock(&DeviceData->HcDmaSpin, &oldIrql);
  802. if (Endpoint->EpFlags & EP_IN_ACTIVE_LIST) {
  803. RemoveEntryList(&Endpoint->EndpointListEntry);
  804. CLR_EPFLAG(Endpoint, EP_IN_ACTIVE_LIST);
  805. }
  806. KeReleaseSpinLock(&DeviceData->HcDmaSpin, oldIrql);
  807. /* Prevent the Host Controller from processing this ED */
  808. ed->HcED.sKip = TRUE;
  809. KeAcquireSpinLock(&DeviceData->EDListSpin, &oldIrql);
  810. {
  811. /* Unlink the ED from the physical ED list */
  812. LOGENTRY(G, 'ULed', Endpoint, ed, list);
  813. if (&list->Head == ed->Link.Blink) {
  814. if (list->HcRegister) {
  815. WRITE_REGISTER_ULONG(list->PhysicalHead, ed->HcED.NextED);
  816. } else {
  817. *list->PhysicalHead = ed->HcED.NextED;
  818. }
  819. previousED = NULL;
  820. } else {
  821. previousED =
  822. CONTAINING_RECORD(ed->Link.Blink,
  823. HCD_ENDPOINT_DESCRIPTOR,
  824. Link);
  825. previousED->HcED.NextED = ed->HcED.NextED;
  826. }
  827. /* Unlink the ED from HCD list */
  828. RemoveEntryList(&ed->Link);
  829. ed->ListIndex = ED_EOF;
  830. }
  831. KeReleaseSpinLock(&DeviceData->EDListSpin, oldIrql);
  832. /* Break the Endpoint / ED connection. This descriptor is now heading for
  833. * the slaughter. */
  834. Endpoint->HcdED = NULL;
  835. ed->Endpoint = NULL;
  836. OHCI_ASSERT(Endpoint->HcdHeadP == Endpoint->HcdTailP);
  837. OHCI_ASSERT((ed->HcED.HeadP & ~15) == ed->HcED.TailP);
  838. /* AKA there are no transfers on this queue. The HC will not touch any of
  839. * these TD's. We can free the 'sentinel' TD here, but we CANNOT actually
  840. * zero out the head and tail pointers, because the HC could still be
  841. * looking at this descriptor. Later, in the irq, when we take this
  842. * endpoint off the reclamation list, we much free the ED, and ignore the
  843. * non zero values of HeadP and TailP. */
  844. OpenHCI_Free_HcdTD(DeviceData, Endpoint->HcdHeadP);
  845. /*
  846. * The control and bulk lists are round robbin. Therefore we need to
  847. * disable these lists to insure that the 'current ED' pointer is not
  848. * pointing to that which we are removing.
  849. */
  850. switch (Endpoint->ListIndex) {
  851. case ED_CONTROL:
  852. listDisable = ~(ULONG) HcCtrl_ControlListEnable;
  853. break;
  854. case ED_BULK:
  855. listDisable = ~(ULONG) HcCtrl_BulkListEnable;
  856. break;
  857. default:
  858. list->Bandwidth -= Endpoint->Bandwidth;
  859. DeviceData->MaxBandwidthInUse
  860. = OpenHCI_CheckBandwidth(DeviceData,
  861. ED_INTERRUPT_32ms,
  862. &tmp);
  863. listDisable = 0;
  864. }
  865. HC = DeviceData->HC;
  866. WRITE_REGISTER_ULONG(&HC->HcInterruptStatus, HcInt_StartOfFrame);
  867. /* Clear the SOF interrupt pending status */
  868. {
  869. if (listDisable) {
  870. KeSynch_HcControl context;
  871. context.NewHcControl.ul = listDisable;
  872. context.DeviceData = DeviceData;
  873. KeSynchronizeExecution(DeviceData->InterruptObject,
  874. OpenHCI_HcControl_AND,
  875. &context);
  876. KeAcquireSpinLock(&DeviceData->ReclamationSpin, &oldIrql);
  877. InsertTailList(&DeviceData->StalledEDReclamation, &ed->Link);
  878. } else {
  879. KeAcquireSpinLock(&DeviceData->ReclamationSpin, &oldIrql);
  880. InsertTailList(&DeviceData->RunningEDReclamation, &ed->Link);
  881. }
  882. ed->ReclamationFrame = Get32BitFrameNumber(DeviceData) + 1;
  883. WRITE_REGISTER_ULONG(&HC->HcInterruptEnable, HcInt_StartOfFrame);
  884. }
  885. KeReleaseSpinLock(&DeviceData->ReclamationSpin, oldIrql);
  886. // free our descriptors and endpoint
  887. OpenHCI_UnReserveDescriptors(DeviceData, Endpoint->DescriptorsReserved);
  888. // now free the endpoint
  889. Endpoint->Sig = 0;
  890. ExFreePool(Endpoint);
  891. }
  892. NTSTATUS
  893. OpenHCI_OpenEndpoint(
  894. IN PDEVICE_OBJECT DeviceObject,
  895. IN PIRP Irp,
  896. IN PHCD_DEVICE_DATA DeviceData,
  897. IN OUT PHCD_URB urb
  898. )
  899. /*++
  900. Routine Description:
  901. Create a OpenHCI endpoint, this function is called from
  902. OpenHCI_URB_Dispatch to create a new endpoint structure.
  903. There are three things that can cause this routine to fail:
  904. 1) ExAllocatePool may fail to allocate an HCD_ENDPOINT,
  905. 2) OpenHCI_ReserveDescriptors may not be able to find enough
  906. descriptors, and
  907. 3) OpenHCI_ReserveBandwidth may not be able to find bandwidth
  908. in the schedule.
  909. This routine is simplified because USBD serializes OpenEndpoint
  910. and CloseEndpoint URBs
  911. Arguments:
  912. DeviceObject - pointer to a device object
  913. Irp - pointer to an I/O Request Packet
  914. Return Value:
  915. NT Status code
  916. --*/
  917. {
  918. PHCD_ENDPOINT endpoint;
  919. PUSB_ENDPOINT_DESCRIPTOR endpointDescriptor;
  920. UCHAR WhichList;
  921. NTSTATUS ntStatus = STATUS_SUCCESS;
  922. ULONG tdsNeeded;
  923. OpenHCI_KdPrintDD(DeviceData,
  924. OHCI_DBG_END_TRACE, ("'enter OpenEndpoint\n"));
  925. #if DBG
  926. /*
  927. * We are assuming that the caller of _OpenEndpoint and _Close endpoint
  928. * make only serial calls. For this reason we will protect ourselves. If
  929. * this is violated we return STATUS_DEVICE_BUSY.
  930. */
  931. if (0 < InterlockedIncrement(&DeviceData->OpenCloseSync)) {
  932. OpenHCI_KdTrap(("'ohciurb.c: _OpenEndpoint: Non serial call! %d",
  933. DeviceData->OpenCloseSync));
  934. TEST_TRAP();
  935. return STATUS_DEVICE_BUSY;
  936. }
  937. #endif // DBG
  938. //
  939. // make sure the length of the urb is what we expect
  940. //
  941. if (urb->HcdUrbOpenEndpoint.Length !=
  942. sizeof(struct _URB_HCD_OPEN_ENDPOINT)) {
  943. urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
  944. return STATUS_INVALID_PARAMETER;
  945. }
  946. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  947. //
  948. // information about the endpoint comes from the USB endpoint
  949. // descriptor passed in the URB.
  950. //
  951. endpointDescriptor = urb->HcdUrbOpenEndpoint.EndpointDescriptor;
  952. urb->HcdUrbOpenEndpoint.HcdEndpoint = NULL;
  953. // How does one transmit to an endpoint that does not have
  954. // a positive max packet size?
  955. // A: this is an error
  956. if (endpointDescriptor->wMaxPacketSize == 0) {
  957. endpoint =
  958. ZERO_LOAD_ENDPOINT(DeviceData);
  959. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  960. ntStatus = STATUS_SUCCESS;
  961. goto OpenHCI_OpenEndpoint_Done;
  962. }
  963. //
  964. // Allocate resources for the endpoint, this includes an endpoint
  965. // handle that will be passed to us in subsequent transfer requests
  966. //
  967. endpoint = (PHCD_ENDPOINT)
  968. ExAllocatePoolWithTag(NonPagedPool,
  969. sizeof(HCD_ENDPOINT),
  970. OpenHCI_TAG);
  971. if (endpoint == NULL) {
  972. urb->UrbHeader.Status = USBD_STATUS_NO_MEMORY;
  973. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  974. goto OpenHCI_OpenEndpoint_Done;
  975. }
  976. //
  977. // Start initializing the endpoint structure
  978. //
  979. InitializeListHead(&endpoint->RequestQueue);
  980. endpoint->Sig = SIG_EP;
  981. endpoint->EpFlags = 0;
  982. endpoint->LowSpeed = FALSE;
  983. endpoint->Isochronous = FALSE;
  984. endpoint->Rate = endpointDescriptor->bInterval;
  985. // Initial conditon:
  986. // No active transfers
  987. // Max of two active transfers
  988. //
  989. endpoint->EndpointStatus = 0;
  990. endpoint->MaxRequest = 2;
  991. endpoint->AbortIrp = NULL;
  992. endpoint->Type =
  993. endpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK;
  994. if (DeviceData->HcFlags & HC_FLAG_SLOW_BULK_ENABLE &&
  995. endpoint->Type == USB_ENDPOINT_TYPE_BULK) {
  996. endpoint->MaxRequest = 1; // limit to only one transfer
  997. SET_EPFLAG(endpoint, EP_ONE_TD);
  998. }
  999. endpoint->ListIndex = ED_EOF; // not on a list yet
  1000. endpoint->Bandwidth = 0; // assume bulk or control
  1001. endpoint->DeviceData = DeviceData;
  1002. endpoint->Control = 0;
  1003. endpoint->HcdED = NULL;
  1004. endpoint->HcdHeadP = endpoint->HcdTailP = NULL;
  1005. endpoint->DescriptorsReserved = 0;
  1006. endpoint->TrueTail = NULL;
  1007. KeInitializeSpinLock(&endpoint->QueueLock);
  1008. SET_EPFLAG(endpoint, EP_VIRGIN);
  1009. endpoint->FunctionAddress = urb->HcdUrbOpenEndpoint.DeviceAddress;
  1010. endpoint->EndpointNumber = endpointDescriptor->bEndpointAddress;
  1011. if (endpoint->Type == USB_ENDPOINT_TYPE_CONTROL) {
  1012. endpoint->Direction = HcEDDirection_Defer;
  1013. } else if (endpointDescriptor->bEndpointAddress & 0x80) {
  1014. endpoint->Direction = HcEDDirection_In;
  1015. } else {
  1016. endpoint->Direction = HcEDDirection_Out;
  1017. }
  1018. if (urb->HcdUrbOpenEndpoint.HcdEndpointFlags & USBD_EP_FLAG_LOWSPEED) {
  1019. endpoint->LowSpeed = TRUE;
  1020. }
  1021. if (endpoint->Type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
  1022. endpoint->Isochronous = TRUE;
  1023. }
  1024. endpoint->MaxPacket = endpointDescriptor->wMaxPacketSize;
  1025. //
  1026. // Figure out how many descriptors we need to reserve
  1027. //
  1028. endpoint->MaxTransfer = urb->HcdUrbOpenEndpoint.MaxTransferSize;
  1029. if (endpoint->FunctionAddress != DeviceData->RootHubAddress) {
  1030. //
  1031. // This is an ordinary device endpoint...
  1032. //
  1033. // the goal here is to reserve enough TDs so that we can
  1034. // program the largest transfer to the hardware
  1035. //
  1036. if (endpoint->Type == USB_ENDPOINT_TYPE_ISOCHRONOUS)
  1037. {
  1038. ULONG packetSize;
  1039. ULONG maxTransfer;
  1040. ULONG msPerTransfer;
  1041. ULONG packetsPerTD;
  1042. maxTransfer = endpoint->MaxTransfer;
  1043. packetSize = endpoint->MaxPacket;
  1044. // Assume that the client driver sized the MaxTransferSize by
  1045. // multiplying the MaxPacketSize by the maximum number of frames
  1046. // the client driver would submit in a single request, so compute
  1047. // the maximun number of frames per request by dividing the
  1048. // MaxTransferSize by the MaxPacketSize.
  1049. //
  1050. msPerTransfer = maxTransfer / packetSize;
  1051. // Isoch transfers are limited to 255 packets per transfer.
  1052. //
  1053. if (msPerTransfer > 255)
  1054. {
  1055. msPerTransfer = 255;
  1056. }
  1057. // A TD can only span one page crossing. In the worst cast we
  1058. // can only fit a page worth of packets into a single TD to
  1059. // guarantee that there is only one page crossing.
  1060. //
  1061. // packetSize packetsPerTD (worst case)
  1062. // 1 - 512 8
  1063. // 513 - 585 7
  1064. // 586 - 682 6
  1065. // 683 - 819 5
  1066. // 820 - 1023 4
  1067. //
  1068. packetsPerTD = OHCI_PAGE_SIZE / packetSize;
  1069. // Regardless of the MaxPacketSize, a single TD is limited to
  1070. // eight packets.
  1071. //
  1072. if (packetsPerTD > 8)
  1073. {
  1074. packetsPerTD = 8;
  1075. }
  1076. // Calculate the number of TDs needed by dividing the maximum
  1077. // number of frames per transfer (rounded up) by the worst case
  1078. // miminum number of frames that will fit in a TD
  1079. //
  1080. tdsNeeded = (msPerTransfer + packetsPerTD - 1) / packetsPerTD;
  1081. LOGENTRY(G, 'rISO', tdsNeeded, packetSize, maxTransfer);
  1082. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_END_TRACE,
  1083. ("'reserve desc for iso ep (%d) pct siz = %d, max xfer = %d\n",
  1084. tdsNeeded, packetSize, maxTransfer));
  1085. // If the magic endpoint flag is set bump the MaxRequests
  1086. // all the way up to 32.
  1087. //
  1088. if (urb->HcdUrbOpenEndpoint.HcdEndpointFlags &
  1089. USBD_EP_FLAG_MAP_ADD_IO)
  1090. {
  1091. endpoint->MaxRequest = 32;
  1092. }
  1093. } else {
  1094. // we will need a TD for each page of data to transfer,
  1095. // worst case
  1096. tdsNeeded = (endpoint->MaxTransfer / (OHCI_PAGE_SIZE+1)) + 1;
  1097. // we need an xtra TD for the setup/status packet
  1098. if (endpoint->Type == USB_ENDPOINT_TYPE_CONTROL) {
  1099. tdsNeeded+=2;
  1100. }
  1101. }
  1102. // We need enough TDs to queue MaxRequest transfers plus:
  1103. // two EDs (why two EDs instead of one?), a dummy TD for the
  1104. // tail TD, and a spare (why?)
  1105. //
  1106. tdsNeeded = (tdsNeeded * endpoint->MaxRequest) + 4;
  1107. //
  1108. // pre-allocate the number of descriptors we will need
  1109. // for this endpoint
  1110. //
  1111. ntStatus = OpenHCI_ReserveDescriptors(DeviceData, tdsNeeded);
  1112. LOGENTRY(G, 'rTDS', endpoint, tdsNeeded, 0);
  1113. if (!NT_SUCCESS(ntStatus)) {
  1114. TEST_TRAP();
  1115. urb->UrbHeader.Status = USBD_STATUS_NO_MEMORY;
  1116. goto OpenHCI_OpenEndpoint_Done;
  1117. }
  1118. endpoint->DescriptorsReserved = tdsNeeded;
  1119. endpoint->Bandwidth =
  1120. (USHORT) USBD_CalculateUsbBandwidth(endpoint->MaxPacket,
  1121. endpoint->Type,
  1122. (BOOLEAN)endpoint->LowSpeed);
  1123. LOGENTRY(G, 'ndBW', endpoint, endpoint->Bandwidth, 0);
  1124. switch(endpoint->Type) {
  1125. case USB_ENDPOINT_TYPE_ISOCHRONOUS:
  1126. WhichList = ED_ISOCHRONOUS;
  1127. DeviceData->EDList[ED_ISOCHRONOUS].Bandwidth +=
  1128. endpoint->Bandwidth;
  1129. DeviceData->MaxBandwidthInUse += endpoint->Bandwidth;
  1130. break;
  1131. case USB_ENDPOINT_TYPE_INTERRUPT:
  1132. //
  1133. // Determine the scheduling period.
  1134. //
  1135. WhichList = ED_INTERRUPT_32ms;
  1136. while (WhichList >= endpoint->Rate && (WhichList >>= 1)) {
  1137. //
  1138. // Keep decrementing the schedule list until, the list
  1139. // chosen
  1140. // meets or exceeds the rate required by the endpoint.
  1141. //
  1142. continue;
  1143. }
  1144. //
  1145. // Determine which scheduling list has the least bandwidth
  1146. //
  1147. OpenHCI_CheckBandwidth(DeviceData, WhichList, &WhichList);
  1148. DeviceData->EDList[WhichList].Bandwidth += endpoint->Bandwidth;
  1149. //
  1150. // Recalculate the max bandwidth which is in use. This
  1151. // allows 1ms (isoc) pipe opens to occur with few calculation
  1152. //
  1153. DeviceData->MaxBandwidthInUse =
  1154. OpenHCI_CheckBandwidth(DeviceData,
  1155. ED_INTERRUPT_32ms,
  1156. NULL);
  1157. break;
  1158. case USB_ENDPOINT_TYPE_BULK:
  1159. WhichList = ED_BULK;
  1160. break;
  1161. case USB_ENDPOINT_TYPE_CONTROL:
  1162. WhichList = ED_CONTROL;
  1163. break;
  1164. }
  1165. endpoint->ListIndex = WhichList;
  1166. urb->HcdUrbOpenEndpoint.ScheduleOffset = WhichList;
  1167. //
  1168. // Verify the new max has not overcomitted the USB
  1169. //
  1170. LOGENTRY(G, 'vrBW', endpoint, DeviceData->MaxBandwidthInUse,
  1171. DeviceData->AvailableBandwidth);
  1172. if (DeviceData->MaxBandwidthInUse > DeviceData->AvailableBandwidth) {
  1173. //
  1174. // Too much, back this bandwidth out and fail the request
  1175. //
  1176. DeviceData->EDList[WhichList].Bandwidth -= endpoint->Bandwidth;
  1177. DeviceData->MaxBandwidthInUse =
  1178. OpenHCI_CheckBandwidth(DeviceData,
  1179. ED_INTERRUPT_32ms,
  1180. NULL);
  1181. //
  1182. // return a CAN_NOT_COMMIT_BANDWIDTH error.
  1183. urb->UrbHeader.Status = USBD_STATUS_NO_BANDWIDTH;
  1184. ntStatus = STATUS_UNSUCCESSFUL;
  1185. goto OpenHCI_OpenEndpoint_Done;
  1186. }
  1187. //
  1188. // Add to Host Controller schedule processing
  1189. //
  1190. // if lowspeed control and Hs/ls hack enabled
  1191. // put control transfers on the periodic list
  1192. if (endpoint->LowSpeed &&
  1193. DeviceData->HcFlags & HC_FLAG_USE_HYDRA_HACK &&
  1194. endpoint->ListIndex == ED_CONTROL) {
  1195. OpenHCI_KdPrint((1, "'*** do hs/ls fix for control ep\n"));
  1196. // put control on the interrupt list
  1197. endpoint->ListIndex = ED_INTERRUPT_1ms;
  1198. }
  1199. InsertEDForEndpoint(endpoint->DeviceData,
  1200. endpoint,
  1201. endpoint->ListIndex,
  1202. NULL);
  1203. OpenHCI_KdPrintDD(DeviceData,
  1204. OHCI_DBG_END_TRACE, ("'Open Endpoint:\n"));
  1205. } else {
  1206. //
  1207. // note that if the controller has lost power
  1208. // before the RH is started we need to restore the HC state
  1209. // before initializing the root hub.
  1210. //
  1211. if (DeviceData->HcFlags & HC_FLAG_LOST_POWER) {
  1212. BOOLEAN lostPower;
  1213. PHC_OPERATIONAL_REGISTER HC;
  1214. HC = DeviceData->HC;
  1215. // should only get here in the case where the
  1216. // HC looses power
  1217. //
  1218. OpenHCI_RestoreHCstate(DeviceData, &lostPower);
  1219. OHCI_ASSERT(lostPower == TRUE);
  1220. OpenHCI_Resume(DeviceObject, lostPower);
  1221. KeSetTimerEx(&DeviceData->DeadmanTimer,
  1222. RtlConvertLongToLargeInteger(-10000),
  1223. 10,
  1224. &DeviceData->DeadmanTimerDPC);
  1225. }
  1226. //
  1227. // This is an emulated Root Hub endpoint
  1228. //
  1229. SET_EPFLAG(endpoint, EP_ROOT_HUB);
  1230. if (endpoint->EndpointNumber == 1 &&
  1231. endpoint->Type == USB_ENDPOINT_TYPE_INTERRUPT) {
  1232. DeviceData->RootHubInterrupt = endpoint;
  1233. /*
  1234. * Note: if you open up two endpoints to the Interrupt endpoint
  1235. * of the root hub then the first one stops responding. But this
  1236. * is only fare as you should not open up two pipes to the same
  1237. * device and endpoint number.
  1238. */
  1239. } else {
  1240. DeviceData->RootHubControl = endpoint;
  1241. }
  1242. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_END_INFO,
  1243. ("'Open Endp (Root Hub Emulation)\n"));
  1244. }
  1245. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_END_INFO,
  1246. ("'ED: Type %d, Dir %d Addr %d FUNC Address %d LowSpeed %d\n",
  1247. endpoint->Type,
  1248. endpoint->Direction,
  1249. endpoint->EndpointNumber,
  1250. endpoint->FunctionAddress,
  1251. endpoint->LowSpeed));
  1252. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_END_INFO,
  1253. ("' MaxPacket %x Interval Requested %d List Selected %d\n",
  1254. endpoint->MaxPacket,
  1255. endpointDescriptor->bInterval,
  1256. endpoint->ListIndex));
  1257. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_END_INFO,
  1258. ("'*****HCD_ENDPOINT addr: 0x%08x HcdED: 0x%08x\n\n\n",
  1259. endpoint, endpoint->HcdED));
  1260. OpenHCI_OpenEndpoint_Done:
  1261. //
  1262. // Complete the IRP, status is in the status field of the URB
  1263. //
  1264. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_END_TRACE,
  1265. ("'exit OpenHCI_OpenEndpoint (URB STATUS = %x)\n",
  1266. urb->UrbHeader.Status));
  1267. if (NT_SUCCESS(ntStatus)) {
  1268. urb->HcdUrbOpenEndpoint.HcdEndpoint = endpoint;
  1269. } else {
  1270. ASSERT(endpoint != ZERO_LOAD_ENDPOINT(DeviceData));
  1271. if (endpoint) {
  1272. OpenHCI_UnReserveDescriptors(DeviceData,
  1273. endpoint->DescriptorsReserved);
  1274. OHCI_ASSERT(!(endpoint->EpFlags & EP_IN_ACTIVE_LIST));
  1275. ExFreePool(endpoint);
  1276. }
  1277. }
  1278. #if DBG
  1279. InterlockedDecrement(&DeviceData->OpenCloseSync);
  1280. #endif //DBG
  1281. LOGENTRY(G, 'opEP', endpoint, urb, ntStatus);
  1282. return ntStatus;
  1283. }
  1284. NTSTATUS
  1285. OpenHCI_CloseEndpoint(
  1286. IN PDEVICE_OBJECT DeviceObject,
  1287. IN PIRP Irp,
  1288. IN PHCD_DEVICE_DATA DeviceData,
  1289. IN OUT PHCD_URB urb
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. Free a OpenHCI endpoint, if there are any pending transfers for this
  1294. endpoint this routine should fail.
  1295. Arguments:
  1296. DeviceObject - pointer to a device object
  1297. Irp - pointer to an I/O Request Packet
  1298. Return Value:
  1299. If out of synchronous call with close and open
  1300. then return STATUS_DEVICE_BUSY otherwise
  1301. return STATUS_SUCCESS
  1302. --*/
  1303. {
  1304. PHCD_ENDPOINT endpoint = urb->HcdUrbCloseEndpoint.HcdEndpoint;
  1305. PHCD_ENDPOINT_DESCRIPTOR ed;
  1306. BOOLEAN outstandingTransfers, activeTransfers;
  1307. KIRQL irql;
  1308. NTSTATUS ntStatus = STATUS_SUCCESS;
  1309. BOOLEAN freeEP = TRUE;
  1310. // LARGE_INTEGER time;
  1311. OpenHCI_KdPrintDD(DeviceData,
  1312. OHCI_DBG_END_TRACE, ("'enter CloseEndpoint\n"));
  1313. LOGENTRY(G, 'rcEP', endpoint, urb, 0);
  1314. #if DBG
  1315. /* We are assuming that the caller of _OpenEndpoint and _Close endpoint
  1316. * make only serial calls. For this reason we will protect ourselves. If
  1317. * this is violated we return STATUS_DEVICE_BUSY. */
  1318. if (0 < InterlockedIncrement(&DeviceData->OpenCloseSync)) {
  1319. OpenHCI_KdTrap(("'ohciurb.c: _OpenEndpoint: Non serial call! %d",
  1320. DeviceData->OpenCloseSync));
  1321. urb->UrbHeader.Status = USBD_STATUS_INTERNAL_HC_ERROR;
  1322. ntStatus = STATUS_UNSUCCESSFUL;
  1323. goto CloseEndpoint_Done;
  1324. }
  1325. #endif // DBG
  1326. if (endpoint == ZERO_LOAD_ENDPOINT(DeviceData)) {
  1327. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  1328. ntStatus = STATUS_SUCCESS;
  1329. goto CloseEndpoint_Done;
  1330. }
  1331. ASSERT_ENDPOINT(endpoint);
  1332. // mark the endpoint as closed -- this prevents any more transers from
  1333. // being queued, if we fail the close we can clear the close flag.
  1334. // NOTE: if someone is sending transfers while we are closing they have a
  1335. // problem anyway this will just let us finish the close.
  1336. SET_EPFLAG(endpoint, EP_CLOSED);
  1337. OpenHCI_LockAndCheckEndpoint(endpoint,
  1338. &outstandingTransfers,
  1339. &activeTransfers,
  1340. &irql);
  1341. OpenHCI_UnlockEndpoint(endpoint, irql);
  1342. if (outstandingTransfers ||
  1343. activeTransfers) {
  1344. //
  1345. // fail if we have pending transfers,
  1346. // note: USBD should prevent this
  1347. //
  1348. // if we get here we probably have a problem somewhere
  1349. TRAP();
  1350. urb->UrbHeader.Status = USBD_STATUS_INTERNAL_HC_ERROR;
  1351. OpenHCI_KdPrintDD(DeviceData,
  1352. OHCI_DBG_END_ERROR,
  1353. ("'exit OutstandingTRANS OpenHCI_CloseEndpoint\n"));
  1354. ntStatus = STATUS_UNSUCCESSFUL;
  1355. goto CloseEndpoint_Done;
  1356. }
  1357. ed = endpoint->HcdED;
  1358. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_END_INFO,
  1359. ("'Closing Endpoint: %x\n", endpoint));
  1360. if (ed) {
  1361. KeAcquireSpinLock(&DeviceData->PausedSpin, &irql);
  1362. if (ed->PauseFlag != HCD_ED_PAUSE_NOT_PAUSED)
  1363. {
  1364. // This endpoint is paused.
  1365. //
  1366. // we are waiting for the CancelTDsForED to complete, we set a
  1367. // flag here that tells CancelTDsForED to call the remove ED
  1368. // function.
  1369. //
  1370. LOGENTRY(G, 'cle1', endpoint, ed, 0);
  1371. SET_EPFLAG(endpoint, EP_FREE);
  1372. KeReleaseSpinLock(&DeviceData->PausedSpin, irql);
  1373. OpenHCI_KdPrintDD(DeviceData,
  1374. OHCI_DBG_END_ERROR, ("'closing paused \n"));
  1375. freeEP = FALSE;
  1376. } else {
  1377. LOGENTRY(G, 'cle2', endpoint, ed, 0);
  1378. KeReleaseSpinLock(&DeviceData->PausedSpin, irql);
  1379. if (ED_EOF != endpoint->ListIndex) {
  1380. RemoveEDForEndpoint(endpoint);
  1381. freeEP = FALSE;
  1382. }
  1383. }
  1384. }
  1385. //
  1386. // we return our BW in RemoveEDForEndpoint
  1387. //
  1388. if (freeEP) {
  1389. ASSERT_ENDPOINT(endpoint);
  1390. // free our descriptors and endpoint
  1391. OpenHCI_UnReserveDescriptors(DeviceData, endpoint->DescriptorsReserved);
  1392. if (DeviceData->RootHubInterrupt == endpoint) {
  1393. DeviceData->RootHubInterrupt = NULL;
  1394. OpenHCI_KdPrintDD(DeviceData,
  1395. OHCI_DBG_END_TRACE, ("'closed RH interrupt\n"));
  1396. }
  1397. if (DeviceData->RootHubControl == endpoint) {
  1398. DeviceData->RootHubControl = NULL;
  1399. // root hub is no longer configured
  1400. DeviceData->RootHubConfig = 0;
  1401. OpenHCI_KdPrintDD(DeviceData,
  1402. OHCI_DBG_END_TRACE, ("'closed RH control\n"));
  1403. if (endpoint->FunctionAddress != 0) {
  1404. DeviceData->RootHubAddress = 0;
  1405. }
  1406. }
  1407. endpoint->Sig = 0;
  1408. OHCI_ASSERT(!(endpoint->EpFlags & EP_IN_ACTIVE_LIST));
  1409. ExFreePool(endpoint);
  1410. }
  1411. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  1412. CloseEndpoint_Done:
  1413. #if DBG
  1414. InterlockedDecrement(&DeviceData->OpenCloseSync);
  1415. if (!NT_SUCCESS(ntStatus)) {
  1416. // check why we are failing the close
  1417. TEST_TRAP();
  1418. }
  1419. #endif
  1420. LOGENTRY(G, 'clEP', 0, urb, ntStatus);
  1421. return ntStatus;
  1422. }
  1423. ULONG
  1424. Get32BitFrameNumber(
  1425. PHCD_DEVICE_DATA DeviceData
  1426. )
  1427. {
  1428. ULONG hp, fn, n;
  1429. /* This code accounts for the fact that HccaFrameNumber is updated by the
  1430. * HC before the HCD gets an interrupt that will adjust FrameHighPart. No
  1431. * synchronization is nescisary due to great cleaverness. */
  1432. hp = DeviceData->FrameHighPart;
  1433. fn = DeviceData->HCCA->HccaFrameNumber;
  1434. n = ((fn & 0x7FFF) | hp) + ((fn ^ hp) & 0x8000);
  1435. // Note: we can't log here because this function is called from the ISR
  1436. return n;
  1437. }
  1438. VOID
  1439. OpenHCI_PauseED(
  1440. IN PHCD_ENDPOINT Endpoint
  1441. )
  1442. /*++
  1443. Routine Description:
  1444. Processing of an endpoint by the HC must be paused before any
  1445. maintenance is performend on the TD list. This function first
  1446. sets the skip bit and then places the ED on a separate paused
  1447. list. At the next Start of Frame this ED can then be worked on.
  1448. Presumably the irq function will call CancelTDsForED on this
  1449. endpoint at that time.
  1450. Arguments:
  1451. Endpoint - then endpoint that need pausing.
  1452. --*/
  1453. {
  1454. PHCD_DEVICE_DATA DeviceData;
  1455. PHCD_ENDPOINT_DESCRIPTOR ed;
  1456. KIRQL oldirq;
  1457. PHC_OPERATIONAL_REGISTER HC;
  1458. ASSERT_ENDPOINT(Endpoint);
  1459. DeviceData = Endpoint->DeviceData;
  1460. HC = DeviceData->HC;
  1461. ed = Endpoint->HcdED;
  1462. OpenHCI_KdPrintDD(DeviceData,
  1463. OHCI_DBG_TD_NOISE, ("'Pausing Endpoint\n"));
  1464. LOGENTRY(G, 'Rpau', DeviceData, Endpoint, ed);
  1465. KeAcquireSpinLock(&DeviceData->PausedSpin, &oldirq);
  1466. // Are we already pasued?
  1467. //
  1468. if (ed->PauseFlag == HCD_ED_PAUSE_NOT_PAUSED)
  1469. {
  1470. // No, pause this endpoint
  1471. ed->HcED.sKip = TRUE;
  1472. // Clear any currently pending SOF interrupt
  1473. //
  1474. WRITE_REGISTER_ULONG(&HC->HcInterruptStatus, HcInt_StartOfFrame);
  1475. // It will be safe to operate on the endpoint in the next frame
  1476. //
  1477. ed->ReclamationFrame = Get32BitFrameNumber(DeviceData) + 1;
  1478. // Put this endpoint on the list of endpoints that OpenHCI_IsrDPC()
  1479. // should pass to OpenHCI_CancelTDsForED()
  1480. //
  1481. InsertTailList(&DeviceData->PausedEDRestart, &ed->PausedLink);
  1482. // Make sure SOF interrupts are enabled
  1483. //
  1484. WRITE_REGISTER_ULONG(&HC->HcInterruptEnable, HcInt_StartOfFrame);
  1485. LOGENTRY(G, 'paus', DeviceData, Endpoint, ed);
  1486. }
  1487. #if DBG
  1488. else {
  1489. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_TD_ERROR,
  1490. ("'Warning Endpoint already paused!\n"));
  1491. }
  1492. #endif
  1493. // Indicate that OpenHCI_CancelTDsForED() needs to make a pass through
  1494. // the requests queued on this endpoint.
  1495. //
  1496. ed->PauseFlag = HCD_ED_PAUSE_NEEDED;
  1497. KeReleaseSpinLock(&DeviceData->PausedSpin, oldirq);
  1498. return;
  1499. }
  1500. BOOLEAN
  1501. OpenHCI_HcControl_OR(
  1502. IN OUT PVOID Context
  1503. )
  1504. /*++
  1505. Routine Description:
  1506. This function is used in connection with KeSynchronizeExecution
  1507. to set the bits of the HcControl register which is accessed by
  1508. all function including the interrupt routine (not just the IsrDPC).
  1509. This function reads the CurrentHcControl field of the device
  1510. extension and ORs in the bits given by NewHcControl. It then
  1511. writes the results to the register.
  1512. Reads of the register take a long time so the value is cached.
  1513. Results:
  1514. This function modifies the input pointer to HC_CONTROL field
  1515. (PNewHcControl) to the result of the OR operation.
  1516. --*/
  1517. {
  1518. PHC_CONTROL newControl = &((PKeSynch_HcControl) Context)->NewHcControl;
  1519. PHCD_DEVICE_DATA DeviceData = ((PKeSynch_HcControl) Context)->DeviceData;
  1520. DeviceData->CurrentHcControl.ul
  1521. = READ_REGISTER_ULONG(&DeviceData->HC->HcControl.ul);
  1522. newControl->ul = (DeviceData->CurrentHcControl.ul |= newControl->ul);
  1523. WRITE_REGISTER_ULONG(&DeviceData->HC->HcControl.ul, newControl->ul);
  1524. return TRUE;
  1525. }
  1526. BOOLEAN
  1527. OpenHCI_HcControl_AND(
  1528. PVOID Context
  1529. )
  1530. /**
  1531. Routine Description:
  1532. OpenHCI_HcControl_OR with a twist.
  1533. --*/
  1534. {
  1535. PHC_CONTROL newControl = &((PKeSynch_HcControl) Context)->NewHcControl;
  1536. PHCD_DEVICE_DATA DeviceData = ((PKeSynch_HcControl) Context)->DeviceData;
  1537. DeviceData->CurrentHcControl.ul
  1538. = READ_REGISTER_ULONG(&DeviceData->HC->HcControl.ul);
  1539. newControl->ul = (DeviceData->CurrentHcControl.ul &= newControl->ul);
  1540. WRITE_REGISTER_ULONG(&DeviceData->HC->HcControl.ul, newControl->ul);
  1541. return TRUE;
  1542. }
  1543. BOOLEAN
  1544. OpenHCI_HcControl_SetHCFS(
  1545. PVOID Context
  1546. )
  1547. /**
  1548. Routine Description:
  1549. Mask out the Functional State in the HcControl register
  1550. and in its place put the ulong.
  1551. --*/
  1552. {
  1553. PHC_CONTROL newControl = &((PKeSynch_HcControl) Context)->NewHcControl;
  1554. PHCD_DEVICE_DATA DeviceData = ((PKeSynch_HcControl) Context)->DeviceData;
  1555. DeviceData->CurrentHcControl.ul
  1556. = READ_REGISTER_ULONG(&DeviceData->HC->HcControl.ul);
  1557. newControl->ul &= HcCtrl_HCFS_MASK;
  1558. DeviceData->CurrentHcControl.ul &= ~HcCtrl_HCFS_MASK;
  1559. newControl->ul = (DeviceData->CurrentHcControl.ul |= newControl->ul);
  1560. WRITE_REGISTER_ULONG(&DeviceData->HC->HcControl.ul, newControl->ul);
  1561. return TRUE;
  1562. }
  1563. BOOLEAN
  1564. OpenHCI_ListEnablesAtNextSOF(
  1565. PVOID Context
  1566. )
  1567. /**
  1568. Routine Description:
  1569. Set the ListEnablesAtNextSOF value in DeviceData so that when the
  1570. interrupt comes those lists will be enabled.
  1571. --*/
  1572. {
  1573. ((PKeSynch_HcControl) Context)->DeviceData->ListEnablesAtNextSOF.ul
  1574. = HcCtrl_ListEnableMask & ((PKeSynch_HcControl) Context)->
  1575. NewHcControl.ul;
  1576. return TRUE;
  1577. }
  1578.