/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.driver.bus.usb.uhci;
import org.jnode.system.resource.ResourceManager;
import org.jnode.util.NumberUtils;
/**
* A wrapper of the UHCI Transfer Descriptor layout.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public final class TransferDescriptor extends AbstractTreeStructure implements UHCIConstants {
/**
* The transfer data buffer
*/
private final byte[] dataBuffer;
/**
* Offset in the data buffer
*/
private final int dataBufferOffset;
/**
* The link pointer
*/
private AbstractTreeStructure linkPointer;
/**
* Is the link a TD
*/
private boolean linkIsTD;
/**
* The original ctrl value
*/
private final int origCtrl;
/**
* Create a new instance
*
* @param rm The resource manager
* @param deviceAddress The destination device address
* @param endPt The destination endpoint address
* @param packetId The packet id.
* @param data0 Data Toggle, if true data0, otherwise data1
* @param dataBuffer The data buffer
* @param dataBufferOffset The offset within the databuffer
* @param isochronous Isochronous transfer yes/no
* @param lowspeed Lowspeed device yes/no
* @param ioc Interrupt on complete yes/no
*/
public TransferDescriptor(
ResourceManager rm,
int deviceAddress,
int endPt,
int packetId,
boolean data0,
byte[] dataBuffer,
int dataBufferOffset,
int bufLength,
boolean isochronous,
boolean lowspeed,
boolean ioc) {
super(rm, 32, 16);
this.dataBuffer = dataBuffer;
this.dataBufferOffset = dataBufferOffset;
final int maxLen;
if (bufLength > 0) {
maxLen = bufLength - 1;
} else {
maxLen = 0x7FF;
}
// Set Linkpointer to invalid
setInt(0, 1);
// Set Control & Status
int ctrl = TD_CTRL_C_ERR_MASK | TD_CTRL_ACTIVE | TD_CTRL_SPD;
if (ioc) {
ctrl |= TD_CTRL_IOC;
}
if (isochronous) {
ctrl |= TD_CTRL_IOS;
}
if (lowspeed) {
ctrl |= TD_CTRL_LS;
}
this.origCtrl = ctrl;
setInt(4, ctrl); //
// Set Token
int token = packetId & 0xFF;
token |= (deviceAddress & 0x7F) << 8;
token |= (endPt & 0xF) << 15;
token |= (data0 ? 0 : 1) << 19;
token |= (maxLen << 21);
setInt(8, token);
// Set Buffer pointer
if (dataBuffer == null) {
setInt(12, 0);
} else {
setInt(12, dataBufferOffset + rm.asMemoryResource(dataBuffer).getAddress().toInt());
}
}
/**
* Reset thestatus of this TD.
* The Active bit is set, the Error bits are cleared, the Error Counter
* is set.
* The SPD, LS, ISO and IOC bits are preserved.
*/
public final void resetStatus() {
setInt(4, origCtrl);
}
/**
* Set the link pointer to the given transfer descriptor.
*
* @param td
*/
public final void setLink(TransferDescriptor td, boolean depthFirst) {
final int ptr = td.getDescriptorAddress() & 0xFFFFFFF0 | (depthFirst ? 0x4 : 0x0);
this.linkPointer = td;
this.linkIsTD = true;
setInt(0, ptr);
}
/**
* Set the link pointer to the given queue head.
*
* @param qh
* @param depthFirst If true, the next queue is processed depth first, otherwise the next queue is
* processed breadth first
*/
public final void setLink(QueueHead qh, boolean depthFirst) {
final int ptr = (qh.getDescriptorAddress() & 0xFFFFFFF0) | 0x2 | (depthFirst ? 0x4 : 0x0);
this.linkPointer = qh;
this.linkIsTD = false;
setInt(0, ptr);
}
/**
* Set the link pointer as invalid
*/
public final void removeLink() {
setInt(0, 1);
this.linkIsTD = false;
this.linkPointer = null;
}
/**
* Set the active bit of this descriptor
*
* @param active
*/
public final void setActive(boolean active) {
int ctrl = getInt(4);
if (active) {
ctrl |= TD_CTRL_ACTIVE;
} else {
ctrl &= ~TD_CTRL_ACTIVE;
}
setInt(4, ctrl);
}
/**
* Is the active bit of this descriptor set.
*/
public final boolean isActive() {
final int ctrl = getInt(4);
return ((ctrl & TD_CTRL_ACTIVE) != 0);
}
/**
* Is the stalled bit of this descriptor set.
*/
public final boolean isStalled() {
final int ctrl = getInt(4);
return ((ctrl & TD_CTRL_STALLED) != 0);
}
/**
* Is the data buffer error bit of this descriptor set.
*/
public final boolean isDataBufferError() {
final int ctrl = getInt(4);
return ((ctrl & TD_CTRL_DBUFERR) != 0);
}
/**
* Is the babble detected bit of this descriptor set.
*/
public final boolean isBabbleDetected() {
final int ctrl = getInt(4);
return ((ctrl & TD_CTRL_BABBLE) != 0);
}
/**
* Is the NAK received bit of this descriptor set.
*/
public final boolean isNAKReceived() {
final int ctrl = getInt(4);
return ((ctrl & TD_CTRL_NAK) != 0);
}
/**
* Is the CRC/Time Out Error bit of this descriptor set.
*/
public final boolean isCRCTimeOutError() {
final int ctrl = getInt(4);
return ((ctrl & TD_CTRL_CRCTIMEO) != 0);
}
/**
* Is the Bitstuff Error bit of this descriptor set.
*/
public final boolean isBitstuffError() {
final int ctrl = getInt(4);
return ((ctrl & TD_CTRL_BITSTUFF) != 0);
}
/**
* Is any of the error flags set.
*/
public final boolean isAnyError() {
final int ctrl = getInt(4);
return ((ctrl & TD_CTRL_ANY_ERROR) != 0);
}
/**
* Gets the actual length that is set by the HC.
*/
public final int getActualLength() {
final int len = getInt(4) & TD_CTRL_ACTLEN_MASK;
if (len == 0x7FF) {
return 0;
} else {
return len + 1;
}
}
/**
* @return Returns the dataBuffer.
*/
public final byte[] getDataBuffer() {
return this.dataBuffer;
}
/**
* @return Returns the offset in the dataBuffer.
*/
public final int getDataBufferOffset() {
return this.dataBufferOffset;
}
/**
* @return Returns the linkPointer.
*/
public final AbstractTreeStructure getLink() {
return this.linkPointer;
}
/**
* Gets the linked TransferDescriptor, if any.
*
* @return The linked TransferDescriptor, or null if the link is null or not a TD.
*/
public final TransferDescriptor getNextTD() {
if (linkIsTD) {
return (TransferDescriptor) this.linkPointer;
} else {
return null;
}
}
/**
* Append the given TD to the end of the list I'm a part of.
*
* @param td
*/
public final void append(TransferDescriptor td, boolean depthFirst) {
AbstractTreeStructure ptr = this;
while (ptr instanceof TransferDescriptor) {
final TransferDescriptor ptrTD = (TransferDescriptor) ptr;
if (ptrTD.linkPointer == null) {
ptrTD.setLink(td, depthFirst);
return;
} else {
ptr = ptrTD.getLink();
}
}
}
/**
* Convert to a String representation
*
* @see java.lang.Object#toString()
*/
public String toString() {
return "TD[" + NumberUtils.hex(getInt(0)) + ", " + NumberUtils.hex(getInt(4)) + ", " +
NumberUtils.hex(getInt(8)) + ", " + NumberUtils.hex(getInt(12)) + "->" + linkPointer + ']';
}
}