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.

1310 lines
40 KiB

  1. /*++
  2. Copyright (c) 1999, 2000 Microsoft Corporation
  3. Module Name:
  4. periodic.c
  5. Abstract:
  6. miniport transfer code for interrupt endpoints
  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. /*
  20. For USB 2 period indicates a microframe polling interval so
  21. our tree structure is based on microframes.
  22. |- 1 ms frame -->|<--------- microframe ------------->|
  23. mic <32> <16> <08> <04> <02> <01>
  24. (table entry)
  25. [FRAME.MICROFRAME]
  26. [0.0] 0 ( 0) -\
  27. ( 0)-\
  28. [2.0] 16 ( 1) -/ \
  29. ( 0)-\
  30. [1.0] 8 ( 2) -\ / \
  31. ( 1)-/ \
  32. [3.0] 24 ( 3) -/ \
  33. (0)-\
  34. [0.4] 4 ( 4) -\ / \
  35. ( 2)-\ / \
  36. [2.4] 20 ( 5) -/ \ / \
  37. ( 1)-/ \
  38. [1.4] 12 ( 6) -\ / \
  39. ( 3)-/ \
  40. [3.4] 28 ( 7) -/ \
  41. (0)-\
  42. [0.2] 2 ( 8) -\ / \
  43. ( 4)-\ / \
  44. [2.2] 18 ( 9) -/ \ / \
  45. ( 2)-\ / \
  46. [1.2] 10 (10) -\ / \ / \
  47. ( 5)-/ \ / \
  48. [3.2] 26 (11) -/ \ / \
  49. (1)-/ \
  50. [0.6] 6 (12) -\ / \
  51. ( 6)-\ / \
  52. [2.6] 22 (13) -/ \ / \
  53. ( 3)-/ \
  54. [1.6] 14 (14) -\ / \
  55. ( 7)-/ \
  56. [3.6] 30 (15) -/ \
  57. (0)
  58. [0.1] 1 (16) -\ /
  59. ( 8)-\ /
  60. [2.1] 17 (17) -/ \ /
  61. ( 4)-\ /
  62. [1.1] 9 (18) -\ / \ /
  63. ( 9)-/ \ /
  64. [3.1] 25 (19) -/ \ /
  65. (2)-\ /
  66. [0.5] 5 (20) -\ / \ /
  67. (10)-\ / \ /
  68. [2.5] 21 (21) -/ \ / \ /
  69. ( 5)-/ \ /
  70. [1.5] 13 (22) -\ / \ /
  71. (11)-/ \ /
  72. [3.5] 29 (23) -/ \ /
  73. (1)-/
  74. [0.3] 3 (24) -\ /
  75. (12)-\ /
  76. [2.3] 19 (25) -/ \ /
  77. ( 6)-\ /
  78. [1.3] 11 (26) -\ / \ /
  79. (13)-/ \ /
  80. [3.3] 27 (27) -/ \ /
  81. (3)-/
  82. [0.7] 7 (28) -\ /
  83. (14)-\ /
  84. [2.7] 23 (29) -/ \ /
  85. ( 7)-/
  86. [1.7] 15 (30) -\ /
  87. (15)-/
  88. [3.7] 31 (31) -/
  89. Allocations:
  90. period.offset table entries
  91. 1 0, 1, 2.........31
  92. 2.0 0, 1, 2.........15
  93. 2.1 16,17,18.........31
  94. 4.0 0, 1, 2..........7
  95. 4.1 8, 9,10.........15
  96. 4.2 16,17,18.........23
  97. 4.3 24,25,26.........31
  98. 8.0 0, 1, 2, 3
  99. 8.1 4, 5, 6, 7
  100. 8.2 8, 9,10,11
  101. 8.3 12,13,14,15
  102. 8.4 16,17,18,19
  103. 8.5 20,21,22,23
  104. 8.6 24,25,26,27
  105. 8.7 28,29,30,31
  106. ...
  107. we mainatin a set of dummy queue heads that correspond to the 1ms nodes
  108. in the chart above.
  109. the queue head table has 4 entries QH 0..3
  110. frame mic frame qh
  111. 0 0..7 <0>
  112. 1 0..7 <1>
  113. driver maintains a mini tree that has seven QHs that are placed in the
  114. schedule.
  115. period frame(microframes)
  116. 32(4) 16(2) 1(8)
  117. frame
  118. 0 (a 0) -\
  119. (e 0)-\
  120. 2 (b 1) -/ \
  121. (g 0)-
  122. 1 (c 2) -\ /
  123. (f 1)-/
  124. 3 (d 3) -/
  125. idx QH frame
  126. 0 a 0
  127. 1 b 2
  128. 2 c 1
  129. 3 d 3
  130. 4 e 0,2
  131. 5 f 1,3
  132. 6 g 0,2,1,3
  133. */
  134. /*
  135. We represent each possible node in the tree with a data structure that decodes
  136. the appropriate queue head and S-Mask for the node
  137. *e.g
  138. for period 8 microframe, sched offset 0 QH = g s-mask = 1
  139. // The structure contains entries for the 64 possible nodes
  140. // plus the static ED for bulk and control (2) each entry
  141. // corresponds to the period in the following table.
  142. //
  143. // the array looks like this:
  144. // 1, 2, 2, 4, 4, 4, 4, 8,
  145. // 8, 8, 8, 8, 8, 8, 8,16,
  146. // 16,16,16,16,16,16,16,16,
  147. // 16,16,16,16,16,16,16,32,
  148. // 32,32,32,32,32,32,32,32,
  149. // 32,32,32,32,32,32,32,32,
  150. // 32,32,32,32,32,32,32,32,
  151. // 32,32,32,32,32,32,32,
  152. queue heads used for high speed
  153. 0 (3) -\
  154. (1)-\
  155. 2 (4) -/ \
  156. (0)-
  157. 1 (5) -\ /
  158. (2)-/
  159. 3 (6) -/
  160. */
  161. /* offsets for each period list */
  162. #define ED_INTERRUPT_1mf 0 //period = 1mf
  163. #define ED_INTERRUPT_2mf 1 //period = 2mf
  164. #define ED_INTERRUPT_4mf 3 //period = 4mf
  165. #define ED_INTERRUPT_8mf 7 //period = 8mf
  166. #define ED_INTERRUPT_16mf 15 //period = 16mf
  167. #define ED_INTERRUPT_32mf 31 //period = 32mf
  168. #define ED_INTERRUPT_1ms 0 //period = 1ms
  169. #define ED_INTERRUPT_2ms 1 //period = 2ms
  170. #define ED_INTERRUPT_4ms 3 //period = 4ms
  171. #define ED_INTERRUPT_8ms 7 //period = 8ms
  172. #define ED_INTERRUPT_16ms 15 //period = 16ms
  173. #define ED_INTERRUPT_32ms 31 //period = 32ms
  174. PERIOD_TABLE periodTable[64] =
  175. { // period, qh-idx, s-mask
  176. 1, 0, 0xFF, // 1111 1111 bits 0..7
  177. 2, 0, 0x55, // 0101 0101 bits 0,2,4,6
  178. 2, 0, 0xAA, // 1010 1010 bits 1,3,5,7
  179. 4, 0, 0x11, // 0001 0001 bits 0,4
  180. 4, 0, 0x44, // 0100 0100 bits 2,6
  181. 4, 0, 0x22, // 0010 0010 bits 1,5
  182. 4, 0, 0x88, // 1000 1000 bits 3,7
  183. 8, 0, 0x01, // 0000 0001 bits 0
  184. 8, 0, 0x10, // 0001 0000 bits 4
  185. 8, 0, 0x04, // 0000 0100 bits 2
  186. 8, 0, 0x40, // 0100 0000 bits 6
  187. 8, 0, 0x02, // 0000 0010 bits 1
  188. 8, 0, 0x20, // 0010 0000 bits 5
  189. 8, 0, 0x08, // 0000 1000 bits 3
  190. 8, 0, 0x80, // 1000 0000 bits 7
  191. 16, 1, 0x01, // 0000 0001 bits 0
  192. 16, 2, 0x01, // 0000 0001 bits 0
  193. 16, 1, 0x10, // 0001 0000 bits 4
  194. 16, 2, 0x10, // 0001 0000 bits 4
  195. 16, 1, 0x04, // 0000 0100 bits 2
  196. 16, 2, 0x04, // 0000 0100 bits 2
  197. 16, 1, 0x40, // 0100 0000 bits 6
  198. 16, 2, 0x40, // 0100 0000 bits 6
  199. 16, 1, 0x02, // 0000 0010 bits 1
  200. 16, 2, 0x02, // 0000 0010 bits 1
  201. 16, 1, 0x20, // 0010 0000 bits 5
  202. 16, 2, 0x20, // 0010 0000 bits 5
  203. 16, 1, 0x08, // 0000 1000 bits 3
  204. 16, 2, 0x08, // 0000 1000 bits 3
  205. 16, 1, 0x80, // 1000 0000 bits 7
  206. 16, 2, 0x80, // 1000 0000 bits 7
  207. 32, 3, 0x01, // 0000 0000 bits 0
  208. 32, 5, 0x01, // 0000 0000 bits 0
  209. 32, 4, 0x01, // 0000 0000 bits 0
  210. 32, 6, 0x01, // 0000 0000 bits 0
  211. 32, 3, 0x10, // 0000 0000 bits 4
  212. 32, 5, 0x10, // 0000 0000 bits 4
  213. 32, 4, 0x10, // 0000 0000 bits 4
  214. 32, 6, 0x10, // 0000 0000 bits 4
  215. 32, 3, 0x04, // 0000 0000 bits 2
  216. 32, 5, 0x04, // 0000 0000 bits 2
  217. 32, 4, 0x04, // 0000 0000 bits 2
  218. 32, 6, 0x04, // 0000 0000 bits 2
  219. 32, 3, 0x40, // 0000 0000 bits 6
  220. 32, 5, 0x40, // 0000 0000 bits 6
  221. 32, 4, 0x40, // 0000 0000 bits 6
  222. 32, 6, 0x40, // 0000 0000 bits 6
  223. 32, 3, 0x02, // 0000 0000 bits 1
  224. 32, 5, 0x02, // 0000 0000 bits 1
  225. 32, 4, 0x02, // 0000 0000 bits 1
  226. 32, 6, 0x02, // 0000 0000 bits 1
  227. 32, 3, 0x20, // 0000 0000 bits 5
  228. 32, 5, 0x20, // 0000 0000 bits 5
  229. 32, 4, 0x20, // 0000 0000 bits 5
  230. 32, 6, 0x20, // 0000 0000 bits 5
  231. 32, 3, 0x04, // 0000 0000 bits 3
  232. 32, 5, 0x04, // 0000 0000 bits 3
  233. 32, 4, 0x04, // 0000 0000 bits 3
  234. 32, 6, 0x04, // 0000 0000 bits 3
  235. 32, 3, 0x40, // 0000 0000 bits 7
  236. 32, 5, 0x40, // 0000 0000 bits 7
  237. 32, 4, 0x40, // 0000 0000 bits 7
  238. 32, 6, 0x40, // 0000 0000 bits 7
  239. };
  240. VOID
  241. EHCI_EnablePeriodicList(
  242. PDEVICE_DATA DeviceData
  243. )
  244. /*++
  245. Routine Description:
  246. Arguments:
  247. Return Value:
  248. --*/
  249. {
  250. PHC_OPERATIONAL_REGISTER hcOp;
  251. USBCMD cmd;
  252. hcOp = DeviceData->OperationalRegisters;
  253. cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
  254. cmd.PeriodicScheduleEnable = 1;
  255. WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul,
  256. cmd.ul);
  257. LOGENTRY(DeviceData, G, '_enP', cmd.ul, 0, 0);
  258. }
  259. UCHAR ClassicPeriodIdx[8] = {
  260. ED_INTERRUPT_1ms, //period = 1ms
  261. ED_INTERRUPT_2ms, //period = 2ms
  262. ED_INTERRUPT_4ms, //period = 4ms
  263. ED_INTERRUPT_8ms, //period = 8ms
  264. ED_INTERRUPT_16ms,//period = 16ms
  265. ED_INTERRUPT_32ms,//period = 32ms
  266. ED_INTERRUPT_32ms,//period = 64ms
  267. ED_INTERRUPT_32ms //period = 128ms
  268. };
  269. USB_MINIPORT_STATUS
  270. EHCI_OpenInterruptEndpoint(
  271. PDEVICE_DATA DeviceData,
  272. PENDPOINT_PARAMETERS EndpointParameters,
  273. OUT PENDPOINT_DATA EndpointData
  274. )
  275. /*++
  276. Routine Description:
  277. Arguments:
  278. Return Value:
  279. --*/
  280. {
  281. PUCHAR buffer;
  282. HW_32BIT_PHYSICAL_ADDRESS phys, qhPhys;
  283. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  284. ULONG i;
  285. ULONG tdCount, bytes, offset;
  286. PPERIOD_TABLE periodTableEntry;
  287. BOOLEAN classic;
  288. PHCD_TRANSFER_DESCRIPTOR dummyTd;
  289. UCHAR periodIdx[8] = {
  290. ED_INTERRUPT_1mf, //period = 1mf
  291. ED_INTERRUPT_2mf, //period = 2mf
  292. ED_INTERRUPT_4mf, //period = 4mf
  293. ED_INTERRUPT_8mf, //period = 8mf
  294. ED_INTERRUPT_16mf,//period = 16mf
  295. ED_INTERRUPT_32mf,//period = 32mf
  296. ED_INTERRUPT_32mf,//period = 64mf
  297. ED_INTERRUPT_32mf //period = 128mf
  298. };
  299. classic =
  300. (EndpointData->Parameters.DeviceSpeed != HighSpeed) ? TRUE : FALSE;
  301. LOGENTRY(DeviceData, G, '_opI', EndpointData, EndpointParameters, classic);
  302. // select the proper list
  303. // the period is a power of 2 ie
  304. // 32,16,8,4,2,1
  305. // we just need to find which bit is set
  306. GET_BIT_SET(EndpointParameters->Period, i);
  307. EHCI_ASSERT(DeviceData, i < 8);
  308. EHCI_ASSERT(DeviceData, EndpointParameters->Period < 64);
  309. InitializeListHead(&EndpointData->DoneTdList);
  310. buffer = EndpointParameters->CommonBufferVa;
  311. phys = EndpointParameters->CommonBufferPhys;
  312. offset = EndpointParameters->ScheduleOffset;
  313. if (classic) {
  314. i = ClassicPeriodIdx[i];
  315. periodTableEntry = NULL;
  316. } else {
  317. i = periodIdx[i];
  318. periodTableEntry = &periodTable[i+offset];
  319. }
  320. LOGENTRY(DeviceData, G, '_iep', EndpointData,
  321. periodTableEntry, i);
  322. // locate the appropriate queue head and period
  323. // table entry
  324. if (classic) {
  325. EndpointData->StaticQH =
  326. DeviceData->StaticInterruptQH[i+offset];
  327. EndpointData->PeriodTableEntry = NULL;
  328. } else {
  329. EndpointData->StaticQH =
  330. DeviceData->StaticInterruptQH[periodTableEntry->qhIdx];
  331. EndpointData->PeriodTableEntry = periodTableEntry;
  332. }
  333. // how much did we get
  334. bytes = EndpointParameters->CommonBufferBytes;
  335. EndpointData->QhChkPhys = phys;
  336. EndpointData->QhChk = buffer;
  337. RtlZeroMemory(buffer, 256);
  338. phys += 256;
  339. buffer += 256;
  340. bytes -= 256;
  341. // make the Ed
  342. qh = (PHCD_QUEUEHEAD_DESCRIPTOR) buffer;
  343. qhPhys = phys;
  344. phys += sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
  345. buffer += sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
  346. bytes -= sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
  347. tdCount = bytes/sizeof(HCD_TRANSFER_DESCRIPTOR);
  348. EHCI_ASSERT(DeviceData, tdCount >= TDS_PER_INTERRUPT_ENDPOINT);
  349. EndpointData->TdList = (PHCD_TD_LIST) buffer;
  350. EndpointData->TdCount = tdCount;
  351. for (i=0; i<tdCount; i++) {
  352. EHCI_InitializeTD(DeviceData,
  353. EndpointData,
  354. &EndpointData->TdList->Td[i],
  355. phys);
  356. phys += sizeof(HCD_TRANSFER_DESCRIPTOR);
  357. }
  358. EndpointData->FreeTds = tdCount;
  359. EndpointData->QueueHead =
  360. EHCI_InitializeQH(DeviceData,
  361. EndpointData,
  362. qh,
  363. qhPhys);
  364. if (classic) {
  365. // use mask parameters passed to us
  366. qh->HwQH.EpCaps.InterruptScheduleMask =
  367. EndpointParameters->InterruptScheduleMask;
  368. qh->HwQH.EpCaps.SplitCompletionMask =
  369. EndpointParameters->SplitCompletionMask;
  370. } else {
  371. qh->HwQH.EpCaps.InterruptScheduleMask =
  372. periodTableEntry->InterruptScheduleMask;
  373. }
  374. // init our polling variables
  375. dummyTd = EHCI_ALLOC_TD(DeviceData, EndpointData);
  376. dummyTd->HwTD.Next_qTD.HwAddress = EHCI_TERMINATE_BIT;
  377. TRANSFER_DESCRIPTOR_PTR(dummyTd->NextHcdTD) = NULL;
  378. dummyTd->HwTD.AltNext_qTD.HwAddress = EHCI_TERMINATE_BIT;
  379. TRANSFER_DESCRIPTOR_PTR(dummyTd->AltNextHcdTD) = NULL;
  380. dummyTd->HwTD.Token.Active = 0;
  381. SET_FLAG(dummyTd->Flags, TD_FLAG_DUMMY);
  382. EndpointData->DummyTd = dummyTd;
  383. EndpointData->HcdHeadP = dummyTd;
  384. // endpoint is not active, set up the overlay
  385. // so that the currentTD is the Dummy
  386. qh->HwQH.CurrentTD.HwAddress = dummyTd->PhysicalAddress;
  387. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress = EHCI_TERMINATE_BIT;
  388. qh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress = EHCI_TERMINATE_BIT;
  389. qh->HwQH.Overlay.qTD.Token.BytesToTransfer = 0;
  390. qh->HwQH.Overlay.qTD.Token.Active = 0;
  391. return USBMP_STATUS_SUCCESS;
  392. }
  393. VOID
  394. EHCI_InsertQueueHeadInPeriodicList(
  395. PDEVICE_DATA DeviceData,
  396. PENDPOINT_DATA EndpointData
  397. )
  398. /*++
  399. Routine Description:
  400. Insert an interrupt endpoint into the h/w schedule
  401. Arguments:
  402. --*/
  403. {
  404. PHCD_QUEUEHEAD_DESCRIPTOR staticQH, qh, nxtQH, prvQH;
  405. HW_LINK_POINTER hLink;
  406. staticQH = EndpointData->StaticQH;
  407. qh = EndpointData->QueueHead;
  408. EHCI_ASSERT(DeviceData,
  409. TEST_FLAG(staticQH->QhFlags, EHCI_QH_FLAG_STATIC));
  410. EHCI_ASSERT(DeviceData,
  411. !TEST_FLAG(qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE));
  412. nxtQH = QH_DESCRIPTOR_PTR(staticQH->NextQh);
  413. prvQH = staticQH;
  414. // Note: This function must be coherent with the budgeter code
  415. // the budgeter inserts endpoints such that the newer endpoints
  416. // are at the end of the sublist, older are at the begining. The
  417. // lower the ordinal value the older the endpoint. The ordinal
  418. // values are used to maintain the same ordering in the event the
  419. // schedule must be reconstructed
  420. // hook this queue head to the the static
  421. // queue head list, two cases
  422. // case 1:
  423. // insert QH1, queue head list is not empty:
  424. //
  425. // |staticQH|<->QH2<->QH3<->|staticQH|<->QH4
  426. //
  427. // |staticQH|<->QH2<->QH3<->QH1<->|staticQH|<->QH4
  428. // (o=1) (o=2) (o=3)
  429. // for case one qeue must insert the queue head in the list
  430. // based on the ordinal value we need to compute prev and
  431. // next
  432. // case 2:
  433. // insert QH1, queue head sublist is empty
  434. //
  435. // |staticQH|<->|staticQH|<->QH4
  436. //
  437. // |staticQH|<->QH1<->|staticQH|<->QH4
  438. LOGENTRY(DeviceData, G, '_inQ', EndpointData, qh, staticQH);
  439. // find the correct spot
  440. // prvQH, nxtQH are currently the beginnig and end of the
  441. // sublist
  442. qh->Ordinal = EndpointData->Parameters.Ordinal;
  443. qh->Period = EndpointData->Parameters.Period;
  444. if (TEST_FLAG(prvQH->QhFlags, EHCI_QH_FLAG_STATIC) &&
  445. (nxtQH == NULL || TEST_FLAG(nxtQH->QhFlags, EHCI_QH_FLAG_STATIC))) {
  446. // case 2 qh list is empty
  447. LOGENTRY(DeviceData, G, '_iq1', prvQH, 0, nxtQH);
  448. } else {
  449. // case 1 qh list is not empty
  450. // find the correct position based on ordinal
  451. while (nxtQH != NULL &&
  452. !TEST_FLAG(nxtQH->QhFlags, EHCI_QH_FLAG_STATIC) &&
  453. qh->Ordinal > nxtQH->Ordinal) {
  454. prvQH = nxtQH;
  455. nxtQH = QH_DESCRIPTOR_PTR(prvQH->NextQh);
  456. }
  457. //if (nxtQH != NULL &&
  458. // !TEST_FLAG(nxtQH->QhFlags, EHCI_QH_FLAG_STATIC)) {
  459. // // middle insertion
  460. // TEST_TRAP();
  461. //}
  462. }
  463. // do the insertion
  464. QH_DESCRIPTOR_PTR(qh->NextQh) = nxtQH;
  465. QH_DESCRIPTOR_PTR(qh->PrevQh) = prvQH;
  466. // next link points back
  467. if (nxtQH != NULL &&
  468. !TEST_FLAG(nxtQH->QhFlags, EHCI_QH_FLAG_STATIC)) {
  469. QH_DESCRIPTOR_PTR(nxtQH->PrevQh) = qh;
  470. }
  471. // prev points to new qh
  472. QH_DESCRIPTOR_PTR(prvQH->NextQh) = qh;
  473. // now link to HW,order of operation is
  474. // important here
  475. hLink.HwAddress = qh->PhysicalAddress;
  476. SET_QH(hLink.HwAddress);
  477. qh->HwQH.HLink = prvQH->HwQH.HLink;
  478. prvQH->HwQH.HLink = hLink;
  479. SET_FLAG(qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE);
  480. }
  481. VOID
  482. EHCI_RemoveQueueHeadFromPeriodicList(
  483. PDEVICE_DATA DeviceData,
  484. PENDPOINT_DATA EndpointData
  485. )
  486. /*++
  487. Routine Description:
  488. remove an interrupt endpoint into from the h/w schedule
  489. Arguments:
  490. --*/
  491. {
  492. PHCD_QUEUEHEAD_DESCRIPTOR staticQH, qh, prevQH, nextQH;
  493. HW_LINK_POINTER hLink;
  494. staticQH = EndpointData->StaticQH;
  495. qh = EndpointData->QueueHead;
  496. if (!TEST_FLAG(qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE)) {
  497. return;
  498. }
  499. LOGENTRY(DeviceData, G, '_rmQ', EndpointData, qh, staticQH);
  500. // remove the queue head
  501. // remove QH2, two cases
  502. // |staticQH|<->QH1<->QH2<->QH3<->|staticQH|<->QH4
  503. //
  504. // |staticQH|<->QH1<->QH3<->|staticQH|<->QH4
  505. prevQH = QH_DESCRIPTOR_PTR(qh->PrevQh);
  506. nextQH = QH_DESCRIPTOR_PTR(qh->NextQh);
  507. // unlink next ptrs
  508. QH_DESCRIPTOR_PTR(prevQH->NextQh) = nextQH;
  509. if (nextQH != NULL &&
  510. !TEST_FLAG(nextQH->QhFlags, EHCI_QH_FLAG_STATIC)) {
  511. QH_DESCRIPTOR_PTR(nextQH->PrevQh) = prevQH;
  512. }
  513. // hw unlink, nextqh will be null if this is period 1ms
  514. // qh
  515. if (nextQH == NULL) {
  516. hLink.HwAddress = 0;
  517. SET_T_BIT(hLink.HwAddress);
  518. } else {
  519. hLink.HwAddress = nextQH->PhysicalAddress;
  520. SET_QH(hLink.HwAddress);
  521. }
  522. prevQH->HwQH.HLink = hLink;
  523. CLEAR_FLAG(qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE);
  524. QH_DESCRIPTOR_PTR(qh->NextQh) = NULL;
  525. QH_DESCRIPTOR_PTR(qh->PrevQh) = NULL;
  526. }
  527. USB_MINIPORT_STATUS
  528. EHCI_InterruptTransfer(
  529. PDEVICE_DATA DeviceData,
  530. PENDPOINT_DATA EndpointData,
  531. PTRANSFER_PARAMETERS TransferUrb,
  532. PTRANSFER_CONTEXT TransferContext,
  533. PTRANSFER_SG_LIST TransferSGList
  534. )
  535. /*++
  536. Routine Description:
  537. Initialize interrupt Transfer
  538. NOTES:
  539. HW pointers nextTD and AltNextTD are shadowed in
  540. NextHcdTD and AltNextHcdTD.
  541. Arguments:
  542. --*/
  543. {
  544. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  545. PHCD_TRANSFER_DESCRIPTOR firstTd, prevTd, td;
  546. ULONG lengthMapped;
  547. // if we have enough TDs do the transfer
  548. if (EndpointData->FreeTds == 0) {
  549. TEST_TRAP();
  550. LOGENTRY(DeviceData, G, '_IIS', EndpointData, TransferUrb, 0);
  551. return USBMP_STATUS_BUSY;
  552. }
  553. EndpointData->PendingTransfers++;
  554. // if we have enough tds, program the transfer
  555. LOGENTRY(DeviceData, G, '_IIT', EndpointData, TransferUrb, 0);
  556. lengthMapped = 0;
  557. prevTd = NULL;
  558. while (lengthMapped < TransferUrb->TransferBufferLength) {
  559. TransferContext->PendingTds++;
  560. td = EHCI_ALLOC_TD(DeviceData, EndpointData);
  561. INITIALIZE_TD_FOR_TRANSFER(td, TransferContext);
  562. if (TransferContext->PendingTds == 1) {
  563. firstTd = td;
  564. } else if (prevTd) {
  565. SET_NEXT_TD(DeviceData, prevTd, td);
  566. }
  567. //
  568. // fields for data TD
  569. //
  570. // use direction specified in transfer
  571. if (TEST_FLAG(TransferUrb->TransferFlags, USBD_TRANSFER_DIRECTION_IN)) {
  572. td->HwTD.Token.Pid = HcTOK_In;
  573. } else {
  574. td->HwTD.Token.Pid = HcTOK_Out;
  575. }
  576. td->HwTD.Token.DataToggle = HcTOK_Toggle1;
  577. td->HwTD.Token.Active = 1;
  578. LOGENTRY(DeviceData,
  579. G, '_dta', td, lengthMapped, TransferUrb->TransferBufferLength);
  580. lengthMapped =
  581. EHCI_MapAsyncTransferToTd(DeviceData,
  582. EndpointData->Parameters.MaxPacketSize,
  583. lengthMapped,
  584. NULL,
  585. TransferContext,
  586. td,
  587. TransferSGList);
  588. prevTd = td;
  589. }
  590. // interrupt on the last TD
  591. td->HwTD.Token.InterruptOnComplete = 1;
  592. // put the request on the hardware queue
  593. LOGENTRY(DeviceData, G,
  594. '_Tal', TransferContext->PendingTds, td->PhysicalAddress, firstTd);
  595. // td points to last TD in this transfer, point it at the dummy
  596. SET_NEXT_TD(DeviceData, td, EndpointData->DummyTd);
  597. EHCI_LinkTransferToQueue(DeviceData,
  598. EndpointData,
  599. firstTd);
  600. ASSERT_DUMMY_TD(DeviceData, EndpointData->DummyTd);
  601. // tell the hc we have periodic transfers available
  602. EHCI_EnablePeriodicList(DeviceData);
  603. return USBMP_STATUS_SUCCESS;
  604. }
  605. /*
  606. CLASSIC
  607. The classic tree has 63 possible nodes, usport bw manager will select the
  608. appropriate node based on a 'classic' bus.
  609. usbport maintains bandwidth management for each classic bus, however
  610. budgeting the microframes is left to the miniport.
  611. classic 1ms interrupt schedule, NOTE:this schedule shares some queue heads with
  612. the hish speed schedule.
  613. * = shared queue head
  614. fr <32> <16> <08> <04> <02> <01>
  615. 0 ( 0) -\
  616. ( 0)-\
  617. 16 ( 1) -/ \
  618. ( 0)-\
  619. 8 ( 2) -\ / \
  620. ( 1)-/ \
  621. 24 ( 3) -/ \
  622. *(0)-\
  623. 4 ( 4) -\ / \
  624. ( 2)-\ / \
  625. 20 ( 5) -/ \ / \
  626. ( 1)-/ \
  627. 12 ( 6) -\ / \
  628. ( 3)-/ \
  629. 28 ( 7) -/ \
  630. *(0)-\
  631. 2 ( 8) -\ / \
  632. ( 4)-\ / \
  633. 18 ( 9) -/ \ / \
  634. ( 2)-\ / \
  635. 10 (10) -\ / \ / \
  636. ( 5)-/ \ / \
  637. 26 (11) -/ \ / \
  638. *(1)-/ \
  639. 6 (12) -\ / \
  640. ( 6)-\ / \
  641. 22 (13) -/ \ / \
  642. ( 3)-/ \
  643. 14 (14) -\ / \
  644. ( 7)-/ \
  645. 30 (15) -/ \
  646. *(0)
  647. 1 (16) -\ /
  648. ( 8)-\ /
  649. 17 (17) -/ \ /
  650. ( 4)-\ /
  651. 9 (18) -\ / \ /
  652. ( 9)-/ \ /
  653. 25 (19) -/ \ /
  654. *(2)-\ /
  655. 5 (20) -\ / \ /
  656. (10)-\ / \ /
  657. 21 (21) -/ \ / \ /
  658. ( 5)-/ \ /
  659. 13 (22) -\ / \ /
  660. (11)-/ \ /
  661. 29 (23) -/ \ /
  662. *(1)-/
  663. 3 (24) -\ /
  664. (12)-\ /
  665. 19 (25) -/ \ /
  666. ( 6)-\ /
  667. 11 (26) -\ / \ /
  668. (13)-/ \ /
  669. 27 (27) -/ \ /
  670. *(3)-/
  671. 7 (28) -\ /
  672. (14)-\ /
  673. 23 (29) -/ \ /
  674. ( 7)-/
  675. 15 (30) -\ /
  676. (15)-/
  677. 31 (31) -/
  678. The node table is arrangened in the standard usb 1.1 fashion so that
  679. the schedule offset passed to us by the budget engine applies
  680. // the static array looks like this:
  681. // 1, 2, 2, 4, 4, 4, 4, 8,
  682. // 8, 8, 8, 8, 8, 8, 8,16,
  683. // 16,16,16,16,16,16,16,16,
  684. // 16,16,16,16,16,16,16,32,
  685. // 32,32,32,32,32,32,32,32,
  686. // 32,32,32,32,32,32,32,32,
  687. // 32,32,32,32,32,32,32,32,
  688. // 32,32,32,32,32,32,32,
  689. CLASSIC BUDGET
  690. The classic budget is maintained by the port driver we
  691. simply need to program the endpoint at the appropriate
  692. offset (node) with the given smask cmask
  693. period(ms) queue head(index)
  694. 1 0
  695. 2 1
  696. 2 2
  697. 4 3
  698. 4 4
  699. 4 5
  700. 4 6
  701. 8 7
  702. 8 8
  703. 8 9
  704. 8 10
  705. 8 11
  706. 8 12
  707. 8 13
  708. 8 14
  709. */
  710. UCHAR EHCI_Frame2Qhead[32] = {
  711. /*
  712. offset ms frame
  713. */
  714. 0, // 0
  715. 16,// 1
  716. 8, // 2
  717. 24,// 3
  718. 4, // 4
  719. 20,// 5
  720. 12,// 6
  721. 28,// 7
  722. 2, // 8
  723. 18,// 9
  724. 10,// 10
  725. 26,// 11
  726. 6, // 12
  727. 22,// 13
  728. 14,// 14
  729. 30,// 15
  730. 1, // 16
  731. 17,// 17
  732. 9, // 18
  733. 25,// 19
  734. 5, // 20
  735. 21,// 21
  736. 13,// 22
  737. 29,// 23
  738. 3, // 24
  739. 19,// 25
  740. 11,// 26
  741. 27,// 27
  742. 7, // 28
  743. 23,// 29
  744. 15,// 30
  745. 31,// 31
  746. };
  747. PHCD_QUEUEHEAD_DESCRIPTOR
  748. EHCI_GetQueueHeadForFrame(
  749. PDEVICE_DATA DeviceData,
  750. ULONG Frame
  751. )
  752. /*++
  753. Routine Description:
  754. Arguments:
  755. Return Value:
  756. static queue head associated with a particular frame
  757. --*/
  758. {
  759. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  760. ULONG f;
  761. // normalize frame
  762. f = Frame%32;
  763. qh = DeviceData->StaticInterruptQH[EHCI_Frame2Qhead[f]+ED_INTERRUPT_32ms];
  764. return qh;
  765. }
  766. /*
  767. Queue head index table, values correspond to index in StaticQueueHead List
  768. fr <32> <16> <08> <04> <02> <01>
  769. 0 (31) -\
  770. (15)-\
  771. 16 (32) -/ \
  772. (7)-\
  773. 8 (33) -\ / \
  774. (16)-/ \
  775. 24 (34) -/ \
  776. *(3)-\
  777. 4 (35) -\ / \
  778. (17)-\ / \
  779. 20 (36) -/ \ / \
  780. (8)-/ \
  781. 12 (37) -\ / \
  782. (18)-/ \
  783. 28 (38) -/ \
  784. *(1)-\
  785. 2 (39) -\ / \
  786. (19)-\ / \
  787. 18 (40) -/ \ / \
  788. (9)-\ / \
  789. 10 (41) -\ / \ / \
  790. (20)-/ \ / \
  791. 26 (42) -/ \ / \
  792. *(4)-/ \
  793. 6 (43) -\ / \
  794. (21)-\ / \
  795. 22 (44) -/ \ / \
  796. (10)-/ \
  797. 14 (45) -\ / \
  798. (22)-/ \
  799. 30 (46) -/ \
  800. *(0)
  801. 1 (47) -\ /
  802. (23)-\ /
  803. 17 (48) -/ \ /
  804. (11)-\ /
  805. 9 (49) -\ / \ /
  806. (24)-/ \ /
  807. 25 (50) -/ \ /
  808. *(5)-\ /
  809. 5 (51) -\ / \ /
  810. (25)-\ / \ /
  811. 21 (51) -/ \ / \ /
  812. (12)-/ \ /
  813. 13 (53) -\ / \ /
  814. (26)-/ \ /
  815. 29 (54) -/ \ /
  816. *(2)-/
  817. 3 (55) -\ /
  818. (27)-\ /
  819. 19 (56) -/ \ /
  820. (13)-\ /
  821. 11 (57) -\ / \ /
  822. (28)-/ \ /
  823. 27 (58) -/ \ /
  824. *(6)-/
  825. 7 (59) -\ /
  826. (29)-\ /
  827. 23 (60) -/ \ /
  828. (14)-/
  829. 15 (61) -\ /
  830. (30)-/
  831. 31 (62) -/
  832. */
  833. UCHAR EHCI_QHeadLinkTable[63] = {
  834. /* nextQueueHead QueueHead */
  835. 0xff, // 0
  836. 0, // 1
  837. 0, // 2
  838. 1, // 3
  839. 1, // 4
  840. 2, // 5
  841. 2, // 6
  842. 3, // 7
  843. 3, // 8
  844. 4, // 9
  845. 4, // 10
  846. 5, // 11
  847. 5, // 12
  848. 6, // 13
  849. 6, // 14
  850. 7, // 15
  851. 7, // 16
  852. 8, // 17
  853. 8, // 18
  854. 9, // 19
  855. 9, // 20
  856. 10, // 21
  857. 10, // 22
  858. 11, // 23
  859. 11, // 24
  860. 12, // 25
  861. 12, // 26
  862. 13, // 27
  863. 13, // 28
  864. 14, // 29
  865. 14, // 30
  866. 15, // 31
  867. 15, // 32
  868. 16, // 33
  869. 16, // 34
  870. 17, // 35
  871. 17, // 36
  872. 18, // 37
  873. 18, // 38
  874. 19, // 39
  875. 19, // 40
  876. 20, // 41
  877. 20, // 42
  878. 21, // 43
  879. 21, // 44
  880. 22, // 45
  881. 22, // 46
  882. 23, // 47
  883. 23, // 48
  884. 24, // 49
  885. 24, // 50
  886. 25, // 51
  887. 25, // 52
  888. 26, // 53
  889. 26, // 54
  890. 27, // 55
  891. 27, // 56
  892. 28, // 57
  893. 28, // 58
  894. 29, // 59
  895. 29, // 60
  896. 30, // 61
  897. 30, // 62
  898. };
  899. VOID
  900. EHCI_InitailizeInterruptSchedule(
  901. PDEVICE_DATA DeviceData
  902. )
  903. /*++
  904. Routine Description:
  905. Arguments:
  906. Return Value:
  907. --*/
  908. {
  909. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  910. ULONG i;
  911. // first initialize all the 'dummy' queue heads
  912. for (i=0; i<63; i++) {
  913. qh = DeviceData->StaticInterruptQH[i];
  914. SET_T_BIT(qh->HwQH.Overlay.qTD.Next_qTD.HwAddress);
  915. qh->HwQH.Overlay.qTD.Token.Halted = 1;
  916. qh->HwQH.EpChars.HeadOfReclimationList = 0;
  917. qh->Sig = SIG_HCD_IQH;
  918. }
  919. #define INIT_QH(q, nq, f) \
  920. do {\
  921. QH_DESCRIPTOR_PTR((q)->NextQh) = (nq); \
  922. QH_DESCRIPTOR_PTR((q)->PrevQh) = NULL; \
  923. (q)->HwQH.HLink.HwAddress = (nq)->PhysicalAddress; \
  924. (q)->HwQH.HLink.HwAddress |= EHCI_DTYPE_QH;\
  925. (q)->HwQH.EpCaps.InterruptScheduleMask =0xff;\
  926. (q)->QhFlags |= EHCI_QH_FLAG_STATIC;\
  927. (q)->QhFlags |= f;\
  928. } while(0)
  929. // now build the above tree
  930. for (i=1; i<63; i++) {
  931. INIT_QH(DeviceData->StaticInterruptQH[i],
  932. DeviceData->StaticInterruptQH[EHCI_QHeadLinkTable[i]],
  933. i<=6 ? EHCI_QH_FLAG_HIGHSPEED : 0);
  934. }
  935. // last qh has t bit set
  936. DeviceData->StaticInterruptQH[0]->HwQH.HLink.HwAddress = 0;
  937. SET_T_BIT(DeviceData->StaticInterruptQH[0]->HwQH.HLink.HwAddress);
  938. DeviceData->StaticInterruptQH[0]->QhFlags |=
  939. (EHCI_QH_FLAG_HIGHSPEED | EHCI_QH_FLAG_STATIC);
  940. #undef INIT_QH
  941. }
  942. VOID
  943. EHCI_WaitFrames(
  944. PDEVICE_DATA DeviceData,
  945. ULONG Frames
  946. )
  947. {
  948. PHC_OPERATIONAL_REGISTER hcOp = NULL;
  949. FRINDEX frameIndex;
  950. ULONG frameNumber, i, c;
  951. hcOp = DeviceData->OperationalRegisters;
  952. for (c=0; c< Frames; c++) {
  953. // bugbug this code does not handle varaible frame list
  954. // sizes
  955. frameIndex.ul = READ_REGISTER_ULONG(&hcOp->UsbFrameIndex.ul);
  956. frameNumber = (ULONG) frameIndex.FrameListCurrentIndex;
  957. // shift off the microframes
  958. frameNumber >>= 3;
  959. i = frameNumber;
  960. do {
  961. frameIndex.ul = READ_REGISTER_ULONG(&hcOp->UsbFrameIndex.ul);
  962. frameNumber = (ULONG) frameIndex.FrameListCurrentIndex;
  963. // shift off the microframes
  964. frameNumber >>= 3;
  965. } while (frameNumber == i);
  966. }
  967. }
  968. VOID
  969. EHCI_RebalanceInterruptEndpoint(
  970. PDEVICE_DATA DeviceData,
  971. PENDPOINT_PARAMETERS EndpointParameters,
  972. PENDPOINT_DATA EndpointData
  973. )
  974. /*++
  975. Routine Description:
  976. compute how much common buffer we will need
  977. for this endpoint
  978. Arguments:
  979. Return Value:
  980. --*/
  981. {
  982. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  983. qh = EndpointData->QueueHead;
  984. // update internal copy of parameters
  985. EndpointData->Parameters = *EndpointParameters;
  986. // period promotion?
  987. if (qh->Period != EndpointParameters->Period) {
  988. ULONG i, offset;
  989. EHCI_KdPrint((DeviceData, 1, "'period change old - %d new %d\n",
  990. qh->Period, EndpointParameters->Period));
  991. EHCI_RemoveQueueHeadFromPeriodicList(DeviceData,
  992. EndpointData);
  993. EHCI_WaitFrames(DeviceData, 2);
  994. // clear residual data from overlay area
  995. qh->HwQH.Overlay.qTD.Token.ErrorCounter = 0;
  996. qh->HwQH.Overlay.qTD.Token.SplitXstate = 0;
  997. qh->HwQH.Overlay.Ov.OverlayDw8.CprogMask = 0;
  998. qh->HwQH.Overlay.Ov.OverlayDw9.Sbytes = 0;
  999. qh->HwQH.Overlay.Ov.OverlayDw9.fTag = 0;
  1000. EHCI_ASSERT(DeviceData,
  1001. EndpointData->Parameters.DeviceSpeed != HighSpeed);
  1002. // select the proper list
  1003. // the period is a power of 2 ie
  1004. // 32,16,8,4,2,1
  1005. // we just need to find which bit is set
  1006. GET_BIT_SET(EndpointParameters->Period, i);
  1007. EHCI_ASSERT(DeviceData, i < 8);
  1008. EHCI_ASSERT(DeviceData, EndpointParameters->Period < 64);
  1009. offset = EndpointParameters->ScheduleOffset;
  1010. i = ClassicPeriodIdx[i];
  1011. EndpointData->StaticQH =
  1012. DeviceData->StaticInterruptQH[i+offset];
  1013. EndpointData->PeriodTableEntry = NULL;
  1014. qh->Period = EndpointParameters->Period;
  1015. qh->HwQH.EpCaps.InterruptScheduleMask =
  1016. EndpointParameters->InterruptScheduleMask;
  1017. qh->HwQH.EpCaps.SplitCompletionMask =
  1018. EndpointParameters->SplitCompletionMask;
  1019. EHCI_InsertQueueHeadInPeriodicList(DeviceData,
  1020. EndpointData);
  1021. } else {
  1022. EHCI_RemoveQueueHeadFromPeriodicList(DeviceData,
  1023. EndpointData);
  1024. EHCI_WaitFrames(DeviceData, 2);
  1025. // clear residual data from overlay area
  1026. qh->HwQH.Overlay.qTD.Token.ErrorCounter = 0;
  1027. qh->HwQH.Overlay.qTD.Token.SplitXstate = 0;
  1028. qh->HwQH.Overlay.Ov.OverlayDw8.CprogMask = 0;
  1029. qh->HwQH.Overlay.Ov.OverlayDw9.Sbytes = 0;
  1030. qh->HwQH.Overlay.Ov.OverlayDw9.fTag = 0;
  1031. qh->HwQH.EpCaps.InterruptScheduleMask =
  1032. EndpointParameters->InterruptScheduleMask;
  1033. qh->HwQH.EpCaps.SplitCompletionMask =
  1034. EndpointParameters->SplitCompletionMask;
  1035. EHCI_InsertQueueHeadInPeriodicList(DeviceData,
  1036. EndpointData);
  1037. }
  1038. }