Package org.jnode.driver.block.floppy

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

/*
* $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.io.IOException;
import java.nio.ByteBuffer;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
import org.jnode.driver.Driver;
import org.jnode.driver.RemovableDeviceAPI;
import org.jnode.driver.block.BlockDeviceAPIHelper;
import org.jnode.driver.block.CHS;
import org.jnode.driver.block.FSBlockAlignmentSupport;
import org.jnode.driver.block.FSBlockDeviceAPI;
import org.jnode.driver.block.Geometry;
import org.jnode.driver.block.floppy.support.FloppyDeviceFactory;
import org.jnode.driver.block.floppy.support.FloppyDriverUtils;
import org.jnode.partitions.PartitionTableEntry;
import org.jnode.util.ByteBufferUtils;
import org.jnode.util.TimeoutException;

/**
* Driver for a FloppyDevice (a single floppy drive)
*
* @author epr
*/
public class FloppyDriver extends Driver implements FSBlockDeviceAPI, RemovableDeviceAPI, FloppyConstants {

    /**
     * My logger
     */
    private static final Logger log = Logger.getLogger(FloppyDriver.class);
    /**
     * Drive number
     */
    private int drive;
    /**
     * The controller of the floppy drive i'm a driver for
     */
    private FloppyControllerDriver controller;
    private FloppyDriveParameters dp;
    private FloppyParameters fp;
    private int currentSectorSize = -1;
    private FSBlockAlignmentSupport api;

    /**
     * Start the device
     */
    protected void startDevice() {
        final FloppyDevice dev = (FloppyDevice) getDevice();
        controller = dev.getFloppyControllerBus().getController();
        drive = dev.getDrive();
        dp = dev.getDriveParams();
        fp = null;
        api = new FSBlockAlignmentSupport(this, 512);
        dev.registerAPI(RemovableDeviceAPI.class, this);
        dev.registerAPI(FSBlockDeviceAPI.class, api);
    }

    /**
     * Stop the device
     */
    protected void stopDevice() {
        final FloppyDevice dev = (FloppyDevice) getDevice();
        dev.unregisterAPI(RemovableDeviceAPI.class);
        dev.unregisterAPI(FSBlockDeviceAPI.class);
        controller = null;
        drive = -1;
        fp = null;
        dp = null;
    }

    /**
     * @see org.jnode.driver.block.BlockDeviceAPI#flush()
     */
    public void flush() {
        // Nothing to do here
    }

    /**
     * @return The length
     * @throws IOException
     * @see org.jnode.driver.block.BlockDeviceAPI#getLength()
     */
    public long getLength() throws IOException {
        testDiskChange();
        return fp.getGeometry().getTotalSectors() * SECTOR_LENGTH[currentSectorSize];
    }

    /**
     * (non-Javadoc)
     *
     * @see org.jnode.driver.block.BlockDeviceAPI#read(long, java.nio.ByteBuffer)
     */
    public void read(long devOffset, ByteBuffer destBuf) throws IOException {
        //TODO optimize it also to use ByteBuffer at lower level                
        ByteBufferUtils.ByteArray destBA = ByteBufferUtils.toByteArray(destBuf);
        byte[] dest = destBA.toArray();
        int destOffset = 0;
        int length = dest.length;

        synchronized (controller) {
            testDiskChange();
            BlockDeviceAPIHelper.checkBounds(this, devOffset, length);
            final int sectorLength = SECTOR_LENGTH[currentSectorSize];
            testAlignment(sectorLength, devOffset, length);
            CHS chs = fp.getGeometry().getCHS(devOffset / sectorLength);
            FloppyDeviceFactory factory;
            try {
                factory = FloppyDriverUtils.getFloppyDeviceFactory();
            } catch (NamingException ex) {
                throw (IOException) new IOException().initCause(ex);
            }

            try {
                while (length > 0) {
                    final FloppyReadSectorCommand cmd;
                    cmd =
                        factory.createFloppyReadSectorCommand(
                            drive,
                            fp.getGeometry(),
                            chs,
                            currentSectorSize,
                            false,
                            fp.getGap1Size(),
                            dest,
                            destOffset);
                    controller.executeAndWait(cmd, RW_TIMEOUT);
                    destOffset += sectorLength;
                    length -= sectorLength;

                    if (length > 0) {
                        // go to next sector only more data to read (length>0)                   
                        chs = fp.getGeometry().nextSector(chs);
                    }
                }
            } catch (TimeoutException ex) {
                timeout(ex, "read");
            }
        }

        destBA.refreshByteBuffer();
    }

    /**
     * (non-Javadoc)
     *
     * @see org.jnode.driver.block.BlockDeviceAPI#write(long, java.nio.ByteBuffer)
     */
    public void write(long devOffset, ByteBuffer srcBuf) throws IOException {
        //TODO optimize it also to use ByteBuffer at lower level                
        ByteBufferUtils.ByteArray srcBA = ByteBufferUtils.toByteArray(srcBuf);
        byte[] src = srcBA.toArray();
        int srcOffset = 0;
        int length = src.length;

        synchronized (controller) {
            testDiskChange();
            BlockDeviceAPIHelper.checkBounds(this, devOffset, length);
            final int sectorLength = SECTOR_LENGTH[currentSectorSize];
            testAlignment(sectorLength, devOffset, length);
            CHS chs = fp.getGeometry().getCHS(devOffset / sectorLength);
            FloppyDeviceFactory factory;
            try {
                factory = FloppyDriverUtils.getFloppyDeviceFactory();
            } catch (NamingException ex) {
                throw (IOException) new IOException().initCause(ex);
            }

            try {
                while (length > 0) {
                    final FloppyWriteSectorCommand cmd;
                    cmd =
                        factory.createFloppyWriteSectorCommand(
                            drive,
                            fp.getGeometry(),
                            chs,
                            currentSectorSize,
                            false,
                            fp.getGap1Size(),
                            src,
                            srcOffset);
                    controller.executeAndWait(cmd, RW_TIMEOUT);
                    srcOffset += sectorLength;
                    length -= sectorLength;

                    if (length > 0) {
                        // go to next sector only more data to write (length>0)                   
                        chs = fp.getGeometry().nextSector(chs);
                    }
                }
            } catch (TimeoutException ex) {
                timeout(ex, "write");
            }
        }
    }

    /**
     * @return The partition table entry, always null here.
     * @see org.jnode.driver.block.FSBlockDeviceAPI#getPartitionTableEntry()
     */
    public PartitionTableEntry getPartitionTableEntry() {
        return null; // A floppy has not partition table
    }

    /**
     * @return int
     * @see org.jnode.driver.block.FSBlockDeviceAPI#getSectorSize()
     */
    public int getSectorSize() {
        if (currentSectorSize < 0) {
            return 512;
        } else {
            return SECTOR_LENGTH[currentSectorSize];
        }
    }

    /**
     * Can this device be locked.
     *
     * @return if this device can be locked
     */
    public boolean canLock() {
        return false;
    }

    /**
     * Can this device be ejected.
     *
     * @return if this device can be ejected
     */
    public boolean canEject() {
        return false;
    }

    /**
     * Lock the device.
     *
     * @throws IOException
     */
    public void lock()
        throws IOException {
        throw new IOException("Unsupported operation");
    }

    /**
     * Unlock the device.
     *
     * @throws IOException
     */
    public void unlock()
        throws IOException {
        throw new IOException("Unsupported operation");
    }

    /**
     * Is this device locked.
     *
     * @see org.jnode.driver.RemovableDeviceAPI#isLocked()
     */
    public boolean isLocked() {
        return false;
    }

    /**
     * Eject this device.
     *
     * @throws IOException
     */
    public void eject()
        throws IOException {
        throw new IOException("Unsupported operation");
    }

    @Override
    public void load() throws IOException {
        throw new IOException("Unsupported operation");
    }

    /**
     * Test if the disk has been changed and/or the format of the loaded floppy
     * is known. If the floppy has been changed or the format of the floppy is
     * not known, try to probe its format.
     *
     * @throws IOException
     */
    private final void testDiskChange() throws IOException {
        if (controller.diskChanged(drive, true)) {
            log.debug("FloppyDisk change detected");
            // Disk has changed, probe for format of new disk
            fp = null;
        }
        if (fp == null) {
            log.debug("Try to probe floppy format...");
            controller.resetFDC();
            log.debug("seek(0)");
            seek(0);
            fp = probeFormat();
            api.setAlignment(SECTOR_LENGTH[currentSectorSize]);
        }
    }

    /**
     * Try to determine the format of the disk in the drive
     *
     * @return The parameters
     * @throws IOException
     */
    private final FloppyParameters probeFormat() throws IOException {
        final FloppyParameters[] fpList = dp.getAutodetectFormats();
        final byte[] buf = new byte[512];
        for (int i = 0; i < fpList.length; i++) {
            final FloppyParameters fp = fpList[i];
            log.debug("Trying format " + fp);

            final Geometry geom = fp.getGeometry();
            final int cyl = geom.getCylinders() - 1;
            final int sect = geom.getSectors();
            final int head = geom.getHeads() - 1;
            final CHS chs0 = new CHS(cyl, head, sect);
            specify(fp);
            seek(cyl);
            readID();

            try {
                final FloppyReadSectorCommand cmd =
                    new FloppyReadSectorCommand(
                        drive,
                        fp.getGeometry(),
                        chs0,
                        currentSectorSize,
                        false,
                        fp.getGap1Size(),
                        buf,
                        0);
                controller.executeAndWait(cmd, RW_TIMEOUT);
                // The read has succeeded, we found the format!
                log.debug("Found floppy format: " + fp);
                return fp;
            } catch (TimeoutException ex) {
                // Read failed, reset the controller and try the next format
                controller.resetFDC();
            }

        }
        throw new IOException("Unknown format");
    }

    /**
     * Seek to a given cylinder
     *
     * @param cylinder
     * @throws IOException
     */
    private final void seek(int cylinder) throws IOException {
        FloppyDeviceFactory factory;
        try {
            factory = FloppyDriverUtils.getFloppyDeviceFactory();
        } catch (NamingException ex) {
            throw (IOException) new IOException().initCause(ex);
        }
        final FloppySeekCommand cmd = factory.createFloppySeekCommand(drive, cylinder);
        try {
            controller.executeAndWait(cmd, SEEK_TIMEOUT);
            if (controller.diskChanged(drive, false)) {
                throw new IOException("Floppy not present");
            }
        } catch (TimeoutException ex) {
            timeout(ex, "seek");
        }
    }

    /**
     * Read the ID of the disk
     *
     * @throws IOException
     */
    private final void readID() throws IOException {
        FloppyDeviceFactory factory;
        try {
            factory = FloppyDriverUtils.getFloppyDeviceFactory();
        } catch (NamingException ex) {
            throw (IOException) new IOException().initCause(ex);
        }
        final FloppyIdCommand cmd = factory.createFloppyIdCommand(drive);
        try {
            controller.executeAndWait(cmd, RW_TIMEOUT);
            if (cmd.hasError()) {
                final IOException ioe = new IOException("Error in Read ID");
                ioe.initCause(cmd.getError());
                throw ioe;
            }
            currentSectorSize = cmd.getSectorSize();
        } catch (TimeoutException ex) {
            timeout(ex, "readID");
        }
    }

    /**
     * Read the ID of the disk
     *
     * @param fp
     * @throws IOException
     */
    private final void specify(FloppyParameters fp) throws IOException {
        FloppyDeviceFactory factory;
        try {
            factory = FloppyDriverUtils.getFloppyDeviceFactory();
        } catch (NamingException ex) {
            throw (IOException) new IOException().initCause(ex);
        }
        final FloppyDriveParametersCommand cmd = factory.createFloppyDriveParametersCommand(drive, dp, fp);

        try {
            controller.executeAndWait(cmd, RW_TIMEOUT);
            if (cmd.hasError()) {
                final IOException ioe = new IOException("Error in specify");
                ioe.initCause(cmd.getError());
                throw ioe;
            }
        } catch (TimeoutException ex) {
            timeout(ex, "specify");
        }
    }

    /**
     * Test the alignment of the given parameters
     *
     * @param sectorLength
     * @param devOffset
     * @param length
     * @throws IOException
     */
    private final void testAlignment(int sectorLength, long devOffset, int length) throws IOException {
        if ((devOffset % sectorLength) != 0) {
            throw new IOException("devOffset is not sector aligned");
        }
        if ((length % sectorLength) != 0) {
            throw new IOException("length is not sector aligned");
        }
    }

    /**
     * Process a timeout during read/write
     *
     * @param ex
     * @param operation
     * @throws IOException
     */
    private final void timeout(TimeoutException ex, String operation) throws IOException {
        controller.resetFDC();
        fp = null;
        final IOException ioe = new IOException("Timeout in " + operation);
        ioe.initCause(ex);
        throw ioe;
    }
}
TOP

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

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.