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.

814 lines
22 KiB

  1. /*++
  2. Copyright (c) 1995,1996 Microsoft Corporation
  3. :ts=4
  4. Module Name:
  5. int.c
  6. Abstract:
  7. This module contains the interrupt routine, DPC routines and routines
  8. that synchronize with the interrupt routine.
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. 11-01-95 : created
  14. --*/
  15. #include "wdm.h"
  16. #include "stdarg.h"
  17. #include "stdio.h"
  18. #include "usbdi.h"
  19. #include "hcdi.h"
  20. #include "uhcd.h"
  21. #ifdef DEBUG_LOG
  22. ULONG TrapOn = 0;
  23. #endif
  24. BOOLEAN
  25. UHCD_InterruptService(
  26. IN PKINTERRUPT Interrupt,
  27. IN PVOID Context
  28. )
  29. /*++
  30. Routine Description:
  31. This is the interrupt service routine for the UHCD.
  32. Arguments:
  33. Interrupt - A pointer to the interrupt object for this interrupt.
  34. Context - A pointer to the device object.
  35. Return Value:
  36. Returns TRUE if the interrupt was expected (and therefore processed);
  37. otherwise, FALSE is returned.
  38. --*/
  39. {
  40. PDEVICE_EXTENSION deviceExtension;
  41. PDEVICE_OBJECT deviceObject;
  42. USHORT status;
  43. ULONG frameNumber;
  44. BOOLEAN usbInt = FALSE;
  45. UNREFERENCED_PARAMETER(Interrupt);
  46. // UHCD_KdPrint((2, "'enter UHCD_InterruptService\n"));
  47. deviceObject = (PDEVICE_OBJECT) Context;
  48. deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
  49. // Ignore ints if we are not in D0.
  50. if (deviceExtension->CurrentDevicePowerState != PowerDeviceD0) {
  51. goto UHCD_InterruptService_Done;
  52. }
  53. status = READ_PORT_USHORT(STATUS_REG(deviceExtension));
  54. if (status & (UHCD_STATUS_USBINT |
  55. UHCD_STATUS_USBERR |
  56. UHCD_STATUS_RESUME |
  57. UHCD_STATUS_HCERR |
  58. UHCD_STATUS_PCIERR
  59. // BUGBUG we will ignore the halt bit by itself since
  60. // the controller will never allow us to clear the status
  61. /*| UHCD_STATUS_HCHALT*/)) {
  62. usbInt = TRUE;
  63. //clear the condition
  64. WRITE_PORT_USHORT(STATUS_REG(deviceExtension), 0xff);
  65. } else {
  66. goto UHCD_InterruptService_Done;
  67. }
  68. if ((status & (UHCD_STATUS_HCHALT | UHCD_STATUS_USBINT)) ==
  69. (UHCD_STATUS_HCHALT | UHCD_STATUS_USBINT)) {
  70. ULONG frame;
  71. USHORT cmd;
  72. frameNumber = (ULONG) READ_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension)) & 0x3ff;
  73. frame = UHCD_GetCurrentFrame(deviceObject);
  74. //LOGENTRY(LOG_MISC, 'Hlt!', status, deviceExtension->FrameListVirtualAddress, frameNumber);
  75. UHCD_KdPrint((2, "'UHCD Host Controller Halted %x, frame = 0x%x - 0x%x\n", status,
  76. frame, frameNumber));
  77. //
  78. // nasty error in the host controller, we will want to debug.
  79. //
  80. UHCD_KdPrint((0, "'HC HALTED! attempting to recover\n"));
  81. // attempt to recover
  82. WRITE_PORT_USHORT(STATUS_REG(deviceExtension), 0xff);
  83. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  84. cmd |= UHCD_CMD_RUN;
  85. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  86. usbInt = TRUE;
  87. return usbInt;
  88. }
  89. //
  90. // Process the interrupt
  91. //
  92. if (status & UHCD_STATUS_RESUME) {
  93. //
  94. // system wakeup interrupt
  95. //
  96. #ifdef MAX_DEBUG
  97. TEST_TRAP();
  98. #endif
  99. } else if (status & UHCD_STATUS_USBINT) {
  100. //
  101. // Interrupt because a TD completed
  102. //
  103. // UHCD_KdPrint((2, "'UHCD_InterruptService status = %x\n", status));
  104. #ifdef DEBUG_LOG
  105. // if (TrapOn > 0) {
  106. // USHORT portStatus;
  107. // // check for port disable
  108. // portStatus = READ_PORT_USHORT(PORT1_REG(deviceExtension));
  109. // if (portStatus & 0x0008) {
  110. frameNumber = (ULONG) READ_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension)) & 0x3ff;
  111. ////
  112. //// UHCD_KdPrint((2, "'Port Disabled frame = 0x%x\n", frameNumber));
  113. ////
  114. // TRAP();
  115. // }
  116. // portStatus = READ_PORT_USHORT(PORT2_REG(deviceExtension));
  117. // if (portStatus & 0x0008) {
  118. // frameNumber = (ULONG) READ_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension)) & 0x3ff;
  119. ////
  120. //// UHCD_KdPrint((2, "'Port Disabled frame = 0x%x\n", frameNumber));
  121. ////
  122. // TRAP();
  123. // }
  124. // }
  125. #endif
  126. // This code maintains the 32-bit frame counter
  127. frameNumber = (ULONG) READ_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension));
  128. // did the sign bit change ?
  129. if ((deviceExtension->LastFrame ^ frameNumber) & 0x0400) {
  130. // Yes
  131. deviceExtension->FrameHighPart += 0x0800 -
  132. ((frameNumber ^ deviceExtension->FrameHighPart) & 0x0400);
  133. }
  134. // remember the last frame number
  135. deviceExtension->LastFrame = frameNumber;
  136. //***
  137. //
  138. // start at the last frame processed
  139. //
  140. {
  141. ULONG i, j;
  142. ULONG currentFrame, highPart;
  143. highPart = deviceExtension->FrameHighPart;
  144. // get 11-bit frame number, high 17-bits are 0
  145. //frameNumber = (ULONG) READ_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension));
  146. currentFrame = ((frameNumber & 0x0bff) | highPart) +
  147. ((frameNumber ^ highPart) & 0x0400);
  148. // UHCD_KdPrint((2, "'currentFrame = %x\n", currentFrame));
  149. if (currentFrame-deviceExtension->LastFrameProcessed > 1024) {
  150. deviceExtension->Stats.ScheduleOverrunCount++;
  151. // we have a schedule overrun,
  152. // this means it has been more that 1000 ms since our last
  153. // interrupt, because of this the iso entries in the schedule
  154. // are invalid -- we need to remove all of them and start over
  155. // UHCD_KdPrint((2, "'schedule overrun currentFrame = %d, lastframe = %d \n",
  156. // currentFrame, deviceExtension->LastFrameProcessed));
  157. // TRAP();
  158. // first remove all iso TDs from the list
  159. for (j=0; j<FRAME_LIST_SIZE; j++) {
  160. // put back the physical address that was there before we started
  161. // adding isoch descriptors.
  162. *( ((PULONG) (deviceExtension->FrameListVirtualAddress) + j) ) =
  163. *( ((PULONG) (deviceExtension->FrameListCopyVirtualAddress) + j) );
  164. #if DBG
  165. *( deviceExtension->IsoList + j ) = 0;
  166. #endif
  167. }
  168. deviceExtension->LastFrameProcessed = currentFrame;
  169. }
  170. {
  171. #ifdef FAST_ISO
  172. PUHCD_ENDPOINT endpoint;
  173. endpoint = UHCD_GetLastFastIsoEndpoint(deviceObject);
  174. #endif /* FAST_ISO */
  175. for (i=deviceExtension->LastFrameProcessed+1; i<currentFrame; i++) {
  176. // remove isoch TDs for frame i;
  177. j = i % FRAME_LIST_SIZE;
  178. // put back the physical address that was there before we started
  179. // adding isoch descriptors.
  180. *( ((PULONG) (deviceExtension->FrameListVirtualAddress) + j) ) =
  181. *( ((PULONG) (deviceExtension->FrameListCopyVirtualAddress) + j) );
  182. #if DBG
  183. *( deviceExtension->IsoList + j ) = 0;
  184. #endif
  185. #ifdef FAST_ISO
  186. if (endpoint) {
  187. UHCD_CleanupFastIsoTD(deviceObject,
  188. endpoint,
  189. j,
  190. TRUE);
  191. }
  192. #endif /* FAST_ISO */
  193. }
  194. }
  195. deviceExtension->LastFrameProcessed = currentFrame-1;
  196. }
  197. //***
  198. //
  199. // Queue the DPC to complete any transfers
  200. //
  201. #ifdef PROFILE
  202. {
  203. LARGE_INTEGER time;
  204. time = KeQueryPerformanceCounter(NULL);
  205. UHCD_KdPrint((2, "'time.HighPart = %x time.LowPart %x\n", time.HighPart,
  206. time.LowPart));
  207. // LOGENTRY(LOG_MISC, 'Tim1", 0, sysTime.LowPart, sysTime.HighPart);
  208. KeInsertQueueDpc(&deviceExtension->IsrDpc,
  209. time.HighPart,
  210. time.LowPart);
  211. }
  212. #else
  213. KeInsertQueueDpc(&deviceExtension->IsrDpc,
  214. NULL,
  215. NULL);
  216. #endif
  217. // UHCD_KdPrint((2, "'exit UHCD_InterruptService\n"));
  218. // USB interrupt
  219. } else {
  220. //
  221. // USB Interrupt not recognized in ISR
  222. //
  223. UHCD_KdBreak((2, "'USB interrupt not recognized by ISR, status = %x\n", status));
  224. // BUGBUG check why we are not handling it
  225. }
  226. UHCD_InterruptService_Done:
  227. //#ifdef MAX_DEBUG
  228. // if (!usbInt) {
  229. // UHCD_KdPrint((2, "'Non USB interrupt, status = %x\n", status));
  230. // }
  231. //#endif
  232. return usbInt;
  233. }
  234. VOID
  235. UHCD_IsrDpc(
  236. IN PKDPC Dpc,
  237. IN PVOID DeferredContext,
  238. IN PVOID SystemArgument1,
  239. IN PVOID SystemArgument2
  240. )
  241. /*++
  242. Routine Description:
  243. This routine runs at DISPATCH_LEVEL IRQL.
  244. Arguments:
  245. Dpc - Pointer to the DPC object.
  246. DeferredContext - supplies the DeviceObject.
  247. SystemArgument1 - not used.
  248. SystemArgument2 - not used.
  249. Return Value:
  250. None.
  251. --*/
  252. {
  253. PDEVICE_EXTENSION deviceExtension;
  254. PDEVICE_OBJECT deviceObject;
  255. PLIST_ENTRY listEntry;
  256. PUHCD_ENDPOINT endpoint;
  257. LONG slot;
  258. BOOLEAN process = TRUE;
  259. KIRQL irql;
  260. // STARTPROC("IDpc");
  261. #ifdef PROFILE
  262. {
  263. //
  264. // See how long it took for our DPC to get called
  265. //
  266. LARGE_INTEGER time, timeNow;
  267. LONG delta;
  268. time.HighPart = SystemArgument1;
  269. time.LowPart = SystemArgument2;
  270. timeNow = KeQueryPerformanceCounter(NULL);
  271. delta = timeNow.QuadPart - time.QuadPart;
  272. UHCD_KdPrint((2, "'time.HighPart = %x time.LowPart %x\n", time.HighPart,
  273. time.LowPart));
  274. UHCD_KdPrint((2, "'timeNow.HighPart = %x timeNow.LowPart %x\n", timeNow.HighPart,
  275. timeNow.LowPart));
  276. UHCD_KdPrint((2, "'delta %x %x ms\n", delta, delta/((0x1234de*50)/1000)));
  277. if (delta > ((0x1234de*50)/1000)) {
  278. UHCD_KdTrap(("DPC delayed > 50 ms\n"));
  279. }
  280. //LOGENTRY(LOG_MISC, 'Tim2", timeNow - time, time, timeNow);
  281. }
  282. #endif
  283. // UHCD_KdPrint((2, "'enter UHCD_IsrDpc\n"));
  284. deviceObject = (PDEVICE_OBJECT) DeferredContext;
  285. deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
  286. //
  287. // Walk through the Endpoint list checking for
  288. // any endpoints that have transfers that need completing
  289. //
  290. LOCK_ENDPOINT_LIST(deviceExtension, irql);
  291. if (deviceExtension->EndpointListBusy) {
  292. process = FALSE;
  293. } else {
  294. deviceExtension->EndpointListBusy = TRUE;
  295. }
  296. UNLOCK_ENDPOINT_LIST(deviceExtension, irql);
  297. if (process) {
  298. //
  299. // we now have exclusive access to the endpoint list
  300. //
  301. listEntry = &deviceExtension->EndpointList;
  302. if (!IsListEmpty(listEntry)) {
  303. listEntry = deviceExtension->EndpointList.Flink;
  304. }
  305. LOGENTRY(LOG_MISC, 'EPl+', listEntry,
  306. &deviceExtension->EndpointList, 0);
  307. while (listEntry != &deviceExtension->EndpointList) {
  308. ULONG cnt = 0;
  309. endpoint = CONTAINING_RECORD(listEntry,
  310. UHCD_ENDPOINT,
  311. ListEntry);
  312. ASSERT_ENDPOINT(endpoint);
  313. // LOGENTRY(LOG_MISC, 'prEP', endpoint,
  314. // &deviceExtension->EndpointList, listEntry);
  315. listEntry = endpoint->ListEntry.Flink;
  316. //
  317. // Scan active transfer slots and process any transfers
  318. // that have been programmed into the hardware.
  319. //
  320. for (slot=0; slot<endpoint->MaxRequests; slot++) {
  321. //
  322. // If we have a transfer in the slot call the completion
  323. // handler.
  324. //
  325. if (endpoint->ActiveTransfers[slot]) {
  326. cnt++;
  327. LOGENTRY(LOG_MISC, 'epWk', endpoint, slot, endpoint->ActiveTransfers[slot]);
  328. // only call the completer if no double buffer
  329. // endpoints
  330. if (!(endpoint->EndpointFlags & EPFLAG_DBL_BUFFER)) {
  331. LOGENTRY(LOG_MISC, 'cPTR', endpoint,
  332. slot, endpoint->ActiveTransfers[slot]);
  333. UHCD_CompleteTransferDPC(deviceObject, endpoint, slot);
  334. }
  335. }
  336. }
  337. // if we had no transfers see if we can idle the endpoint
  338. if (cnt) {
  339. UHCD_EndpointWakeup(deviceObject, endpoint);
  340. } else {
  341. UHCD_EndpointIdle(deviceObject, endpoint);
  342. }
  343. //
  344. // For DBL_BUFFER transfers, we don't do the active abort
  345. // until we call the worker code. The worker code will also
  346. // clear the flag for us. So, if it is a DBL_BUFFER, don't
  347. // clear the flag yet.
  348. //
  349. if (!(endpoint->EndpointFlags & EPFLAG_DBL_BUFFER)) {
  350. //
  351. // safe to clear the ABORT_ACTIVE_TRANSFERS flag
  352. // this will allow a reset_endpoint to succeed.
  353. // LOGENTRY(LOG_MISC, 'clrA', endpoint, 0, 0);
  354. //
  355. CLR_EPFLAG(endpoint, EPFLAG_ABORT_ACTIVE_TRANSFERS);
  356. }
  357. // does this endpoint need attention, we mail have bailed
  358. // because endpointworker was busy, if so process it now
  359. if (endpoint->EndpointFlags & EPFLAG_HAVE_WORK) {
  360. UHCD_EndpointWorker(deviceObject, endpoint);
  361. }
  362. }
  363. LOGENTRY(LOG_MISC, 'EPl-', listEntry,
  364. &deviceExtension->EndpointList, 0);
  365. // now walk the list looking for idle bulk
  366. {
  367. ULONG idleBulkEndpoints = 0;
  368. ULONG bulkEndpoints = 0;
  369. listEntry = &deviceExtension->EndpointList;
  370. if (!IsListEmpty(listEntry)) {
  371. listEntry = deviceExtension->EndpointList.Flink;
  372. }
  373. LOGENTRY(LOG_MISC, 'EPl+', listEntry,
  374. &deviceExtension->EndpointList, 0);
  375. while (listEntry != &deviceExtension->EndpointList) {
  376. BOOLEAN idle = TRUE;
  377. endpoint = CONTAINING_RECORD(listEntry,
  378. UHCD_ENDPOINT,
  379. ListEntry);
  380. ASSERT_ENDPOINT(endpoint);
  381. LOGENTRY(LOG_MISC, 'prEP', endpoint,
  382. &deviceExtension->EndpointList, listEntry);
  383. listEntry = endpoint->ListEntry.Flink;
  384. // see if this ep is closed, if so remove it and
  385. // it on the closed list
  386. if (endpoint->EndpointFlags & EPFLAG_EP_CLOSED) {
  387. LOGENTRY(LOG_MISC, 'epCL', endpoint,
  388. &deviceExtension->EndpointList, listEntry);
  389. RemoveEntryList(&endpoint->ListEntry);
  390. continue;
  391. }
  392. //
  393. // Scan active transfer slots and process any transfers
  394. // thet have been programmed into the hardware.
  395. //
  396. for (slot=0; slot<endpoint->MaxRequests; slot++) {
  397. //
  398. // If we have a transfer in the slot we are not idle
  399. //
  400. if (endpoint->ActiveTransfers[slot]) {
  401. idle = FALSE;
  402. }
  403. }
  404. if (endpoint->Type == USB_ENDPOINT_TYPE_BULK) {
  405. bulkEndpoints++;
  406. if (idle) {
  407. idleBulkEndpoints++;
  408. }
  409. }
  410. }
  411. if (bulkEndpoints && bulkEndpoints == idleBulkEndpoints) {
  412. // no activity on the bulk endpoints
  413. // disable BW reclimation.
  414. UHCD_BW_Reclimation(deviceObject, FALSE);
  415. }
  416. }
  417. //
  418. // See if we can free any endpoint structures
  419. //
  420. // walk through the closed endpoint list, if we find an endpoint that has
  421. // been freed in a previous frame then go ahead and release its
  422. // resources.
  423. while (!IsListEmpty(&deviceExtension->ClosedEndpointList)) {
  424. ULONG cnt;
  425. listEntry = RemoveHeadList( &deviceExtension->ClosedEndpointList);
  426. endpoint = CONTAINING_RECORD(listEntry,
  427. UHCD_ENDPOINT,
  428. ListEntry);
  429. ASSERT_ENDPOINT(endpoint);
  430. if (UHCD_GetCurrentFrame(deviceObject) <= endpoint->FrameToClose) {
  431. //
  432. // put it back and get out
  433. //
  434. InsertHeadList(&deviceExtension->ClosedEndpointList, &endpoint->ListEntry);
  435. break;
  436. }
  437. // free the endpoint resources
  438. UHCD_KdPrint((2, "'UHCD_IsrDpc free endpoint %x\n", endpoint));
  439. if (endpoint->EndpointFlags & EPFLAG_DBL_BUFFER) {
  440. UHCD_UnInitializeNoDMAEndpoint(deviceObject,
  441. endpoint);
  442. }
  443. UHCD_ASSERT(!(endpoint->EndpointFlags & EPFLAG_FAST_ISO));
  444. UHCD_FreeBandwidth(deviceObject, endpoint, endpoint->Offset);
  445. for (cnt=0; cnt< endpoint->MaxRequests; cnt++) {
  446. UHCD_FreeHardwareDescriptors(deviceObject,
  447. endpoint->HardwareDescriptorList[cnt]);
  448. }
  449. #if DBG
  450. //UHCD_BufferPoolCheck(deviceObject);
  451. #endif
  452. RETHEAP(endpoint);
  453. }
  454. // now check the lookaside list and add any endpoints on it
  455. while (!IsListEmpty(&deviceExtension->EndpointLookAsideList)) {
  456. listEntry = RemoveHeadList(&deviceExtension->EndpointLookAsideList);
  457. endpoint = CONTAINING_RECORD(listEntry,
  458. UHCD_ENDPOINT,
  459. ListEntry);
  460. ASSERT_ENDPOINT(endpoint);
  461. InsertHeadList(&deviceExtension->EndpointList, &endpoint->ListEntry);
  462. }
  463. LOCK_ENDPOINT_LIST(deviceExtension, irql);
  464. deviceExtension->EndpointListBusy = FALSE;
  465. UNLOCK_ENDPOINT_LIST(deviceExtension, irql);
  466. }
  467. #ifdef FAST_ISO
  468. // walk the fastiso list and complete any transfers
  469. // if the last frame has pssed
  470. {
  471. listEntry = &deviceExtension->FastIsoTransferList;
  472. if (!IsListEmpty(listEntry)) {
  473. listEntry = deviceExtension->FastIsoTransferList.Flink;
  474. }
  475. LOGENTRY(LOG_MISC, 'FIl+', listEntry,
  476. &deviceExtension->FastIsoTransferList, 0);
  477. while (listEntry != &deviceExtension->FastIsoTransferList) {
  478. PIRP irp;
  479. PHCD_URB urb;
  480. ULONG cf, lastFrame;
  481. urb = (PHCD_URB) CONTAINING_RECORD(
  482. listEntry,
  483. struct _URB_HCD_COMMON_TRANSFER,
  484. hca.HcdListEntry);
  485. listEntry = HCD_AREA(urb).HcdListEntry.Flink;
  486. lastFrame = urb->UrbIsochronousTransfer.StartFrame+1;
  487. // urb->UrbIsochronousTransfer.NumberOfPackets;
  488. cf = UHCD_GetCurrentFrame(deviceObject);
  489. LOGENTRY(LOG_MISC, 'FIck', urb, cf, lastFrame);
  490. if (cf >= lastFrame) {
  491. LOGENTRY(LOG_MISC, 'FIcp', urb, cf, lastFrame);
  492. RemoveEntryList(&HCD_AREA(urb).HcdListEntry);
  493. irp = HCD_AREA(urb).HcdIrp;
  494. UHCD_CompleteIrp(deviceObject,
  495. irp,
  496. STATUS_SUCCESS,
  497. 0,
  498. urb);
  499. continue;
  500. }
  501. }
  502. }
  503. #endif /* FAST_ISO */
  504. // ENDPROC("IDpc");
  505. // UHCD_KdPrint((2, "'exit UHCD_IsrDpc\n"));
  506. }
  507. VOID
  508. UHCD_RequestInterrupt(
  509. IN PDEVICE_OBJECT DeviceObject,
  510. IN LONG FrameNumber
  511. )
  512. /*++
  513. Routine Description:
  514. This routine triggers a hradware interrupt on a specific
  515. USB frame number.
  516. Arguments:
  517. DeviceObject - Supplies the device object.
  518. Frame - frame to generate intrerrupt on, a negative value
  519. indicates relative to the current frame.
  520. Return Value:
  521. None.
  522. --*/
  523. {
  524. ULONG requestFrameNumber;
  525. PDEVICE_EXTENSION deviceExtension;
  526. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  527. ULONG i;
  528. UHCD_KdPrint((2, "'enter UHCD_RequestInterrupt\n"));
  529. deviceExtension = DeviceObject->DeviceExtension;
  530. //
  531. // Allocate a TD we can use for this request
  532. //
  533. // NOTE:
  534. // First two TDs are dedicated to detecting frame rollover.
  535. //
  536. for (i=UHCD_FIRST_TRIGGER_TD; i<MAX_TDS_PER_ENDPOINT; i++) {
  537. transferDescriptor =
  538. &deviceExtension->TriggerTDList->TDs[i];
  539. if (deviceExtension->LastFrameProcessed >
  540. transferDescriptor->Frame) {
  541. break;
  542. }
  543. transferDescriptor = NULL;
  544. }
  545. if (transferDescriptor == NULL) {
  546. //
  547. // no TDS available for interrupt request, this means enough
  548. // interrupts are happening that we'll be OK -- worst case
  549. // is we'll get an interrupt on frame rollover.
  550. //
  551. UHCD_KdBreak((2, "'no tds for interrupt request\n"));
  552. goto UHCD_RequestInterrupt_Done;
  553. }
  554. if (FrameNumber < 0) {
  555. requestFrameNumber = UHCD_GetCurrentFrame(DeviceObject) -
  556. FrameNumber;
  557. } else {
  558. requestFrameNumber = FrameNumber;
  559. }
  560. //
  561. // all we do here is put a dummy isoch TD in the schedule at
  562. // the requested frame number
  563. //
  564. LOGENTRY(LOG_MISC, 'REQi', requestFrameNumber, FrameNumber,
  565. transferDescriptor);
  566. //
  567. // Make sure we can schedule it
  568. //
  569. if (requestFrameNumber >
  570. deviceExtension->LastFrameProcessed+1+FRAME_LIST_SIZE-1) {
  571. // note: if the request is to far in advance.
  572. LOGENTRY(LOG_MISC, 'REQf', FrameNumber, requestFrameNumber,
  573. (deviceExtension->LastFrameProcessed+1+FRAME_LIST_SIZE-1));
  574. // if the request is too far in advance we'll just let it be handled
  575. // by the rollover interrupts.
  576. } else {
  577. transferDescriptor->Active = 0;
  578. transferDescriptor->MaxLength = UHCD_SYSTEM_TO_USB_BUFFER_LENGTH(0);
  579. transferDescriptor->InterruptOnComplete = 1;
  580. transferDescriptor->Frame = requestFrameNumber;
  581. #ifdef VIA_HC
  582. transferDescriptor->PID = USB_IN_PID;
  583. #endif /* VIA_HC */
  584. UHCD_InsertIsochDescriptor(DeviceObject,
  585. transferDescriptor,
  586. requestFrameNumber);
  587. }
  588. UHCD_RequestInterrupt_Done:
  589. UHCD_KdPrint((2, "'exit UHCD_RequestInterrupt\n"));
  590. }