public void Free() { FOS_System.Heap.Free(queueHead); queueHead = null; }
/// <summary> /// Initializes a new queue head with specified underlying memory structure. /// </summary> /// <param name="aQueueHead">The existing underlying queue head.</param> public EHCI_QueueHead(EHCI_QueueHead_Struct* aQueueHead) { queueHead = aQueueHead; }
/// <summary> /// Adds a transfer for the async schedule. /// </summary> /// <param name="transfer">The transfer to add.</param> protected void AddToAsyncSchedule(USBTransfer transfer) { // Set the expected number of USB Interrupts to 1 // 1 because we expect one and only one for the last transaction of the transfer // which we flagged to Interrupt On Complete in IssueTransfer. USBIntCount = 1; // If the schedule is disabled: // Section 2.3.2 of Intel EHCI Spec if ((USBSTS & EHCI_Consts.STS_AsyncEnabled) == 0) { // Enable / start the async schedule EnableAsyncSchedule(); } // Save the old tail queue head (which may not be the idle queue head) (save in a wrapper) EHCI_QueueHead oldTailQH = new EHCI_QueueHead(TailQueueHead); // The new queue head will now be end of the queue TailQueueHead = (EHCI_QueueHead_Struct*)transfer.underlyingTransferData; // Create wrappers for the idle and tail queue heads. EHCI_QueueHead idleQH = new EHCI_QueueHead(IdleQueueHead); EHCI_QueueHead tailQH = new EHCI_QueueHead(TailQueueHead); // Create the ring. Link the new queue head with idleQH (which is always the head of the queue) tailQH.HorizontalLinkPointer = (EHCI_QueueHead_Struct*)VirtMemManager.GetPhysicalAddress(IdleQueueHead); // Insert the queue head into the queue as an element behind old queue head oldTailQH.HorizontalLinkPointer = (EHCI_QueueHead_Struct*)VirtMemManager.GetPhysicalAddress(TailQueueHead); int timeout = 100; while (USBIntCount > 0 && (HostSystemErrors == 0) && !IrrecoverableError && --timeout > 0) { Kernel.Processes.SystemCalls.SleepThread(50); #if EHCI_TRACE if (timeout % 10 == 0) { BasicConsole.WriteLine("Waiting for transfer to complete..."); } #endif } #if EHCI_TRACE if (timeout == 0) { BasicConsole.WriteLine("Transfer timed out."); } #endif // Restore the link of the old tail queue head to the idle queue head oldTailQH.HorizontalLinkPointer = (EHCI_QueueHead_Struct*)VirtMemManager.GetPhysicalAddress(IdleQueueHead); // Queue head done. // Because nothing else touches the async queue and this method is a synchronous method, // the idle queue head will now always be the end of the queue again. TailQueueHead = oldTailQH.queueHead; }
/// <summary> /// Initializes a new queue head with empty underlying memory structure. /// </summary> public EHCI_QueueHead() { queueHead = (EHCI_QueueHead_Struct*)FOS_System.Heap.AllocZeroedAPB((uint)sizeof(EHCI_QueueHead_Struct), 32, "EHCI : EHCI_QueueHead()"); }
/// <summary> /// Initialises the async schedule. /// </summary> protected void InitializeAsyncSchedule() { // If there is no idle queue head: if (IdleQueueHead == null) { // Create one and set it as both the idle and tail queue heads. IdleQueueHead = TailQueueHead = new EHCI_QueueHead().queueHead; // The Idle Queue Head always remains in the queue and it does nothing. // It is also always the head of the reclamation list. (Note: The // reclamation list is not made use of by this driver implementation). // The spec makes no explicit mention of needing an Idle Queue Head. // However, the need is clearly implicitly there. The spec says that // while the async queue is enabled, it will use the ASYNCLISTADDR to // try and traverse the async queue. This clearly suggests then, that // the ASYNCLISTADDR must be valid for the entire time that the async // schedule is enabled. For this to be possible without continually // sending actual transfers, we must have the idle transfer (queue head). // Section 4.8 of Intel EHCI Spec } // Initialise the idle queue head as a circular list of 1 item - i.e. idle queue head // points to itself. And as the head of the reclamation list. InitQH(IdleQueueHead, IdleQueueHead, null, true, 0, 0, 0); // Set the Async List Address to point to the idle queue head. // Note: Physical address of queue head is required. // Section 2.3.7 of Intel EHCI Spec ASYNCLISTADDR = (EHCI_QueueHead_Struct*)VirtMemManager.GetPhysicalAddress(IdleQueueHead); // Enable the async schedule. EnableAsyncSchedule(); }