Package org.jnode.driver.block.floppy

Source Code of org.jnode.driver.block.floppy.DefaultFDC

/*
* $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.block.floppy;

import java.security.PrivilegedExceptionAction;

import javax.naming.NameNotFoundException;

import org.apache.log4j.Logger;
import org.jnode.driver.DriverException;
import org.jnode.driver.system.cmos.CMOSConstants;
import org.jnode.driver.system.cmos.CMOSService;
import org.jnode.naming.InitialNaming;
import org.jnode.system.resource.DMAException;
import org.jnode.system.resource.DMAManager;
import org.jnode.system.resource.DMAResource;
import org.jnode.system.resource.IOResource;
import org.jnode.system.resource.IRQResource;
import org.jnode.system.resource.MemoryResource;
import org.jnode.system.resource.ResourceManager;
import org.jnode.system.resource.ResourceNotFreeException;
import org.jnode.system.resource.ResourceOwner;
import org.jnode.util.AccessControllerUtils;
import org.jnode.util.NumberUtils;
import org.jnode.util.TimeoutException;

/**
* @author epr
*/
public class DefaultFDC implements FDC {

    /**
     * My logger
     */
    private static final Logger log = Logger.getLogger(DefaultFDC.class);
    /**
     * Floppy IRQ
     */
    private final IRQResource irq;
    /**
     * Floppy DMA channel
     */
    private final DMAResource dma;
    /**
     * IO-port range1
     */
    private final IOResource io1;
    /**
     * IO-port range2
     */
    private final IOResource io2;
    /**
     * DMA transfer buffer
     */
    private final MemoryResource dmaMem;
    /**
     * Use primary controller?
     */
    private final boolean primary;
    /**
     * The first I/O port
     */
    private final int startPort;
    /**
     * Currently executing command
     */
    private FloppyCommand currentCommand;
    /**
     * The drive parameters
     */
    private final FloppyDriveParameters[] driveParams;
    private final boolean[] diskChanged;

    /**
     * Create a new instance
     *
     * @param owner
     * @param primary
     * @throws ResourceNotFreeException
     * @throws DriverException
     */
    public DefaultFDC(ResourceOwner owner, boolean primary)
        throws ResourceNotFreeException, DriverException {
        IRQResource irq = null;
        DMAResource dma = null;
        IOResource io1 = null;
        IOResource io2 = null;
        MemoryResource dmaMem = null;

        if (primary) {
            startPort = PRIMARY_START_PORT;
        } else {
            startPort = SECONDARY_START_PORT;
        }

        // Try to read the floppy parameters in CMOS
        try {
            final CMOSService cmos = InitialNaming.lookup(CMOSService.NAME);
            final int fd = cmos.getRegister(CMOSConstants.CMOS_FLOPPY_DRIVES);
            driveParams = new FloppyDriveParameters[NR_DRIVES];
            diskChanged = new boolean[NR_DRIVES];
            for (int i = 0; i < NR_DRIVES; i++) {
                final int cmosType;
                if (i == 0) {
                    cmosType = (fd >> 4) & 0xf;
                } else if (i == 1) {
                    cmosType = (fd & 0xf);
                } else {
                    cmosType = 0;
                }
                driveParams[i] = getDriveParam(cmosType);
                diskChanged[i] = true;
            }
        } catch (NameNotFoundException ex) {
            throw new ResourceNotFreeException("Cannot find CMOSService", ex);
        }

        try {
            final ResourceManager rm = InitialNaming.lookup(ResourceManager.NAME);
            final DMAManager dmaService = InitialNaming.lookup(DMAManager.NAME);
            // PRESERVE THIS CLAIMING ORDER!
            irq = rm.claimIRQ(owner, FLOPPY_IRQ, this, false);
            dma = dmaService.claimDMAChannel(owner, FLOPPY_DMA);
            io1 = claimPorts(rm, owner, startPort + OFFSET_RANGE1, NR_PORTS_RANGE1);
            io2 = claimPorts(rm, owner, startPort + OFFSET_RANGE2, NR_PORTS_RANGE2);
            dmaMem = rm.claimMemoryResource(owner, null, 64 * 1024, ResourceManager.MEMMODE_ALLOC_DMA);
        } catch (NameNotFoundException ex) {
            throw new ResourceNotFreeException("Cannot find ResourceManager or DMAService", ex);
        } catch (ResourceNotFreeException ex) {
            if (dmaMem != null) {
                dmaMem.release();
            }
            if (io2 != null) {
                io2.release();
            }
            if (io1 != null) {
                io1.release();
            }
            if (dma != null) {
                dma.release();
            }
            if (irq != null) {
                irq.release();
            }
            throw ex;
        }
        this.primary = primary;
        this.irq = irq;
        this.dma = dma;
        this.io1 = io1;
        this.io2 = io2;
        this.dmaMem = dmaMem;
    }


    /**
     * (non-Javadoc)
     *
     * @see org.jnode.driver.block.floppy.FDC#sendCommand(byte[], boolean)
     */
    public void sendCommand(byte[] command, boolean enableDMA)
        throws FloppyException {
        if (enableDMA) {
            try {
                dma.enable();
            } catch (DMAException ex) {
                throw new FloppyException("Cannot enable DMA", ex);
            }
        }
        final int len = command.length;
        for (int i = 0; i < len; i++) {
            // Wait until MRQ is on
            /*while ((getStateReg() & STATE_MRQ) == 0) {
                   Thread.yield();
               }*/
            io1.outPortByte(startPort + RW8_DATA_OFFSET, command[i] & 0xFF);
        }
    }


    /**
     * (non-Javadoc)
     *
     * @see org.jnode.driver.block.floppy.FDC#setupDMA(int, int)
     */
    public void setupDMA(int length, int mode)
        throws FloppyException {
        try {
            dma.setup(dmaMem, length, mode);
        } catch (DMAException ex) {
            throw new FloppyException("Cannot setup DMA", ex);
        }
    }

    /**
     * (non-Javadoc)
     *
     * @see org.jnode.driver.block.floppy.FDC#copyToDMA(byte[], int, int)
     */
    public void copyToDMA(byte[] src, int srcOffset, int length) {
        dmaMem.setBytes(src, srcOffset, 0, length);
    }

    /**
     * (non-Javadoc)
     *
     * @see org.jnode.driver.block.floppy.FDC#copyFromDMA(byte[], int, int)
     */
    public void copyFromDMA(byte[] dest, int destOffset, int length) {
        dmaMem.getBytes(0, dest, destOffset, length);
    }

    /**
     * Copy from the given byte array into the DMA buffer
     *
     * @param src
     * @param length
     */
    protected void copyToDMA(byte[] src, int length) {
        dmaMem.setBytes(src, 0, 0, length);
    }


    /**
     * (non-Javadoc)
     *
     * @see org.jnode.driver.block.floppy.FDC#getCommandState(int)
     */
    public byte[] getCommandState(int length)
        throws TimeoutException, FloppyException {
        final byte[] res = new byte[MAX_REPLIES];
        for (int i = 0; i < MAX_REPLIES; i++) {
            int status;
            status = waitUntilReady();
            status &= STATE_DIO | STATE_READY | STATE_BUSY | STATE_NDMA;
            if ((status & ~STATE_BUSY) == STATE_READY) {
                return res;
            }
            if (status == (STATE_DIO | STATE_READY | STATE_BUSY)) {
                res[i] = (byte) io1.inPortByte(startPort + RW8_DATA_OFFSET);
            } else {
                throw new FloppyException("Error in reading state: state=" + NumberUtils.hex(status, 2));
            }
        }
        throw new FloppyException("Too many result bytes");
    }

    /**
     * Wait until the FDC is in the ready state
     *
     * @return The contents of the state register
     * @throws TimeoutException
     */
    private final int waitUntilReady()
        throws TimeoutException {
        for (int i = 0; i < 1000; i++) {
            final int state = getStateReg();
            if ((state & STATE_READY) != 0) {
                return state;
            }
        }
        throw new TimeoutException("Timeout in waiting for ready");
    }

    /**
     * Gets the STATE register
     *
     * @return int
     */
    public final int getStateReg() {
        return io1.inPortByte(startPort + R8_STATE_OFFSET);
    }

    /**
     * Gets the DOR register
     *
     * @return int
     */
    public final int getDorReg() {
        return io1.inPortByte(startPort + RW8_DOR_OFFSET);
    }

    /**
     * Gets the DIR register
     *
     * @return int
     */
    public final int getDirReg() {
        return io2.inPortByte(startPort + R8_DIR_OFFSET);
    }

    /**
     * Has the disk changed since the last command?
     *
     * @param drive
     * @param resetFlag
     * @return boolean
     */
    public final boolean diskChanged(int drive, boolean resetFlag) {
        final boolean rc = diskChanged[drive];
        if (rc && resetFlag) {
            diskChanged[drive] = false;
        }
        return rc;
    }


    /**
     * (non-Javadoc)
     *
     * @see org.jnode.driver.block.floppy.FDC#setDorReg(int, boolean, boolean)
     */
    public final void setDorReg(int drive, boolean motorOn, boolean dma) {
        setDorReg(drive, motorOn, dma, false);
    }

    /**
     * Sets the DOR register
     *
     * @param drive
     * @param motorOn
     * @param dma
     * @param reset
     */
    private final void setDorReg(int drive, boolean motorOn, boolean dma, boolean reset) {
        final int driveV;
        final int motorV;
        final int oldDor = io1.inPortByte(startPort + RW8_DOR_OFFSET);
        final int oldDrive = oldDor & DOR_DRIVE_MASK;
        if ((oldDrive != drive) || reset) {
            // Test disk change for old drive
            diskChanged[oldDrive] |= ((getDirReg() & DIR_DISKCHANGE) != 0);
        }

        switch (drive) {
            case 0:
                driveV = DOR_DRIVE0;
                motorV = DOR_MOTOR0;
                break;
            case 1:
                driveV = DOR_DRIVE1;
                motorV = DOR_MOTOR1;
                break;
            case 2:
                driveV = DOR_DRIVE2;
                motorV = DOR_MOTOR2;
                break;
            case 3:
                driveV = DOR_DRIVE3;
                motorV = DOR_MOTOR3;
                break;
            default:
                throw new IllegalArgumentException("Invalid drive value " + drive);
        }
        int v = driveV;
        if (motorOn) {
            v |= motorV;
        }
        if (dma) {
            v |= DOR_DMA;
        }
        if (!reset) {
            v |= DOR_NRESET;
        }
        io1.outPortByte(startPort + RW8_DOR_OFFSET, v);
        if ((oldDrive != drive) || reset) {
            // Test disk change for new drive
            diskChanged[drive] |= ((getDirReg() & DIR_DISKCHANGE) != 0);
        }
    }

    /**
     * (non-Javadoc)
     *
     * @see org.jnode.driver.block.floppy.FDC#getST0()
     */
    public final int getST0() throws TimeoutException, FloppyException {
        final byte[] res = senseInterruptStatus();
        return res[0] & 0xFF;
    }

    /**
     * Gets the current cylinder
     *
     * @return int
     * @throws TimeoutException
     * @throws FloppyException
     */
    protected final int getCylinder()
        throws TimeoutException, FloppyException {
        final byte[] res = senseInterruptStatus();
        return res[0] & 0xFF;
    }

    /**
     * Perform a "Sense interrupt" command
     *
     * @return byte[]
     * @throws TimeoutException
     * @throws FloppyException
     */
    protected final byte[] senseInterruptStatus() throws TimeoutException, FloppyException {
        final byte[] cmd = new byte[1];
        cmd[0] = 0x08;
        sendCommand(cmd, false);
        final byte[] res = getCommandState(2);
        return res;
    }

    /**
     * Perform a "Sense drive status" command
     *
     * @param drive
     * @param head
     * @return ST3
     * @throws TimeoutException
     * @throws FloppyException
     */
    protected final int senseDriveStatus(int drive, int head) throws TimeoutException, FloppyException {
        final byte[] cmd = new byte[2];
        cmd[0] = 0x04;
        cmd[1] = (byte) ((drive & 3) | ((head & 1) << 2));
        sendCommand(cmd, false);
        final byte[] res = getCommandState(1);
        return res[0] & 0xFF;
    }

    /**
     * Add the given command to the command queue and wait till the command
     * has finished.
     *
     * @param cmd
     * @param timeout
     * @throws InterruptedException
     * @throws TimeoutException
     */
    public synchronized void executeAndWait(FloppyCommand cmd, long timeout)
        throws InterruptedException, TimeoutException {
        currentCommand = cmd;
        try {
            cmd.setup(this);
            cmd.waitUntilFinished(timeout);
        } catch (FloppyException ex) {
            cmd.notifyError(ex);
        } finally {
            currentCommand = null;
        }
    }

    /**
     * Release all resources.
     */
    public void release() {
        dmaMem.release();
        io2.release();
        io1.release();
        dma.release();
        irq.release();
    }

    /**
     * Reset the FDC
     */
    public final void reset() {
        final int dor = io1.inPortByte(startPort + RW8_DOR_OFFSET);
        setDorReg(dor & DOR_DRIVE_MASK, false, true, true);
        // Wait a while
        try {
            Thread.sleep(10);
        } catch (InterruptedException ex) {
            // Ignore
        }
        setDorReg(dor & DOR_DRIVE_MASK, false, true, false);
    }

    /**
     * @param irq
     * @see org.jnode.system.resource.IRQHandler#handleInterrupt(int)
     */
    public void handleInterrupt(int irq) {
        final FloppyCommand cmd = currentCommand;
        if (cmd != null) {
            try {
                cmd.handleIRQ(this);
            } catch (FloppyException ex) {
                log.error("Error in Floppy IRQ", ex);
                cmd.notifyError(ex);
            }
            if (cmd.isFinished()) {
                currentCommand = null;
            }
        } else {
            try {
                log.debug("Unhandled Floppy IRQ, " +
                    "DIR=" + NumberUtils.hex(getDirReg(), 2) + ", " +
                    "ST0=" + NumberUtils.hex(getST0(), 2) + ", " +
                    "State=" + NumberUtils.hex(getStateReg(), 2)
                );
            } catch (Exception ex) {
                log.error("Exception in unhandled Floppy IRQ", ex);
            }
        }
    }

    /**
     * Is the primary FDC used.
     *
     * @return True if the primary controller is used, false if the secondary controller is used.
     */
    public boolean isPrimary() {
        return primary;
    }

    /**
     * Gets the drive parameters for a given drive
     *
     * @param drive
     * @return Parameters
     */
    public FloppyDriveParameters getDriveParams(int drive) {
        return driveParams[drive];
    }

    /**
     * Gets the number of drives under control of this controller
     *
     * @return Number of drivers
     */
    public int getDriveCount() {
        return driveParams.length;
    }

    /**
     * Gets the data transfer rate for a given drive in Kb/sec
     *
     * @param drive
     * @return DTR
     */
    public int getDTR(int drive) {
        return 500;
    }

    /**
     * (non-Javadoc)
     *
     * @see org.jnode.driver.block.floppy.FDC#logDMAState()
     */
    public void logDMAState() throws DMAException {
        log.debug("dma.length = " + dma.getLength());
    }

    private final FloppyDriveParameters getDriveParam(int cmosType) {
        final FloppyDriveParameters[] list = DRIVE_PARAMS;
        for (int i = 0; i < list.length; i++) {
            final FloppyDriveParameters dp = list[i];
            if (dp.getCmosType() == cmosType) {
                return dp;
            }
        }
        return FDP_UNKNOWN;
    }

    private IOResource claimPorts(final ResourceManager rm, final ResourceOwner owner, final int low, final int length)
        throws ResourceNotFreeException, DriverException {
        try {
            return AccessControllerUtils.doPrivileged(new PrivilegedExceptionAction<IOResource>() {
                public IOResource run() throws ResourceNotFreeException {
                    return rm.claimIOResource(owner, low, length);
                }
            });
        } catch (ResourceNotFreeException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new DriverException("Unknown exception", ex);
        }

    }
}
TOP

Related Classes of org.jnode.driver.block.floppy.DefaultFDC

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.