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; } }
/// <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); } }
/// <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; }
/// <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); } }
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; } }
/// <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; } }
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; } }
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; } }
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 } }
/// <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); } }
/// <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);
/// <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);
/// <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); } }
/// <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; } }
/// <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);
/// <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; } }