Example #1
0
 public void Free()
 {
     FOS_System.Heap.Free(queueHead);
     queueHead = null;
 }
Example #2
0
 /// <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;
 }
Example #3
0
        /// <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;
        }
Example #4
0
 /// <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()");
 }
Example #5
0
        /// <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();
        }