/// <summary> /// Initializes a qTD with specified underlying data structure. /// </summary> /// <param name="aqTD">The existing underlying data structure.</param> public EHCI_qTD(EHCI_qTD_Struct* aqTD) { qtd = aqTD; }
/// <summary> /// Allocates memory for a new qTD and does initialisation common to all qTD types. /// </summary> /// <param name="next">A pointer to the next qTD in the linked list or 1 to specify no pointer.</param> /// <returns>The new qTD.</returns> protected static EHCI_qTD AllocAndInitQTD(EHCI_qTD_Struct* next) { EHCI_qTD newQTD = new EHCI_qTD(); if (next != null) { newQTD.NextqTDPointerTerminate = false; newQTD.NextqTDPointer = (EHCI_qTD_Struct*)VirtMemManager.GetPhysicalAddress(next); } else { newQTD.NextqTDPointerTerminate = true; } newQTD.AlternateNextqTDPointerTerminate = true; // No alternate next, so T-Bit is set to 1 newQTD.Status = 0x80; // This will be filled by the Host Controller. Active bit set newQTD.ErrorCounter = 0x0; // Written by the Host Controller. newQTD.CurrentPage = 0x0; // Written by the Host Controller. newQTD.InterruptOnComplete = false; //Set only for the last transaction of a transfer return newQTD; }
/// <summary> /// Creates and initialises a new qTD as a SETUP qTD. /// </summary> /// <param name="next">A pointer to the next qTD in the linked list or 1 to specify no pointer.</param> /// <param name="toggle">The toggle state for the new qTD.</param> /// <param name="tokenBytes">The number of bytes to transfer.</param> /// <param name="type">The USB Request type.</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 index of the USB Request.</param> /// <param name="length">The length of the USB Request.</param> /// <returns>The new qTD.</returns> protected EHCI_qTD CreateQTD_SETUP(EHCI_qTD_Struct* next, bool toggle, ushort tokenBytes, byte type, byte req, byte hiVal, byte loVal, ushort index, ushort length) { EHCI_qTD td = AllocAndInitQTD(next); td.PIDCode = (byte)EHCI_qTDTypes.SETUP; // SETUP = 2 td.TotalBytesToTransfer = tokenBytes; // dependent on transfer td.DataToggle = toggle; // Should be toggled every list entry USBRequest* request = (USBRequest*)(AllocQTDbuffer(td)); request->type = type; request->request = req; request->valueHi = hiVal; request->valueLo = loVal; request->index = index; request->length = length; return td; }
/// <summary> /// Creates a new qTD and initialises it as an IN or OUT qTD. /// </summary> /// <param name="next">A pointer to the next qTD in the linked list or 1 to specify no pointer.</param> /// <param name="direction">The direction of the qTD (in or out)</param> /// <param name="toggle">The toggle state for the new qTD.</param> /// <param name="tokenBytes">The number of bytes to transfer.</param> /// <param name="bufferSize">The size of the qTD data buffer.</param> /// <returns>The new qTD.</returns> protected EHCI_qTD CreateQTD_IO(EHCI_qTD_Struct* next, byte direction, bool toggle, ushort tokenBytes, uint bufferSize) { EHCI_qTD td = AllocAndInitQTD(next); td.PIDCode = direction; td.TotalBytesToTransfer = tokenBytes; // dependent on transfer td.DataToggle = toggle; // Should be toggled every list entry AllocQTDbuffer(td); return td; }
/// <summary> /// Initialises a queue head - memory must already be allocated. /// </summary> /// <param name="headPtr">A pointer to the queue head structure to initialise.</param> /// <param name="horizPtr"> /// The virtual address of the next queue head in the list (or the first queue head since the /// async queue is a circular buffer). This is translated into the physical address internally. /// </param> /// <param name="firstQTD">A pointer to the first qTD of the queue head.</param> /// <param name="H">The Head of Reclamation list flag.</param> /// <param name="deviceAddr">The address of the USB device to which this queue head belongs.</param> /// <param name="endpoint">The endpoint number of the USB device to which this queue head belongs.</param> /// <param name="maxPacketSize">The maximum packet size to use when transferring.</param> protected void InitQH(EHCI_QueueHead_Struct* headPtr, EHCI_QueueHead_Struct* horizPtr, EHCI_qTD_Struct* firstQTD, bool H, byte deviceAddr, byte endpoint, ushort maxPacketSize) { EHCI_QueueHead head = new EHCI_QueueHead(headPtr); head.HorizontalLinkPointer = (EHCI_QueueHead_Struct*)VirtMemManager.GetPhysicalAddress(horizPtr); head.Type = 0x1; // Types: 00b iTD, 01b QH, 10b siTD, 11b FSTN head.Terminate = false; head.DeviceAddress = deviceAddr; // The device address head.InactiveOnNextTransaction = false; head.EndpointNumber = endpoint; // endpoint 0 contains Device infos such as name head.EndpointSpeed = 2; // 00b = full speed; 01b = low speed; 10b = high speed head.DataToggleControl = true; // get the Data Toggle bit out of the included qTD head.HeadOfReclamationList = H; // mark a queue head as being the head of the reclaim list head.MaximumPacketLength = maxPacketSize; // 64 byte for a control transfer to a high speed device head.ControlEndpointFlag = false; // only used if endpoint is a control endpoint and not high speed head.NakCountReload = 0; // this value is used by EHCI to reload the Nak Counter field. 0=ignores NAK counter. head.InterruptScheduleMask = 0; // not used for async schedule head.SplitCompletionMask = 0; // unused if (not low/full speed and in periodic schedule) head.HubAddr = 0; // unused if high speed (Split transfer) head.PortNumber = 0; // unused if high speed (Split transfer) head.HighBandwidthPipeMultiplier = 1; // 1-3 transaction per micro-frame, 0 means undefined results if (firstQTD == null) { head.NextqTDPointer = null; head.NextqTDPointerTerminate = true; } else { head.NextqTDPointer = (EHCI_qTD_Struct*)VirtMemManager.GetPhysicalAddress(firstQTD); head.NextqTDPointerTerminate = false; } }