Exemplo n.º 1
0
        /// <summary>
        /// Sets up an OUT transaction and adds it to the specified transfer.
        /// </summary>
        /// <param name="transfer">The transfer to which the transaction should be added.</param>
        /// <param name="controlHandshake">Whether the transaction is part of a control handshake or not.</param>
        /// <param name="buffer">The buffer of outgoing data.</param>
        /// <param name="length">The length of the buffer.</param>
        public void OUTTransaction(USBTransfer transfer, bool controlHandshake, void *buffer, ushort length)
        {
            ushort clampedLength = FOS_System.Math.Min(transfer.packetSize, length);

            length -= clampedLength;
            ushort remainingTransactions = (ushort)(length / transfer.packetSize);

            if (length % transfer.packetSize != 0)
            {
                remainingTransactions++;
            }

            USBTransaction transaction = new USBTransaction();

            transaction.type = USBTransactionType.OUT;

            if (controlHandshake) // Handshake transaction of control transfers always have toggle set to 1
            {
                ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle = true;
            }

            _OUTTransaction(transfer, transaction, ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle, buffer, clampedLength);

            transfer.transactions.Add(transaction);

            ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle = !((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle; // Switch toggle

            if (remainingTransactions > 0)
            {
                OUTTransaction(transfer, controlHandshake, ((byte *)buffer + clampedLength), length);
            }
        }
Exemplo n.º 2
0
        protected override void _OUTTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, void *buffer, ushort length)
        {
#if UHCI_TRACE
            BasicConsole.WriteLine("UHCI: OUT Transaction");
            BasicConsole.DelayOutput(5);
#endif

            UHCITransaction uT = new UHCITransaction();
            uTransaction.underlyingTz = uT;
            uT.inBuffer = null;
            uT.inLength = 0;

            uT.qTD       = CreateQTD_IO((UHCI_QueueHead_Struct *)transfer.underlyingTransferData, (uint *)1, UHCI_Consts.TD_OUT, toggle, length, transfer.device.address, transfer.endpoint, transfer.packetSize);
            uT.qTDBuffer = uT.qTD->virtBuffer;

            if (buffer != null && length != 0)
            {
                MemoryUtils.MemCpy_32((byte *)uT.qTDBuffer, (byte *)buffer, length);
            }

            if (transfer.transactions.Count > 0)
            {
                UHCITransaction uLastTransaction = (UHCITransaction)((USBTransaction)(transfer.transactions[transfer.transactions.Count - 1])).underlyingTz;
                uLastTransaction.qTD->next   = (((uint)VirtMemManager.GetPhysicalAddress(uT.qTD) & 0xFFFFFFF0) | UHCI_Consts.BIT_Vf); // build TD queue
                uLastTransaction.qTD->q_next = uT.qTD;
            }
        }
Exemplo n.º 3
0
        protected override void _SetupTransfer(USBTransfer transfer)
        {
#if UHCI_TRACE
            BasicConsole.WriteLine("UHCI: Setup Transfer");
            BasicConsole.DelayOutput(5);
#endif

            transfer.underlyingTransferData = qhPointer; // QH
        }
Exemplo n.º 4
0
        /// <summary>
        /// Sets up a SETUP transaction and adds it to the specified transfer.
        /// </summary>
        /// <param name="transfer">The transfer to which the transaction should be added.</param>
        /// <param name="tokenBytes">The number of bytes to send.</param>
        /// <param name="type">The type of the USB Request.</param>
        /// <param name="req">The specific USB Request.</param>
        /// <param name="hiVal">The USB Request Hi-Val.</param>
        /// <param name="loVal">The USB Request Lo-Val.</param>
        /// <param name="index">The USB request index.</param>
        /// <param name="length">The length of the USB request.</param>
        public void SETUPTransaction(USBTransfer transfer, ushort tokenBytes, byte type, byte req, byte hiVal, byte loVal,
                                     ushort index, ushort length)
        {
            USBTransaction transaction = new USBTransaction();

            transaction.type = USBTransactionType.SETUP;

            _SETUPTransaction(transfer, transaction, false, tokenBytes, type, req, hiVal, loVal, index, length);

            transfer.transactions.Add(transaction);

            ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle = true;
        }
Exemplo n.º 5
0
        /// <summary>
        /// Sets up an IN transaction and adds it to the specified transfer.
        /// </summary>
        /// <param name="transfer">The transfer to which the transaction should be added.</param>
        /// <param name="controlHandshake">Whether the transaction is part of a control handshake or not.</param>
        /// <param name="buffer">The buffer to store the incoming data in.</param>
        /// <param name="length">The length of the buffer.</param>
        public void INTransaction(USBTransfer transfer, bool controlHandshake, void *buffer, ushort length)
        {
#if HCI_TRACE || USB_TRACE
            BasicConsole.WriteLine(((FOS_System.String) "transfer.packetSize=") + transfer.packetSize +
                                   ", length=" + length);
#endif
            ushort clampedLength = FOS_System.Math.Min(transfer.packetSize, length);
            length -= clampedLength;
#if HCI_TRACE || USB_TRACE
            BasicConsole.WriteLine(((FOS_System.String) "clampedLength=") + clampedLength);
            BasicConsole.DelayOutput(1);
#endif
            ushort remainingTransactions = (ushort)(length / transfer.packetSize);
#if HCI_TRACE || USB_TRACE
            BasicConsole.WriteLine("Division passed.");
            BasicConsole.DelayOutput(1);
#endif
            if (length % transfer.packetSize != 0)
            {
                remainingTransactions++;
            }

            USBTransaction transaction = new USBTransaction();
            transaction.type = USBTransactionType.IN;

            if (controlHandshake) // Handshake transaction of control transfers always have toggle set to 1
            {
                ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle = true;
            }

#if HCI_TRACE
            BasicConsole.WriteLine("Call _INTransaction...");
            BasicConsole.DelayOutput(1);
#endif

            _INTransaction(transfer, transaction, ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle, buffer, clampedLength);

#if HCI_TRACE
            BasicConsole.WriteLine("Done.");
            BasicConsole.DelayOutput(1);
#endif

            transfer.transactions.Add(transaction);

            ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle = !((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle; // Switch toggle

            if (remainingTransactions > 0)
            {
                INTransaction(transfer, controlHandshake, ((byte *)buffer + clampedLength), length);
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Sets up a USB transfer for sending via the EHCI.
        /// </summary>
        /// <param name="usbDevice">The USb device to send the transfer to.</param>
        /// <param name="transfer">The transfer to send.</param>
        /// <param name="type">The type of USB transfer.</param>
        /// <param name="endpoint">The endpoint of the device to send the transfer to.</param>
        /// <param name="maxLength">The maximum packet size to use when transferring.</param>
        public void SetupTransfer(Devices.USBDeviceInfo usbDevice, USBTransfer transfer, USBTransferType type, byte endpoint,
                                  ushort maxLength)
        {
            transfer.device   = usbDevice;
            transfer.endpoint = endpoint;
            transfer.type     = type;
#if HCI_TRACE
            BasicConsole.WriteLine(((FOS_System.String) "SetupTransfer: maxLength=") + maxLength + ", endpoint=" + endpoint + ", mps=" + ((Endpoint)usbDevice.Endpoints[endpoint]).mps);
#endif
            transfer.packetSize = FOS_System.Math.Min(maxLength, ((Endpoint)usbDevice.Endpoints[endpoint]).MPS);
#if HCI_TRACE
            BasicConsole.WriteLine(((FOS_System.String) "SetupTransfer: packetSize=") + transfer.packetSize);
#endif
            transfer.success      = false;
            transfer.transactions = new List(3);

            _SetupTransfer(transfer);
        }
Exemplo n.º 7
0
        protected override void _SETUPTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, ushort tokenBytes, byte type, byte req, byte hiVal, byte loVal, ushort index, ushort length)
        {
#if UHCI_TRACE
            BasicConsole.WriteLine("UHCI: SETUP Transaction");
            BasicConsole.DelayOutput(5);
#endif

            UHCITransaction uT = new UHCITransaction();
            uTransaction.underlyingTz = uT;
            uT.inBuffer = null;
            uT.inLength = 0;

            uT.qTD       = CreateQTD_SETUP((UHCI_QueueHead_Struct *)transfer.underlyingTransferData, (uint *)1, toggle, tokenBytes, type, req, hiVal, loVal, index, length, transfer.device.address, transfer.endpoint, transfer.packetSize);
            uT.qTDBuffer = uT.qTD->virtBuffer;

            if (transfer.transactions.Count > 0)
            {
                UHCITransaction uLastTransaction = (UHCITransaction)((USBTransaction)(transfer.transactions[transfer.transactions.Count - 1])).underlyingTz;
                uLastTransaction.qTD->next   = (((uint)VirtMemManager.GetPhysicalAddress(uT.qTD) & 0xFFFFFFF0) | UHCI_Consts.BIT_Vf); // build TD queue
                uLastTransaction.qTD->q_next = uT.qTD;
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Sends a SCSI command that receives data.
        /// </summary>
        /// <param name="SCSIcommand">The SCSI command to send.</param>
        /// <param name="LBA">The LBA to access.</param>
        /// <param name="TransferLength">The length of the data to receive.</param>
        /// <param name="dataBuffer">The data buffer - must be at least as big as the transfer length.</param>
        /// <param name="statusBuffer">The buffer to store the command status result in. Must be at least 13 bytes long.</param>
        /// <see cref="!:http://www.beyondlogic.org/usbnutshell/usb4.htm#Bulk"/>
        public bool SendSCSICommand_IN(byte SCSIcommand, uint LBA, ushort TransferLength, void* dataBuffer, void* statusBuffer, bool resetOnFail = true)
        {
#if MSD_TRACE
            DBGMSG("OUT part");
            DBGMSG(((FOS_System.String)"Toggle OUT ") + ((Endpoint)DeviceInfo.Endpoints[DeviceInfo.MSD_OUTEndpointID]).toggle);
#endif
            bool OK = true;

            //Allocate memory for the command block
            //  This is passed to the out transaction as the SCSI command data.
#if MSD_TRACE
            BasicConsole.Write("CBW Size: ");
            BasicConsole.Write(sizeof(CommandBlockWrapper));
            if(sizeof(CommandBlockWrapper) != 31)
            {
                BasicConsole.WriteLine(" - INCORRECT! FAILED!");
            }
            else
            {
                BasicConsole.WriteLine(" - correct.");
            }
#endif
            CommandBlockWrapper* cbw = (CommandBlockWrapper*)FOS_System.Heap.AllocZeroed((uint)sizeof(CommandBlockWrapper), "MassStorageDevice : SendSCSICommand_IN (1)");
            bool FreeStatusBuffer = false;
            try
            {
                //Initialise the command data
                SetupSCSICommand(SCSIcommand, cbw, LBA, TransferLength);
#if MSD_TRACE
                BasicConsole.WriteLine("cbw: ");
                BasicConsole.DumpMemory(cbw, sizeof(CommandBlockWrapper));
                DBGMSG("Setup command. Transferring data...");
#endif
                // Create a new USB transfer 
                //  This transfer is re-used for all transfers throughout this method
                USBTransfer transfer = new USBTransfer();
                
                // Initialises the transfer
                //  Sets the transfer packet size, points it to the MSD OUT endpoint and sets it as a bulk transfer
                DeviceInfo.hc.SetupTransfer(DeviceInfo, transfer, USBTransferType.Bulk, DeviceInfo.MSD_OUTEndpointID, 512);
                // Adds an OUT transaction to the transfer.
                //  This OUT transaction ouptuts the SCSI command to the MSD
                DeviceInfo.hc.OUTTransaction(transfer, false, cbw, 31);
                // Issues the complete transfer to the device.
                DeviceInfo.hc.IssueTransfer(transfer);

                // If the transfer completed successfully.
                if (transfer.success)
                {
#if MSD_TRACE
                    DBGMSG("IN part");
#endif

                    // If the caller didn't provide a pre-allocated status buffer, we
                    //  must allocate one.
                    if (statusBuffer == null)
                    {
#if MSD_TRACE
                        DBGMSG("Alloc 13 bytes of mem...");
#endif
                        // And we must remember to only free it later if we created it.
                        FreeStatusBuffer = true;
                        // Create the pre-allocated buffer. Size 13 is the size of the response.
                        statusBuffer = FOS_System.Heap.AllocZeroed(13u, "MassStorageDevice : SendSCSICommand_IN (2)");
                    }

#if MSD_TRACE
                    DBGMSG("Setup transfer...");
#endif
                    // Setup a new transfer to receive the response from the device
                    DeviceInfo.hc.SetupTransfer(DeviceInfo, transfer, USBTransferType.Bulk, DeviceInfo.MSD_INEndpointID, 512);
#if MSD_TRACE
                    DBGMSG("Done.");
#endif
                    // If the amount of data to receive is greater than 0 bytes in length:
                    if (TransferLength > 0)
                    {
#if MSD_TRACE
                        DBGMSG("Setup IN transactions...");
#endif
                        // We must do an IN transaction to receive the data from the device
                        DeviceInfo.hc.INTransaction(transfer, false, dataBuffer, TransferLength);
                        // And then do the normal IN transaction to receive the status response.
                        DeviceInfo.hc.INTransaction(transfer, false, statusBuffer, 13);
#if MSD_TRACE
                        DBGMSG("Done.");
#endif
                    }
                    else
                    {
                        // No data to receive so just do the IN transaction to receive the status 
                        //  response.
                        DeviceInfo.hc.INTransaction(transfer, false, statusBuffer, 13);
                    }
#if MSD_TRACE
                    DBGMSG("Issue transfer...");
#endif
                    // Issue the transfer of IN data.
                    DeviceInfo.hc.IssueTransfer(transfer);
#if MSD_TRACE
                    DBGMSG("Done.");
                    DBGMSG("Check command...");
#endif
                    // If the transfer failed or the status response indicates failure of some form:
                    if (!transfer.success || CheckSCSICommand(statusBuffer, SCSIcommand) != 0)
                    {
                        // TODO: Handle failure/timeout
#if MSD_TRACE
                        DBGMSG("SCSI IN command failed!");
#endif
                        OK = false;

                        if (resetOnFail)
                        {
                            ResetRecoveryMSD();
                        }
                    }
#if MSD_TRACE
                    else
                    {
                        DBGMSG("Command OK.");
                        BasicConsole.DelayOutput(1);
                    }
#endif
                }
                else
                {
                    // TODO: Handle failure/timeout
                    OK = false;
#if MSD_TRACE
                    DBGMSG("SCSI OUT command failed!");
#endif
                }
            }
            finally
            {
                FOS_System.Heap.Free(cbw);
                // Only free the status buffer if we allocated it
                if (FreeStatusBuffer)
                {
                    FOS_System.Heap.Free(statusBuffer);
                }
            }

            return OK;
        }
Exemplo n.º 9
0
        /// <summary>
        /// Sets up a SETUP transaction and adds it to the specified transfer.
        /// </summary>
        /// <param name="transfer">The transfer to which the transaction should be added.</param>
        /// <param name="tokenBytes">The number of bytes to send.</param>
        /// <param name="type">The type of the USB Request.</param>
        /// <param name="req">The specific USB Request.</param>
        /// <param name="hiVal">The USB Request Hi-Val.</param>
        /// <param name="loVal">The USB Request Lo-Val.</param>
        /// <param name="index">The USB request index.</param>
        /// <param name="length">The length of the USB request.</param>
        public void SETUPTransaction(USBTransfer transfer, ushort tokenBytes, byte type, byte req, byte hiVal, byte loVal, 
                                     ushort index, ushort length)
        {
            USBTransaction transaction = new USBTransaction();
            transaction.type = USBTransactionType.SETUP;

            _SETUPTransaction(transfer, transaction, false, tokenBytes, type, req, hiVal, loVal, index, length);

            transfer.transactions.Add(transaction);

            ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle = true;
        }
Exemplo n.º 10
0
        /// <summary>
        /// Issues the specified transfer to the physical device via the async schedule.
        /// </summary>
        /// <param name="transfer">The transfer to issue.</param>
        protected override void _IssueTransfer(USBTransfer transfer)
        {
            if (HostSystemErrors > 0 || IrrecoverableError)
            {
                ExceptionMethods.Throw(new FOS_System.Exception("Cannot issue transfer through EHCI because the host controller has encountered a host system error."));
            }
            else if (HCHalted)
            {
                ExceptionMethods.Throw(new FOS_System.Exception("Cannot issue transfer through EHCI because the host controller is currently halted."));
            }

            // Please note: The word "completed" is not synonymous with "succeeded". 
            //              "Completed" means the hardware, firmware or software finished
            //              processing something.
            //              "Succeeded" means the hardware, firmware or software finished
            //              processing something and there were no errors during processing.

            // Get the last qTD of the transfer
            EHCITransaction lastTransaction = (EHCITransaction)((USBTransaction)transfer.transactions[transfer.transactions.Count - 1]).underlyingTz;
            EHCI_qTD lastQTD = lastTransaction.qTD;
            // Enable the Interrupt on Complete. This allows us to detect the end of the entire transfer 
            //  when the USB Interrupt occurs.
            lastQTD.InterruptOnComplete = true;

#if EHCI_TRACE
            //Test walking the transaction tree
            bool treeOK = true;
            for (int k = 0; k < transfer.transactions.Count - 1; k++)
            {
                EHCITransaction transaction1 = (EHCITransaction)((USBTransaction)transfer.transactions[k]).underlyingTz;
                EHCITransaction transaction2 = (EHCITransaction)((USBTransaction)transfer.transactions[k + 1]).underlyingTz;
                EHCI_qTD qtd1 = transaction1.qTD;
                treeOK = treeOK && (qtd1.NextqTDPointer == VirtMemManager.GetPhysicalAddress(transaction2.qTD.qtd)) && !qtd1.NextqTDPointerTerminate;
                if (!treeOK)
                {
                    BasicConsole.Write(((FOS_System.String)"Incorrect tansfer index: ") + k);
                    if (qtd1.NextqTDPointer != VirtMemManager.GetPhysicalAddress(transaction2.qTD.qtd))
                    {
                        BasicConsole.WriteLine(((FOS_System.String)"    > Pointers incorrect! QTD1.NextPtr=") + (uint)qtd1.NextqTDPointer + ", &QTD2=" + (uint)VirtMemManager.GetPhysicalAddress(transaction2.qTD.qtd));
                    }
                    else if (qtd1.NextqTDPointerTerminate)
                    {
                        BasicConsole.WriteLine("    > QTD1.NextTerminate incorrect!");
                    }
                    else
                    {
                        BasicConsole.WriteLine("    > Previous transaction was incorrect.");
                    }
                }
            }
            {
                treeOK = treeOK && lastQTD.NextqTDPointerTerminate;
                if (!treeOK)
                {
                    BasicConsole.WriteLine("Incorrect tansfer index: last");
                    if (!lastQTD.NextqTDPointerTerminate)
                    {
                        BasicConsole.WriteLine("    > LastQTD.NextTerminate incorrect!");
                    }
                    else
                    {
                        BasicConsole.WriteLine("    > Previous transaction was incorrect.");
                    }
                }
            }
            DBGMSG(((FOS_System.String)"Transfer transactions tree OK: ") + treeOK);
            BasicConsole.DelayOutput(10);
#endif
            // Get the first qTD of the transfer. This is passed to InitQH to tell it the start of the linked
            //  list of transactions.
            EHCITransaction firstTransaction = (EHCITransaction)((USBTransaction)(transfer.transactions[0])).underlyingTz;
            // Init the Queue Head for this transfer
            InitQH((EHCI_QueueHead_Struct*)transfer.underlyingTransferData, 
                   (EHCI_QueueHead_Struct*)transfer.underlyingTransferData, 
                   firstTransaction.qTD.qtd, 
                   false, 
                   transfer.device.address, 
                   transfer.endpoint, 
                   transfer.packetSize);
            
            // Attempt to issue the transfer until it either succeeds or we reach our 
            //  maximum number of retries or an irrecoverable host system error occurs. 
            //  The maxmimum number of retries is an entirely arbitary, internal number.
            for (byte i = 0; i < EHCI_Consts.NumAsyncListRetries && !transfer.success && !IrrecoverableError; i++)
            {
#if EHCI_TRACE
                transfer.success = true;
                for (int k = 0; k < transfer.transactions.Count; k++)
                {
                    EHCITransaction transaction = (EHCITransaction)((USBTransaction)transfer.transactions[k]).underlyingTz;
                    byte status = transaction.qTD.Status;
                    transfer.success = transfer.success && (status == 0 || status == Utils.BIT(0));

                    DBGMSG(((FOS_System.String)"PRE Issue: Transaction ") + k + " status: " + status);
                }
                if (!transfer.success)
                {
                    DBGMSG("EHCI: PRE Issue - Transfer detected as failed.");
                    BasicConsole.DelayOutput(1);
                }
                else
                {
                    DBGMSG("EHCI: PRE Issue - Transfer OK.");
                }
#endif
                // Add it to the async schedule. This will cause the HC to attempt to send the transactions.
                //  This is a blocking method that waits until the HC signals the last transaction of the 
                //  transfer is complete. This does not mean all or the last transaction completed succesfully.
                AddToAsyncSchedule(transfer);
                // If during the transfer we hit an irrecoverable host system error:
                if (IrrecoverableError)
                {
                    // Mark the transfer as failed
                    transfer.success = false;
#if EHCI_TRACE
                    DBGMSG("EHCI: Irrecoverable error! No retry.");
                    BasicConsole.DelayOutput(2);
#endif
                }
                else
                {
                    // Assume the transfer succeeded to start with
                    transfer.success = true;
                    // Then check each transaction to see if it succeeded.
                    for (int k = 0; k < transfer.transactions.Count; k++)
                    {
                        // Get the transaction to check
                        EHCITransaction transaction = (EHCITransaction)((USBTransaction)transfer.transactions[k]).underlyingTz;
                        // Get the transaction's status
                        byte status = transaction.qTD.Status;
                        // If the status == 0, it indicates success
                        // If bit 0 of the status is set and the other buts are 0, 
                        //  then since this must be a High Speed endpoint, it is just the
                        //  Ping State.
                        // It is worth noting that the Ping State bit is only valid if the 
                        //  endpoint is an OUT endpoint. However, the specification also suggests
                        //  the this bit is only an error bit if the device is a low- or full-speed
                        //  device. This means the value for IN endpoints on High Speed devices is 
                        //  somewhat undefined and I am lead to assume the value must always be 0.
                        transfer.success = transfer.success && (status == 0 || status == Utils.BIT(0));

#if EHCI_TRACE
                        DBGMSG(((FOS_System.String)"POST Issue: Transaction ") + k + " status: " + status);
#endif
                    }

#if EHCI_TRACE
                    if (!transfer.success)
                    {
                        DBGMSG(((FOS_System.String)"EHCI: Retry transfer: ") + (i + 1));
                        BasicConsole.DelayOutput(2);

                        // Reset the status bits so the transactions are active again
                        for (int k = 0; k < transfer.transactions.Count; k++)
                        {
                            EHCITransaction transaction = (EHCITransaction)((USBTransaction)transfer.transactions[k]).underlyingTz;
                            byte status = transaction.qTD.Status;
                            if (!(status == 0 || status == Utils.BIT(0)))
                            {
                                transaction.qTD.Status = 0x80;
                            }
                        }
                    }
#endif
                }
            }

            // After the transfer has completed, we can free the underlying queue head memory.
            //        At this point we use the Async Doorbell to confirm the
            //        HC has finished using the queue head and that all caches of 
            //        pointers to the queue head have been released. 

            AsyncDoorbellIntCount = 1;
            USBCMD |= EHCI_Consts.CMD_AsyncInterruptDoorbellMask;
            while (AsyncDoorbellIntCount > 0)
            {
                Kernel.Processes.SystemCalls.SleepThread(5);
            }

            FOS_System.Heap.Free(transfer.underlyingTransferData);
            // Loop through each transaction in the transfer
            for (int k = 0; k < transfer.transactions.Count; k++)
            {
                // Get the current transaction
                EHCITransaction transaction = (EHCITransaction)((USBTransaction)transfer.transactions[k]).underlyingTz;
                // Create a wrapper for the underlying qTD of the transaction
                EHCI_qTD theQTD = transaction.qTD;

                // If the transaction has an input buffer, we must copy the input data from the qTD
                //  to the input buffer. 
                // Note: The reason the qTD has a different buffer to the input buffer is because when
                //       the input buffer was provided, there was no guarantee it had been properly 
                //       allocated (i.e. size and alignment may have been incorrect)
                if (transaction.inBuffer != null && transaction.inLength != 0)
                {
#if EHCI_TRACE
                    DBGMSG(((FOS_System.String)"Doing MemCpy of in data... inBuffer=") + (uint)transaction.inBuffer + 
                                               ", qTDBuffer=" + (uint)transaction.qTD.qtd + 
                                               ", inLength=" + transaction.inLength + ", Data to copy: ");
#endif
                    // Copy the memory
                    Utilities.MemoryUtils.MemCpy_32((byte*)transaction.inBuffer, theQTD.Buffer0VirtAddr, transaction.inLength);

#if EHCI_TRACE
                    //for (int i = 0; i < transaction.inLength; i++)
                    //{
                    //    DBGMSG(((FOS_System.String)"i=") + i + ", qTDBuffer[i]=" + ((byte*)transaction.qTD.qtd)[i] + ", inBuffer[i]=" + ((byte*)transaction.inBuffer)[i]);
                    //}
#endif
#if EHCI_TRACE
                    DBGMSG("Done.");
                    BasicConsole.DelayOutput(2);
#endif
                }
                // Free the qTD buffer(s)
                FOS_System.Heap.Free(theQTD.Buffer0VirtAddr);
                // Free the qTD
                theQTD.Free();
            }

#if EHCI_TRACE
            if (transfer.success)
            {
                DBGMSG("EHCI: Transfer succeeded.");
            }
            else
            {
                DBGMSG("EHCI:IssueTransfer(): Transfer failed.");
            }
            BasicConsole.DelayOutput(2);
#endif
        }
Exemplo n.º 11
0
        /// <summary>
        /// Sets up an IN transaction and adds it to the specified transfer.
        /// </summary>
        /// <param name="transfer">The transfer to which the transaction should be added.</param>
        /// <param name="uTransaction">The USB Transaction to convert to an EHCI transaction.</param>
        /// <param name="toggle">The transaction toggle state.</param>
        /// <param name="buffer">The buffer to store the incoming data in.</param>
        /// <param name="length">The length of the buffer.</param>
        protected override void _INTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, void* buffer, ushort length)
        {
            // Create an EHCI-specific object to describe the transaction
            EHCITransaction eTransaction = new EHCITransaction();
            // Store the underlying HC-specific transaction info
            uTransaction.underlyingTz = eTransaction;
            // IN transaction so use the supplied input data buffer
            eTransaction.inBuffer = buffer;
            eTransaction.inLength = length;

#if EHCI_TRACE
            DBGMSG(((FOS_System.String)"IN Transaction : buffer=") + (uint)buffer);

            DBGMSG(((FOS_System.String)"IN Transaction : Before CreateQTD : bufferPtr=&qTDBuffer=") + (uint)buffer);
#endif

            // Create and initialise the IN queue transfer descriptor
            eTransaction.qTD = CreateQTD_IO(null, 1, toggle, length, length);

#if EHCI_TRACE
            DBGMSG(((FOS_System.String)"IN Transaction : After CreateQTD : bufferPtr=&qTDBuffer=") + (uint)buffer + ", Buffer0=" + (uint)eTransaction.qTD.Buffer0);
#endif
            // If the number of existing transactions is greater than 0
            //  i.e. some transactions have already been added. 
            if (transfer.transactions.Count > 0)
            {
                // Get the previous (i.e. last) transaction then the underlying transaction from it
                EHCITransaction eLastTransaction = (EHCITransaction)((USBTransaction)(transfer.transactions[transfer.transactions.Count - 1])).underlyingTz;
                // Create a wrapper for the last transaction (qTD)
                EHCI_qTD lastQTD = eLastTransaction.qTD;
                // Set the Next Transaction (qTD) Pointer on the previous qTD to point to the qTD
                //  we just created. 
                // Note: The NextqTDPointer must be the physical address of qTD data.
                lastQTD.NextqTDPointer = (EHCI_qTD_Struct*)VirtMemManager.GetPhysicalAddress(eTransaction.qTD.qtd);
                // Mark the previous qTD's Next Transaction Pointer as valid.
                lastQTD.NextqTDPointerTerminate = false;
            }
        }
Exemplo n.º 12
0
 /// <summary>
 /// Sets up a USB transfer for sending via the EHCI.
 /// </summary>
 /// <param name="transfer">The transfer to set up.</param>
 protected override void _SetupTransfer(USBTransfer transfer)
 { 
     // Allocate memory for the transfer strcture. This is a queue head strcture.
     //  It gets appended to the end of the Async Queue in AddToAsyncSchedule.
     // This memory must be allocated on a 32-byte boundary as per EHCI spec.
     //      "The memory structure referenced by this physical memory pointer is 
     //       assumed to be 32-byte (cache line) aligned."
     //  Section 2.3.7 of Intel EHCI Spec
     // Note: This sets the virtual address. This allows it to be accessed and freed by the 
     //       driver. However, when passing the address to the HC, it must be converted to
     //       a physical address.
     transfer.underlyingTransferData = (EHCI_QueueHead_Struct*)FOS_System.Heap.AllocZeroedAPB((uint)sizeof(EHCI_QueueHead_Struct), 32, "EHCI : _SetupTransfer");
 }
Exemplo n.º 13
0
        protected override void _SetupTransfer(USBTransfer transfer)
        {
#if UHCI_TRACE
            BasicConsole.WriteLine("UHCI: Setup Transfer");
            BasicConsole.DelayOutput(5);
#endif

            transfer.underlyingTransferData = qhPointer; // QH
        }
Exemplo n.º 14
0
        /// <summary>
        /// Sets up an OUT transaction and adds it to the specified transfer.
        /// </summary>
        /// <param name="transfer">The transfer to which the transaction should be added.</param>
        /// <param name="controlHandshake">Whether the transaction is part of a control handshake or not.</param>
        /// <param name="buffer">The buffer of outgoing data.</param>
        /// <param name="length">The length of the buffer.</param>
        public void OUTTransaction(USBTransfer transfer, bool controlHandshake, void* buffer, ushort length)
        {
            ushort clampedLength = FOS_System.Math.Min(transfer.packetSize, length);
            length -= clampedLength;
            ushort remainingTransactions = (ushort)(length / transfer.packetSize);
            if (length % transfer.packetSize != 0)
                remainingTransactions++;

            USBTransaction transaction = new USBTransaction();
            transaction.type = USBTransactionType.OUT;

            if (controlHandshake) // Handshake transaction of control transfers always have toggle set to 1
            {
                ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle = true;
            }

            _OUTTransaction(transfer, transaction, ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle, buffer, clampedLength);

            transfer.transactions.Add(transaction);

            ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle = !((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle; // Switch toggle

            if (remainingTransactions > 0)
            {
                OUTTransaction(transfer, controlHandshake, ((byte*)buffer + clampedLength), length);
            }
        }
Exemplo n.º 15
0
        /// <summary>
        /// Sends a SCSI command that sends data.
        /// </summary>
        /// <param name="SCSIcommand">The SCSI command to send.</param>
        /// <param name="LBA">The LBA to access.</param>
        /// <param name="TransferLength">The length of the data to send.</param>
        /// <param name="dataBuffer">The data buffer - must be at least as long as the transfer length.</param>
        /// <param name="statusBuffer">The data buffer to store the command status result in. Must be at least 13 bytes long.</param>
        public void SendSCSICommand_OUT(byte SCSIcommand, uint LBA, ushort TransferLength, void* dataBuffer, void* statusBuffer)
        {
#if MSD_TRACE
            DBGMSG("OUT part");
            DBGMSG(((FOS_System.String)"Toggle OUT ") + ((Endpoint)DeviceInfo.Endpoints[DeviceInfo.MSD_OUTEndpointID]).toggle);
#endif

            //This method work pretty much the same as the SendSCSICommand_IN method so see there for docs.

            CommandBlockWrapper* cbw = (CommandBlockWrapper*)FOS_System.Heap.AllocZeroed((uint)sizeof(CommandBlockWrapper), "MassStorageDevice : SendSCSICommand_OUT (1)");
            bool FreeStatusBuffer = false;
            try
            {
                SetupSCSICommand(SCSIcommand, cbw, LBA, TransferLength);

#if MSD_TRACE
                DBGMSG("Setup transfer...");
#endif
                //Issue the command transfer
                USBTransfer transfer = new USBTransfer();
                DeviceInfo.hc.SetupTransfer(DeviceInfo, transfer, USBTransferType.Bulk, DeviceInfo.MSD_OUTEndpointID, 512);
                DeviceInfo.hc.OUTTransaction(transfer, false, cbw, 31);
                DeviceInfo.hc.IssueTransfer(transfer);

                // If the command transfer completed successfully:
                if (transfer.success)
                {
                    //Issue the output data transfer
                    //  Through much testing / debugging I discovered that you cannot do the data OUT
                    //  transaction in the same transfer as the command OUT transaction. This seems odd
                    //  to me and I have not found any documentation or specification to back up this
                    //  behaviour. There are two possibilities here:
                    //      1) This is a genuine part of some spec / requirement, in which case we have
                    //          no issue.
                    //      2) Or my implementation for issusing multiple OUT transactions in a row in 
                    //          one is broken. In this case, I have failed to find out what causes ths issue 
                    //          / why it occurs.
                    DeviceInfo.hc.SetupTransfer(DeviceInfo, transfer, USBTransferType.Bulk, DeviceInfo.MSD_OUTEndpointID, 512);
                    DeviceInfo.hc.OUTTransaction(transfer, false, dataBuffer, TransferLength);
                    DeviceInfo.hc.IssueTransfer(transfer);

#if MSD_TRACE
                    if (!transfer.success)
                    {
                        DBGMSG("Transfer 2 failed!");
                        BasicConsole.DelayOutput(5);
                    }
#endif
                }
#if MSD_TRACE
                else
                {
                    DBGMSG("Transfer 1 failed!");
                    BasicConsole.DelayOutput(5);
                }
#endif
                // If the command and data transfers completed successfully:
                if (transfer.success)
                {
#if MSD_TRACE
                    DBGMSG("IN part");
#endif

                    if (statusBuffer == null)
                    {
#if MSD_TRACE
                        DBGMSG("Alloc 13 bytes of mem...");
#endif
                        FreeStatusBuffer = true;
                        statusBuffer = FOS_System.Heap.AllocZeroed(13u, "MassStorageDevice : SendSCSICommand_OUT (2)");
                    }

#if MSD_TRACE
                    DBGMSG("Setup transfer...");
#endif
                    DeviceInfo.hc.SetupTransfer(DeviceInfo, transfer, USBTransferType.Bulk, DeviceInfo.MSD_INEndpointID, 512);
#if MSD_TRACE
                    DBGMSG("Done.");
#endif
                    DeviceInfo.hc.INTransaction(transfer, false, statusBuffer, 13);
#if MSD_TRACE
                    DBGMSG("Issue transfer...");
#endif
                    DeviceInfo.hc.IssueTransfer(transfer);
#if MSD_TRACE
                    DBGMSG("Done.");
                    DBGMSG("Check command...");
#endif

                    if (!transfer.success || CheckSCSICommand(statusBuffer, SCSIcommand) != 0)
                    {
                        // TODO: Handle failure/timeout
#if MSD_TRACE
                        DBGMSG("SCSI IN command failed!");
#endif
                    }
#if MSD_TRACE
                    else
                    {
                        DBGMSG("Command OK.");
                        BasicConsole.DelayOutput(1);
                    }
#endif
                }
                else
                {
                    // TODO: Handle failure/timeout
#if MSD_TRACE
                    DBGMSG("SCSI OUT command failed!");
#endif
                }
            }
            finally
            {
                FOS_System.Heap.Free(cbw);
                if (FreeStatusBuffer)
                {
                    FOS_System.Heap.Free(statusBuffer);
                }
            }
        }
Exemplo n.º 16
0
 /// <summary>
 /// Issues the specified transfer to the physical device.
 /// </summary>
 /// <param name="transfer">The transfer to issue.</param>
 public void IssueTransfer(USBTransfer transfer)
 {
     _IssueTransfer(transfer);
 }
Exemplo n.º 17
0
 /// <summary>
 /// When overridden in a derived class, handles HC implementation specific method of issuing a transfer.
 /// </summary>
 /// <param name="transfer">The transfer to issue.</param>
 protected abstract void _IssueTransfer(USBTransfer transfer);
Exemplo n.º 18
0
 /// <summary>
 /// When overridden in a derived class, handles HC implementation specific OUT transaction initialisation.
 /// </summary>
 /// <param name="transfer">The transfer to which the transaction should be added.</param>
 /// <param name="uTransaction">The USB Transaction to convert to an EHCI transaction.</param>
 /// <param name="toggle">The transaction toggle state.</param>
 /// <param name="buffer">The buffer of outgoing data.</param>
 /// <param name="length">The length of the buffer.</param>
 protected abstract void _OUTTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, void* buffer, ushort length);
Exemplo n.º 19
0
 /// <summary>
 /// When overridden in a derived class, handles HC implementation specific SETUP transaction initialisation.
 /// </summary>
 /// <param name="transfer">The transfer to which the transaction should be added.</param>
 /// <param name="uTransaction">The USB Transaction to convert to an EHCI Transaction.</param>
 /// <param name="toggle">The transaction toggle state.</param>
 /// <param name="tokenBytes">The number of bytes to send.</param>
 /// <param name="type">The type of the USB Request.</param>
 /// <param name="req">The specific USB Request.</param>
 /// <param name="hiVal">The USB Request Hi-Val.</param>
 /// <param name="loVal">The USB Request Lo-Val.</param>
 /// <param name="index">The USB request index.</param>
 /// <param name="length">The length of the USB request.</param>
 protected abstract void _SETUPTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, ushort tokenBytes,
                                    byte type, byte req, byte hiVal, byte loVal, ushort index, ushort length);
Exemplo n.º 20
0
 /// <summary>
 /// When overridden in a derived class, handles HC implementation specific transfer initialisation.
 /// </summary>
 /// <param name="transfer">The transfer to set up.</param>
 protected abstract void _SetupTransfer(USBTransfer transfer);
Exemplo n.º 21
0
        /// <summary>
        /// Sends a SCSI Sync Cache command.
        /// </summary>
        /// <param name="SyncNV">
        /// Whether the device is required to sync volatile and non-volatile caches or not. Specify 
        /// "false" to force full cache sync including non-volatile caches. Specify "true" to force 
        /// sync volatile caches and optionally sync non-volatile caches (up to the specific device
        /// what it does).
        /// </param>
        /// <param name="ImmediateResponse">
        /// Whether the device should send the status response as soon as the command is recognised
        /// or the device should only send the response once the sync is completed. Specify "false"
        /// for the latter option.
        /// </param>
        /// <param name="LBA">The LBA of the first block to sync.</param>
        /// <param name="Blocks">
        /// The number of blocks to sync. Specify 0 to sync all the blocks from the start LBA through
        /// to the end of the device.
        /// </param>
        /// <param name="statusBuffer">
        /// Buffer for the status response. Specify null if you don't want to keep the response data.
        /// </param>
        public void SendSCSI_SyncCacheCommand(bool SyncNV, bool ImmediateResponse, uint LBA, ushort Blocks, void* statusBuffer)
        {
            #if MSD_TRACE
            DBGMSG("SyncCache Command");
            DBGMSG("OUT part");
            DBGMSG(((FOS_System.String)"Toggle OUT ") + ((Endpoint)DeviceInfo.Endpoints[DeviceInfo.MSD_OUTEndpointID]).toggle);
            #endif

            CommandBlockWrapper* cbw = (CommandBlockWrapper*)FOS_System.Heap.AllocZeroed((uint)sizeof(CommandBlockWrapper), "MassStorageDevice : SendSCSI_SyncCacheCommand (1)");
            bool FreeStatusBuffer = false;
            try
            {
                SetupSCSICommand(0x35, cbw, LBA, Blocks);
                cbw->commandByte[1] = (byte)((SyncNV ? 0x4 : 0) | (ImmediateResponse ? 0x2 : 0));

                #if MSD_TRACE
                DBGMSG("Setup transfer...");
                #endif
                USBTransfer transfer = new USBTransfer();
                DeviceInfo.hc.SetupTransfer(DeviceInfo, transfer, USBTransferType.Bulk, DeviceInfo.MSD_OUTEndpointID, 512);
                DeviceInfo.hc.OUTTransaction(transfer, false, cbw, 31);
                DeviceInfo.hc.IssueTransfer(transfer);


                if (transfer.success)
                {
                    #if MSD_TRACE
                    DBGMSG("IN part");
                    #endif

                    if (statusBuffer == null)
                    {
                        #if MSD_TRACE
                        DBGMSG("Alloc 13 bytes of mem...");
                        #endif
                        FreeStatusBuffer = true;
                        statusBuffer = FOS_System.Heap.AllocZeroed(13u, "MassStorageDevice : SendSCSI_SyncCacheCommand (2)");
                    }

                    #if MSD_TRACE
                    DBGMSG("Setup transfer...");
                    #endif
                    DeviceInfo.hc.SetupTransfer(DeviceInfo, transfer, USBTransferType.Bulk, DeviceInfo.MSD_INEndpointID, 512);
                    #if MSD_TRACE
                    DBGMSG("Done.");
                    #endif
                    DeviceInfo.hc.INTransaction(transfer, false, statusBuffer, 13);
                    #if MSD_TRACE
                    DBGMSG("Issue transfer...");
                    #endif
                    DeviceInfo.hc.IssueTransfer(transfer);
                    #if MSD_TRACE
                    DBGMSG("Done.");
                    DBGMSG("Check command...");
                    #endif

                    if (!transfer.success || CheckSCSICommand(statusBuffer, 0x35) != 0)
                    {
                        // TODO: Handle failure/timeout
                        #if MSD_TRACE
                        DBGMSG("SCSI SyncCaches (10) (In) command failed!");
                        #endif
                    }
                    #if MSD_TRACE
                    else
                    {
                        DBGMSG("Command OK.");
                        BasicConsole.DelayOutput(1);
                    }
                    #endif
                }
                else
                {
                    // TODO: Handle failure/timeout
                    #if MSD_TRACE
                    DBGMSG("SCSI SyncCache (10) (Out) command failed!");
                    #endif
                }
            }
            finally
            {
                FOS_System.Heap.Free(cbw);
                if (FreeStatusBuffer)
                {
                    FOS_System.Heap.Free(statusBuffer);
                }
            }
        }
Exemplo n.º 22
0
        protected override void _SETUPTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, ushort tokenBytes, byte type, byte req, byte hiVal, byte loVal, ushort index, ushort length)
        {
#if UHCI_TRACE
            BasicConsole.WriteLine("UHCI: SETUP Transaction");
            BasicConsole.DelayOutput(5);
#endif

            UHCITransaction uT = new UHCITransaction();
            uTransaction.underlyingTz = uT;
            uT.inBuffer = null;
            uT.inLength = 0;

            uT.qTD = CreateQTD_SETUP((UHCI_QueueHead_Struct*)transfer.underlyingTransferData, (uint*)1, toggle, tokenBytes, type, req, hiVal, loVal, index, length, transfer.device.address, transfer.endpoint, transfer.packetSize);
            uT.qTDBuffer = uT.qTD->virtBuffer;

            if (transfer.transactions.Count > 0)
            {
                UHCITransaction uLastTransaction = (UHCITransaction)((USBTransaction)(transfer.transactions[transfer.transactions.Count - 1])).underlyingTz;
                uLastTransaction.qTD->next = (((uint)VirtMemManager.GetPhysicalAddress(uT.qTD) & 0xFFFFFFF0) | UHCI_Consts.BIT_Vf); // build TD queue
                uLastTransaction.qTD->q_next = uT.qTD;
            }
        }
Exemplo n.º 23
0
 /// <summary>
 /// Issues the specified transfer to the physical device.
 /// </summary>
 /// <param name="transfer">The transfer to issue.</param>
 public void IssueTransfer(USBTransfer transfer)
 {
     _IssueTransfer(transfer);
 }
Exemplo n.º 24
0
        /// <summary>
        /// Sets up an IN transaction and adds it to the specified transfer.
        /// </summary>
        /// <param name="transfer">The transfer to which the transaction should be added.</param>
        /// <param name="controlHandshake">Whether the transaction is part of a control handshake or not.</param>
        /// <param name="buffer">The buffer to store the incoming data in.</param>
        /// <param name="length">The length of the buffer.</param>
        public void INTransaction(USBTransfer transfer, bool controlHandshake, void* buffer, ushort length)
        {
#if HCI_TRACE || USB_TRACE
            BasicConsole.WriteLine(((FOS_System.String)"transfer.packetSize=") + transfer.packetSize +
                                                       ", length=" + length);
#endif
            ushort clampedLength = FOS_System.Math.Min(transfer.packetSize, length);
            length -= clampedLength;
#if HCI_TRACE || USB_TRACE
            BasicConsole.WriteLine(((FOS_System.String)"clampedLength=") + clampedLength);
            BasicConsole.DelayOutput(1);
#endif
            ushort remainingTransactions = (ushort)(length / transfer.packetSize);
#if HCI_TRACE || USB_TRACE
            BasicConsole.WriteLine("Division passed.");
            BasicConsole.DelayOutput(1);
#endif
            if (length % transfer.packetSize != 0)
            {
                remainingTransactions++;
            }

            USBTransaction transaction = new USBTransaction();
            transaction.type = USBTransactionType.IN;

            if (controlHandshake) // Handshake transaction of control transfers always have toggle set to 1
            {
                ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle = true;
            }

#if HCI_TRACE
            BasicConsole.WriteLine("Call _INTransaction...");
            BasicConsole.DelayOutput(1);
#endif

            _INTransaction(transfer, transaction, ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle, buffer, clampedLength);

#if HCI_TRACE
            BasicConsole.WriteLine("Done.");
            BasicConsole.DelayOutput(1);
#endif

            transfer.transactions.Add(transaction);

            ((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle = !((Endpoint)transfer.device.Endpoints[transfer.endpoint]).Toggle; // Switch toggle

            if (remainingTransactions > 0)
            {
                INTransaction(transfer, controlHandshake, ((byte*)buffer + clampedLength), length);
            }
        }
Exemplo n.º 25
0
        protected override void _IssueTransfer(USBTransfer transfer)
        {
#if UHCI_TRACE
            BasicConsole.WriteLine("UHCI: Issue Transfer");
            BasicConsole.DelayOutput(5);
#endif

            UHCITransaction firstTransaction = (UHCITransaction)((USBTransaction)transfer.transactions[0]).underlyingTz;
            UHCITransaction lastTransaction  = (UHCITransaction)((USBTransaction)transfer.transactions[transfer.transactions.Count - 1]).underlyingTz;
            UHCI_qTD.SetIntOnComplete(lastTransaction.qTD, true);  // We want an interrupt after complete transfer
            CreateQH((UHCI_QueueHead_Struct *)transfer.underlyingTransferData, (uint)transfer.underlyingTransferData, firstTransaction.qTD);

#if UHCI_TRACE
            BasicConsole.WriteLine("    Queue head data:");
            BasicConsole.DumpMemory(transfer.underlyingTransferData, sizeof(UHCI_QueueHead_Struct));
            BasicConsole.WriteLine("    Transactions data:");
            for (int i = 0; i < transfer.transactions.Count; i++)
            {
                BasicConsole.Write(" ");
                BasicConsole.Write(i);
                BasicConsole.WriteLine(" : ");
                BasicConsole.WriteLine("  - qTD:");
                BasicConsole.DumpMemory(
                    ((UHCITransaction)((USBTransaction)transfer.transactions[i]).underlyingTz).qTD, sizeof(UHCI_qTD_Struct));
                BasicConsole.WriteLine("  - qTDBuffer:");
                BasicConsole.DumpMemory(
                    ((UHCITransaction)((USBTransaction)transfer.transactions[i]).underlyingTz).qTDBuffer, 16);
            }
            BasicConsole.DelayOutput(60);

            BasicConsole.WriteLine("UHCI: Issuing transfer...");
#endif

            for (byte i = 0; i < UHCI_Consts.NUMBER_OF_UHCI_RETRIES && !transfer.success; i++)
            {
                TransactionsCompleted = 0;
                for (int j = 0; j < transfer.transactions.Count; j++)
                {
                    USBTransaction  elem = (USBTransaction)transfer.transactions[j];
                    UHCITransaction uT   = (UHCITransaction)(elem.underlyingTz);
                    uT.qTD->u1 = uT.qTD->u1 & 0xFF00FFFF;
                    UHCI_qTD.SetActive(uT.qTD, true);
                }

                // stop scheduler
                USBSTS.Write_UInt16(UHCI_Consts.STS_MASK);
                USBCMD.Write_UInt16((ushort)(USBCMD.Read_UInt16() & ~UHCI_Consts.CMD_RS));
                while ((USBSTS.Read_UInt16() & UHCI_Consts.STS_HCHALTED) == 0)
                {
                    Hardware.Devices.Timer.Default.Wait(10);
                }

                // update scheduler
                uint qhPhysAddr = ((uint)VirtMemManager.GetPhysicalAddress(transfer.underlyingTransferData) | UHCI_Consts.BIT_QH);
                FrameList[0] = qhPhysAddr;
                FRBASEADD.Write_UInt32((uint)VirtMemManager.GetPhysicalAddress(FrameList));
                FRNUM.Write_UInt16(0);
                // start scheduler
                USBSTS.Write_UInt16(UHCI_Consts.STS_MASK);
                USBCMD.Write_UInt16((ushort)(USBCMD.Read_UInt16() | UHCI_Consts.CMD_RS));
                while ((USBSTS.Read_UInt16() & UHCI_Consts.STS_HCHALTED) != 0)
                {
                    Hardware.Devices.Timer.Default.Wait(10);
                }

#if UHCI_TRACE
                BasicConsole.WriteLine(((FOS_System.String) "USBINT val: ") + USBINTR.Read_UInt16());
#endif

                // run transactions
                bool active  = true;
                int  timeout = 100; //5 seconds
                while (active && timeout > 0)
                {
                    active = false;
                    for (int j = 0; j < transfer.transactions.Count; j++)
                    {
                        USBTransaction  elem = (USBTransaction)transfer.transactions[j];
                        UHCITransaction uT   = (UHCITransaction)(elem.underlyingTz);
                        active = active || ((uT.qTD->u1 & 0x00FF0000) == 0x00800000);
                    }

                    Hardware.Devices.Timer.Default.Wait(50);
                    timeout--;
                }

#if UHCI_TRACE
                BasicConsole.WriteLine("Finished waiting.");
#endif

                FrameList[0] = UHCI_Consts.BIT_T;

                if (timeout == 0 ||
                    TransactionsCompleted != transfer.transactions.Count)
                {
#if UHCI_TRACE
                    BasicConsole.SetTextColour(BasicConsole.error_colour);
                    BasicConsole.WriteLine("UHCI: Error! Transactions wait timed out or wrong number of transactions completed.");
                    BasicConsole.SetTextColour(BasicConsole.default_colour);

                    BasicConsole.WriteLine(((FOS_System.String) "Transactions completed: ") + TransactionsCompleted);

                    if (timeout == 0)
                    {
                        BasicConsole.SetTextColour(BasicConsole.error_colour);
                        BasicConsole.WriteLine("UHCI: Error! Transfer timed out.");
                        BasicConsole.SetTextColour(BasicConsole.default_colour);
                    }
#endif

                    transfer.success = false;

                    bool completeDespiteNoInterrupt = true;
                    for (int j = 0; j < transfer.transactions.Count; j++)
                    {
                        USBTransaction  elem = (USBTransaction)transfer.transactions[j];
                        UHCITransaction uT   = (UHCITransaction)(elem.underlyingTz);

#if UHCI_TRACE
                        BasicConsole.WriteLine(((FOS_System.String) "u1=") + uT.qTD->u1 + ", u2=" + uT.qTD->u2);
                        BasicConsole.WriteLine(((FOS_System.String) "Status=") + (byte)(uT.qTD->u1 >> 16));
#endif
                        completeDespiteNoInterrupt = completeDespiteNoInterrupt && isTransactionSuccessful(uT);
                    }

                    transfer.success = completeDespiteNoInterrupt;

#if UHCI_TRACE
                    BasicConsole.SetTextColour(BasicConsole.warning_colour);
                    BasicConsole.WriteLine(((FOS_System.String) "Complete despite no interrupts: ") + completeDespiteNoInterrupt);
                    BasicConsole.SetTextColour(BasicConsole.default_colour);

                    BasicConsole.DelayOutput(5);
#endif
                }
                else
                {
                    transfer.success = true;
                }

                if (transfer.success)
                {
                    // check conditions and save data
                    for (int j = 0; j < transfer.transactions.Count; j++)
                    {
                        USBTransaction  elem = (USBTransaction)transfer.transactions[j];
                        UHCITransaction uT   = (UHCITransaction)(elem.underlyingTz);
                        transfer.success = transfer.success && isTransactionSuccessful(uT); // executed w/o error

                        if (uT.inBuffer != null && uT.inLength != 0)
                        {
                            MemoryUtils.MemCpy_32((byte *)uT.inBuffer, (byte *)uT.qTDBuffer, uT.inLength);
                        }
                    }
                }

#if UHCI_TRACE
                if (!transfer.success)
                {
                    BasicConsole.SetTextColour(BasicConsole.error_colour);
                    BasicConsole.WriteLine("UHCI: Transfer failed.");
                    BasicConsole.SetTextColour(BasicConsole.default_colour);
                }
                else
                {
                    BasicConsole.SetTextColour((char)0x0200);
                    BasicConsole.WriteLine("Transfer succeeded.");
                    BasicConsole.SetTextColour(BasicConsole.default_colour);
                }
#endif
            }
        }
Exemplo n.º 26
0
 /// <summary>
 /// When overridden in a derived class, handles HC implementation specific transfer initialisation.
 /// </summary>
 /// <param name="transfer">The transfer to set up.</param>
 protected abstract void _SetupTransfer(USBTransfer transfer);
Exemplo n.º 27
0
        protected override void _OUTTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, void* buffer, ushort length)
        {
#if UHCI_TRACE
            BasicConsole.WriteLine("UHCI: OUT Transaction");
            BasicConsole.DelayOutput(5);
#endif

            UHCITransaction uT = new UHCITransaction();
            uTransaction.underlyingTz = uT;
            uT.inBuffer = null;
            uT.inLength = 0;

            uT.qTD = CreateQTD_IO((UHCI_QueueHead_Struct*)transfer.underlyingTransferData, (uint*)1, UHCI_Consts.TD_OUT, toggle, length, transfer.device.address, transfer.endpoint, transfer.packetSize);
            uT.qTDBuffer = uT.qTD->virtBuffer;

            if (buffer != null && length != 0)
            {
                MemoryUtils.MemCpy_32((byte*)uT.qTDBuffer, (byte*)buffer, length);
            }

            if (transfer.transactions.Count > 0)
            {
                UHCITransaction uLastTransaction = (UHCITransaction)((USBTransaction)(transfer.transactions[transfer.transactions.Count - 1])).underlyingTz;
                uLastTransaction.qTD->next = (((uint)VirtMemManager.GetPhysicalAddress(uT.qTD) & 0xFFFFFFF0) | UHCI_Consts.BIT_Vf); // build TD queue
                uLastTransaction.qTD->q_next = uT.qTD;
            }
        }
Exemplo n.º 28
0
 /// <summary>
 /// When overridden in a derived class, handles HC implementation specific SETUP transaction initialisation.
 /// </summary>
 /// <param name="transfer">The transfer to which the transaction should be added.</param>
 /// <param name="uTransaction">The USB Transaction to convert to an EHCI Transaction.</param>
 /// <param name="toggle">The transaction toggle state.</param>
 /// <param name="tokenBytes">The number of bytes to send.</param>
 /// <param name="type">The type of the USB Request.</param>
 /// <param name="req">The specific USB Request.</param>
 /// <param name="hiVal">The USB Request Hi-Val.</param>
 /// <param name="loVal">The USB Request Lo-Val.</param>
 /// <param name="index">The USB request index.</param>
 /// <param name="length">The length of the USB request.</param>
 protected abstract void _SETUPTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, ushort tokenBytes,
                                           byte type, byte req, byte hiVal, byte loVal, ushort index, ushort length);
Exemplo n.º 29
0
        protected override void _IssueTransfer(USBTransfer transfer)
        {
#if UHCI_TRACE
            BasicConsole.WriteLine("UHCI: Issue Transfer");
            BasicConsole.DelayOutput(5);
#endif

            UHCITransaction firstTransaction = (UHCITransaction)((USBTransaction)transfer.transactions[0]).underlyingTz;
            UHCITransaction lastTransaction = (UHCITransaction)((USBTransaction)transfer.transactions[transfer.transactions.Count - 1]).underlyingTz;
            UHCI_qTD.SetIntOnComplete(lastTransaction.qTD, true);  // We want an interrupt after complete transfer
            CreateQH((UHCI_QueueHead_Struct*)transfer.underlyingTransferData, (uint)transfer.underlyingTransferData, firstTransaction.qTD);
            
#if UHCI_TRACE
            BasicConsole.WriteLine("    Queue head data:");
            BasicConsole.DumpMemory(transfer.underlyingTransferData, sizeof(UHCI_QueueHead_Struct));
            BasicConsole.WriteLine("    Transactions data:");
            for (int i = 0; i < transfer.transactions.Count; i++)
            {
                BasicConsole.Write(" ");
                BasicConsole.Write(i);
                BasicConsole.WriteLine(" : ");
                BasicConsole.WriteLine("  - qTD:");
                BasicConsole.DumpMemory(
                    ((UHCITransaction)((USBTransaction)transfer.transactions[i]).underlyingTz).qTD, sizeof(UHCI_qTD_Struct));
                BasicConsole.WriteLine("  - qTDBuffer:");
                BasicConsole.DumpMemory(
                    ((UHCITransaction)((USBTransaction)transfer.transactions[i]).underlyingTz).qTDBuffer, 16);
            }
            BasicConsole.DelayOutput(60);

            BasicConsole.WriteLine("UHCI: Issuing transfer...");
#endif

            for (byte i = 0; i < UHCI_Consts.NUMBER_OF_UHCI_RETRIES && !transfer.success; i++)
            {
                TransactionsCompleted = 0;
                for (int j = 0; j < transfer.transactions.Count; j++)
                {
                    USBTransaction elem = (USBTransaction)transfer.transactions[j];
                    UHCITransaction uT = (UHCITransaction)(elem.underlyingTz);
                    uT.qTD->u1 = uT.qTD->u1 & 0xFF00FFFF;
                    UHCI_qTD.SetActive(uT.qTD, true);
                }

                // stop scheduler
                USBSTS.Write_UInt16(UHCI_Consts.STS_MASK);
                USBCMD.Write_UInt16((ushort)(USBCMD.Read_UInt16() & ~UHCI_Consts.CMD_RS));
                while ((USBSTS.Read_UInt16() & UHCI_Consts.STS_HCHALTED) == 0)
                {
                    Hardware.Devices.Timer.Default.Wait(10);
                }

                // update scheduler
                uint qhPhysAddr = ((uint)VirtMemManager.GetPhysicalAddress(transfer.underlyingTransferData) | UHCI_Consts.BIT_QH);
                FrameList[0] = qhPhysAddr;
                FRBASEADD.Write_UInt32((uint)VirtMemManager.GetPhysicalAddress(FrameList));
                FRNUM.Write_UInt16(0);
                // start scheduler
                USBSTS.Write_UInt16(UHCI_Consts.STS_MASK);
                USBCMD.Write_UInt16((ushort)(USBCMD.Read_UInt16() | UHCI_Consts.CMD_RS));
                while ((USBSTS.Read_UInt16() & UHCI_Consts.STS_HCHALTED) != 0)
                {
                    Hardware.Devices.Timer.Default.Wait(10);
                }

#if UHCI_TRACE
                BasicConsole.WriteLine(((FOS_System.String)"USBINT val: ") + USBINTR.Read_UInt16());
#endif

                // run transactions
                bool active = true;
                int timeout = 100; //5 seconds
                while (active && timeout > 0)
                {
                    active = false;
                    for (int j = 0; j < transfer.transactions.Count; j++)
                    {
                        USBTransaction elem = (USBTransaction)transfer.transactions[j];
                        UHCITransaction uT = (UHCITransaction)(elem.underlyingTz);
                        active = active || ((uT.qTD->u1 & 0x00FF0000) == 0x00800000);
                    }

                    Hardware.Devices.Timer.Default.Wait(50);
                    timeout--;
                }

#if UHCI_TRACE
                BasicConsole.WriteLine("Finished waiting.");
#endif

                FrameList[0] = UHCI_Consts.BIT_T;
                
                if (timeout == 0 ||
                    TransactionsCompleted != transfer.transactions.Count)
                {
#if UHCI_TRACE
                    BasicConsole.SetTextColour(BasicConsole.error_colour);
                    BasicConsole.WriteLine("UHCI: Error! Transactions wait timed out or wrong number of transactions completed.");
                    BasicConsole.SetTextColour(BasicConsole.default_colour);

                    BasicConsole.WriteLine(((FOS_System.String)"Transactions completed: ") + TransactionsCompleted);

                    if (timeout == 0)
                    {
                        BasicConsole.SetTextColour(BasicConsole.error_colour);
                        BasicConsole.WriteLine("UHCI: Error! Transfer timed out.");
                        BasicConsole.SetTextColour(BasicConsole.default_colour);
                    }
#endif

                    transfer.success = false;

                    bool completeDespiteNoInterrupt = true;
                    for (int j = 0; j < transfer.transactions.Count; j++)
                    {
                        USBTransaction elem = (USBTransaction)transfer.transactions[j];
                        UHCITransaction uT = (UHCITransaction)(elem.underlyingTz);
                        
#if UHCI_TRACE
                        BasicConsole.WriteLine(((FOS_System.String)"u1=") + uT.qTD->u1 + ", u2=" + uT.qTD->u2);
                        BasicConsole.WriteLine(((FOS_System.String)"Status=") + (byte)(uT.qTD->u1 >> 16));
#endif
                        completeDespiteNoInterrupt = completeDespiteNoInterrupt && isTransactionSuccessful(uT);
                    }

                    transfer.success = completeDespiteNoInterrupt;

#if UHCI_TRACE
                    BasicConsole.SetTextColour(BasicConsole.warning_colour);
                    BasicConsole.WriteLine(((FOS_System.String)"Complete despite no interrupts: ") + completeDespiteNoInterrupt);
                    BasicConsole.SetTextColour(BasicConsole.default_colour);
                    
                    BasicConsole.DelayOutput(5);
#endif
                }
                else
                {
                    transfer.success = true;
                }

                if (transfer.success)
                {
                    // check conditions and save data
                    for (int j = 0; j < transfer.transactions.Count; j++)
                    {
                        USBTransaction elem = (USBTransaction)transfer.transactions[j];
                        UHCITransaction uT = (UHCITransaction)(elem.underlyingTz);
                        transfer.success = transfer.success && isTransactionSuccessful(uT); // executed w/o error

                        if (uT.inBuffer != null && uT.inLength != 0)
                        {
                            MemoryUtils.MemCpy_32((byte*)uT.inBuffer, (byte*)uT.qTDBuffer, uT.inLength);
                        }
                    }
                }

#if UHCI_TRACE
                if (!transfer.success)
                {
                    BasicConsole.SetTextColour(BasicConsole.error_colour);
                    BasicConsole.WriteLine("UHCI: Transfer failed.");
                    BasicConsole.SetTextColour(BasicConsole.default_colour);
                }
                else
                {
                    BasicConsole.SetTextColour((char)0x0200);
                    BasicConsole.WriteLine("Transfer succeeded.");
                    BasicConsole.SetTextColour(BasicConsole.default_colour);
                }
#endif
            }
        }
Exemplo n.º 30
0
 /// <summary>
 /// When overridden in a derived class, handles HC implementation specific OUT transaction initialisation.
 /// </summary>
 /// <param name="transfer">The transfer to which the transaction should be added.</param>
 /// <param name="uTransaction">The USB Transaction to convert to an EHCI transaction.</param>
 /// <param name="toggle">The transaction toggle state.</param>
 /// <param name="buffer">The buffer of outgoing data.</param>
 /// <param name="length">The length of the buffer.</param>
 protected abstract void _OUTTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, void *buffer, ushort length);
Exemplo n.º 31
0
 /// <summary>
 /// Sets up a SETUP transaction and adds it to the specified transfer.
 /// </summary>
 /// <param name="transfer">The transfer to which the transaction should be added.</param>
 /// <param name="uTransaction">The USB Transaction to convert to an EHCI Transaction.</param>
 /// <param name="toggle">The transaction toggle state.</param>
 /// <param name="tokenBytes">The number of bytes to send.</param>
 /// <param name="type">The type of the USB Request.</param>
 /// <param name="req">The specific USB Request.</param>
 /// <param name="hiVal">The USB Request Hi-Val.</param>
 /// <param name="loVal">The USB Request Lo-Val.</param>
 /// <param name="index">The USB request index.</param>
 /// <param name="length">The length of the USB request.</param>
 protected override void _SETUPTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, ushort tokenBytes,
                                           byte type, byte req, byte hiVal, byte loVal, ushort index, ushort length)
 {
     // Create an EHCI-specific object to describe the transaction
     EHCITransaction eTransaction = new EHCITransaction();
     // Store the underlying HC-specific transaction info
     uTransaction.underlyingTz = eTransaction;
     // SETUP transaction so there is no input buffer
     eTransaction.inBuffer = null;
     eTransaction.inLength = 0u;
     // Create and initialise the SETUP queue transfer descriptor
     eTransaction.qTD = CreateQTD_SETUP(null, toggle, tokenBytes, type, req, hiVal, loVal, index, length);
     
     // If the number of existing transactions is greater than 0
     //  i.e. some transactions have already been added.
     if (transfer.transactions.Count > 0)
     {
         // Get the previous (i.e. last) transaction then the underlying transaction from it
         EHCITransaction eLastTransaction = (EHCITransaction)((USBTransaction)(transfer.transactions[transfer.transactions.Count - 1])).underlyingTz;
         // Create a wrapper for the last transaction (qTD)
         EHCI_qTD lastQTD = eLastTransaction.qTD;
         // Set the Next Transaction (qTD) Pointer on the previous qTD to point to the qTD
         //  we just created. 
         // Note: The NextqTDPointer must be the physical address of qTD data.
         lastQTD.NextqTDPointer = (EHCI_qTD_Struct*)VirtMemManager.GetPhysicalAddress(eTransaction.qTD.qtd);
         // Mark the previous qTD's Next Transaction Pointer as valid.
         lastQTD.NextqTDPointerTerminate = false;
     }
 }
Exemplo n.º 32
0
 /// <summary>
 /// When overridden in a derived class, handles HC implementation specific method of issuing a transfer.
 /// </summary>
 /// <param name="transfer">The transfer to issue.</param>
 protected abstract void _IssueTransfer(USBTransfer transfer);
Exemplo n.º 33
0
        /// <summary>
        /// Sets up an IN transaction and adds it to the specified transfer.
        /// </summary>
        /// <param name="transfer">The transfer to which the transaction should be added.</param>
        /// <param name="uTransaction">The USB Transaction to convert to an EHCI transaction.</param>
        /// <param name="toggle">The transaction toggle state.</param>
        /// <param name="buffer">The buffer of outgoing data.</param>
        /// <param name="length">The length of the buffer.</param>
        protected override void _OUTTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, void* buffer, ushort length)
        {
            // Create an EHCI-specific object to describe the transaction
            EHCITransaction eTransaction = new EHCITransaction();
            // Store the underlying HC-specific transaction info
            uTransaction.underlyingTz = eTransaction;
            // OUT transaction so there is no input buffer
            eTransaction.inBuffer = null;
            eTransaction.inLength = 0u;

            // Create and initialise the OUT queue transfer descriptor
            EHCI_qTD theQTD = CreateQTD_IO(null, 0, toggle, length, length);
            // Set the qTD structure in the transaction description object
            eTransaction.qTD = theQTD;
            // If there is an output buffer and it has > 0 length:
            if (buffer != null && length != 0)
            {
                // Copy the data from the output buffer to the transaction's output buffer
                // The transaction's output buffer has been allocated so it as aligned correctly
                //  where as there is no guarantee the output buffer passed to us has been so we
                //  must copy the data across.
                Utilities.MemoryUtils.MemCpy_32(theQTD.Buffer0VirtAddr, (byte*)buffer, length);

#if EHCI_TRACE
                BasicConsole.WriteLine("EHCI: OUTTransaction - Buffer0:");
                BasicConsole.DumpMemory(theQTD.Buffer0VirtAddr, length);
#endif
            }

            // If the number of existing transactions is greater than 0
            //  i.e. some transactions have already been added. 
            if (transfer.transactions.Count > 0)
            {
                // Get the previous (i.e. last) transaction then the underlying transaction from it
                EHCITransaction eLastTransaction = (EHCITransaction)((USBTransaction)(transfer.transactions[transfer.transactions.Count - 1])).underlyingTz;
                // Create a wrapper for the last transaction (qTD)
                EHCI_qTD lastQTD = eLastTransaction.qTD;
                // Set the Next Transaction (qTD) Pointer on the previous qTD to point to the qTD
                //  we just created. 
                // Note: The NextqTDPointer must be the physical address of qTD data.
                lastQTD.NextqTDPointer = (EHCI_qTD_Struct*)VirtMemManager.GetPhysicalAddress(eTransaction.qTD.qtd);
                // Mark the previous qTD's Next Transaction Pointer as valid.
                lastQTD.NextqTDPointerTerminate = false;
            }
        }
Exemplo n.º 34
0
        /// <summary>
        /// Resets the bulk tarnsfer interface.
        /// </summary>
        /// <param name="numInterface">The bulk transfer interface number to reset.</param> 
        public void BulkReset(byte numInterface)
        {
#if MSD_TRACE
            DBGMSG(((FOS_System.String)"USB MSD: TransferBulkOnly - MassStorageReset, interface: ") + numInterface);
#endif

            USBTransfer transfer = new USBTransfer();
            DeviceInfo.hc.SetupTransfer(DeviceInfo, transfer, USBTransferType.Control, 0, 64);

            // RequestType   Request   Value  Index     Length   Data
            // 00100001b     11111111b 0000h  Interface 0000h    None
            DeviceInfo.hc.SETUPTransaction(transfer, 8, 0x21, 0xFF, 0, 0, numInterface, 0);
            DeviceInfo.hc.INTransaction(transfer, true, null, 0); // Handshake
            DeviceInfo.hc.IssueTransfer(transfer);
        }
Exemplo n.º 35
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;
        }
Exemplo n.º 36
0
        /// <summary>
        /// Sets up a USB transfer for sending via the EHCI.
        /// </summary>
        /// <param name="usbDevice">The USb device to send the transfer to.</param>
        /// <param name="transfer">The transfer to send.</param>
        /// <param name="type">The type of USB transfer.</param>
        /// <param name="endpoint">The endpoint of the device to send the transfer to.</param>
        /// <param name="maxLength">The maximum packet size to use when transferring.</param>
        public void SetupTransfer(Devices.USBDeviceInfo usbDevice, USBTransfer transfer, USBTransferType type, byte endpoint, 
                                  ushort maxLength)
        {
            transfer.device = usbDevice;
            transfer.endpoint = endpoint;
            transfer.type = type;
#if HCI_TRACE
            BasicConsole.WriteLine(((FOS_System.String)"SetupTransfer: maxLength=") + maxLength + ", endpoint=" + endpoint + ", mps=" + ((Endpoint)usbDevice.Endpoints[endpoint]).mps);
#endif
            transfer.packetSize = FOS_System.Math.Min(maxLength, ((Endpoint)usbDevice.Endpoints[endpoint]).MPS);
#if HCI_TRACE
            BasicConsole.WriteLine(((FOS_System.String)"SetupTransfer: packetSize=") + transfer.packetSize);
#endif
            transfer.success = false;
            transfer.transactions = new List(3);

            _SetupTransfer(transfer);
        }