Package org.jnode.driver.net.prism2

Source Code of org.jnode.driver.net.prism2.Prism2IO

/*
* $Id$
*
* Copyright (C) 2003-2014 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.net.prism2;

import static org.jnode.driver.net.prism2.Prism2Constants.Register.CMD;
import static org.jnode.driver.net.prism2.Prism2Constants.Register.DATA0;
import static org.jnode.driver.net.prism2.Prism2Constants.Register.EVACK;
import static org.jnode.driver.net.prism2.Prism2Constants.Register.EVSTAT;
import static org.jnode.driver.net.prism2.Prism2Constants.Register.OFFSET0;
import static org.jnode.driver.net.prism2.Prism2Constants.Register.PARAM0;
import static org.jnode.driver.net.prism2.Prism2Constants.Register.PARAM1;
import static org.jnode.driver.net.prism2.Prism2Constants.Register.PARAM2;
import static org.jnode.driver.net.prism2.Prism2Constants.Register.SELECT0;
import static org.jnode.driver.net.prism2.Prism2Constants.Register.STATUS;

import org.apache.log4j.Logger;
import org.jnode.driver.DriverException;
import org.jnode.system.resource.MemoryResource;
import org.jnode.util.LittleEndian;
import org.jnode.util.NumberUtils;
import org.jnode.util.TimeUtils;
import org.jnode.util.TimeoutException;

/**
* Class responsible for handling the low level I/O to the prism2 device.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
final class Prism2IO implements Prism2Constants {

    /**
     * My logger
     */
    private static final Logger log = Logger.getLogger(Prism2IO.class);

    /**
     * The memory mapped registers
     */
    private final MemoryResource regs;

    /**
     * Initialize this instance.
     *
     * @param regs
     */
    public Prism2IO(MemoryResource regs) {
        this.regs = regs;
    }

    /**
     * Release all resources.
     */
    final void release() {
        regs.release();
    }

    /**
     * Gets a register value.
     *
     * @param reg
     */
    final int getReg(Register reg) {
        return regs.getShort(reg.getOffset()) & 0xFFFF;
    }

    /**
     * Gets a register value.
     *
     * @param reg
     */
    final void setReg(Register reg, int value) {
        regs.setShort(reg.getOffset(), (short) value);
    }

    /**
     * Execute a command and wait until it has completed.
     *
     * @param cmd
     * @param parm0
     * @param parm1
     * @param parm2
     * @return the RESULT code.
     */
    final Result executeCommand(Command cmd, int cmdFlags, int parm0, int parm1, int parm2,
            Prism2CommandResponse response) throws TimeoutException {
        // Wait for the busy bit to clear
        waitUntilNotBusy();

        // Write command
        setReg(PARAM0, parm0);
        setReg(PARAM1, parm1);
        setReg(PARAM2, parm2);
        setReg(CMD, cmd.getCode() | cmdFlags);

        // Wait until command completion
        waitUntilCommandCompleted();

        // Read status and response
        final int status;
        if (response != null) {
            response.initialize(this);
            status = response.getStatus();
        } else {
            status = getReg(STATUS);
        }

        // Acknowledge
        setReg(EVACK, EVACK_CMD);

        // Return the result code.
        return Result.getByCode((status & STATUS_RESULT) >> 8);
    }

    /**
     * Wait until a given event mask is reached, or a timeout occurs.
     *
     * @param eventMask
     * @param eventAck
     * @param wait
     * @param timeout
     */
    final int waitForEvent(int eventMask, int eventAck, int wait, int timeout) {
        for (int counter = 0; counter < timeout; counter++) {
            final int reg = getReg(EVSTAT);
            if ((reg & eventMask) != 0) {
                // Acknowledge
                setReg(EVACK, reg & (eventMask | eventAck));
                return reg;
            }
            TimeUtils.sleep(wait);
        }
        log.debug("Timeout in waitForEvent");
        return 0;
    }

    /**
     * Wait until the device is no longer busy.
     *
     * @throws TimeoutException
     */
    private final void waitUntilNotBusy() throws TimeoutException {
        for (int counter = 0; counter < 10; counter++) {
            final int cmd = getReg(CMD);
            if ((cmd & CMD_BUSY) == 0) {
                return;
            } else {
                TimeUtils.sleep(5);
            }
        }
        ;
        throw new TimeoutException("Prism2 still busy cmd=0x" + NumberUtils.hex(getReg(CMD), 4));
    }

    /**
     * Wait until the command is completed.
     *
     * @throws TimeoutException
     */
    private final void waitUntilCommandCompleted() throws TimeoutException {
        for (int counter = 0; counter < 200; counter++) {
            final int reg = getReg(EVSTAT);
            if ((reg & EVSTAT_CMD) != 0) {
                return;
            } else {
                TimeUtils.sleep(2);
            }
        }
        ;
        throw new TimeoutException("Prism2 still busy evstat=0x" +
                NumberUtils.hex(getReg(EVSTAT), 4));
    }

    /**
     * Wait until the BAP is no longer busy.
     *
     * @throws TimeoutException
     */
    private final void waitUntilBapNotBusy() throws TimeoutException {
        for (int counter = 0; counter < 100; counter++) {
            final int cmd = getReg(OFFSET0);
            if ((cmd & OFFSET_BUSY) == 0) {
                return;
            } else {
                TimeUtils.sleep(5);
            }
        }
        ;
        throw new TimeoutException("Prism2 still busy offset=0x" +
                NumberUtils.hex(getReg(OFFSET0), 4));
    }

    /**
     * Throw an exception depending on the given result code. No exception is
     * thrown if the result is success.
     *
     * @param result
     * @throws DriverException
     */
    final void resultToException(Result result) throws DriverException {
        switch (result) {
            case SUCCESS:
                return;
            case CARD_FAIL:
                throw new DriverException("Card failure");
            case NO_BUFF:
                throw new DriverException("No buffer");
            case CMD_ERR:
                throw new DriverException("Command error");
            default:
                throw new DriverException("Unknown result code 0x" +
                        NumberUtils.hex(result.getCode(), 2));
        }
    }

    /**
     * Copy from the BAP into the given byte buffer.
     *
     * @param id        FID or RID, destined for the select register (host order)
     * @param offset    An _even_ offset into the buffer for the given FID/RID
     * @param dst       Destination buffer
     * @param dstOffset Offset in destination buffer
     * @param len       length of data to transfer in bytes
     * @throws DriverException
     */
    final void copyFromBAP(int id, int offset, byte[] dst, int dstOffset, int len)
        throws DriverException {
        // Prepare the BAP
        prepareBAP(id, offset);

        // Read even(len) buf contents from data reg
        final int maxlen = len & 0xFFFE;
        for (int i = 0; i < maxlen; i += 2) {
            final int v = getReg(DATA0);
            LittleEndian.setInt16(dst, dstOffset + i, v);
        }
        // If len odd, handle last byte
        if ((len % 2) != 0) {
            final int v = getReg(DATA0);
            dst[dstOffset + len - 1] = (byte) (v & 0xFF);
        }
    }

    /**
     * Copy to the BAP from the given byte buffer.
     *
     * @param id        FID or RID, destined for the select register (host order)
     * @param offset    An _even_ offset into the buffer for the given FID/RID
     * @param src       Source buffer
     * @param srcOffset Offset in source buffer
     * @param len       length of data to transfer in bytes
     * @throws DriverException
     */
    final void copyToBAP(int id, int offset, byte[] src, int srcOffset, int len)
        throws DriverException {
        // Prepare the BAP
        prepareBAP(id, offset);

        // Write even(len) buf contents to data reg
        final int maxlen = len & 0xFFFE;
        for (int i = 0; i < maxlen; i += 2) {
            final int v = LittleEndian.getInt16(src, srcOffset + i);
            setReg(DATA0, v);
        }
        // If len odd, handle last byte
        if ((len % 2) != 0) {
            int v = getReg(DATA0);
            prepareBAP(id, offset + maxlen);
            v = (v & 0xFF00) | (src[srcOffset + len - 1] & 0xFF);
            setReg(DATA0, v);
        }
    }

    /**
     * Prepare the BAP registers for a transfer.
     *
     * @param id     FID or RID, destined for the select register (host order)
     * @param offset An _even_ offset into the buffer for the given FID/RID
     * @throws DriverException
     * @throws IllegalArgumentException For an invalid offset.
     */
    private final void prepareBAP(int id, int offset) throws DriverException {
        if ((offset > BAP_OFFSET_MAX) || ((offset % 2) != 0)) {
            throw new IllegalArgumentException("Invalid offset " + offset);
        }
        // Write fid/rid and offset
        setReg(SELECT0, id);
        TimeUtils.sleep(1);
        setReg(OFFSET0, offset);

        // Wait for the bap to settle.
        try {
            waitUntilBapNotBusy();
        } catch (TimeoutException ex) {
            throw new DriverException("Cannot setup BAP in time", ex);
        }

        // Test for errors
        if ((getReg(OFFSET0) & OFFSET_ERR) != 0) {
            throw new DriverException("Error in offset");
        }
    }
}
TOP

Related Classes of org.jnode.driver.net.prism2.Prism2IO

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.