fdc.java
来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 514 行
JAVA
514 行
/*
* $Id: FDC.java,v 1.1 2003/11/25 11:50:45 epr Exp $
*/
package org.jnode.driver.floppy;
import javax.naming.NameNotFoundException;
import org.apache.log4j.Logger;
import org.jnode.driver.cmos.CMOSConstants;
import org.jnode.driver.cmos.CMOSService;
import org.jnode.naming.InitialNaming;
import org.jnode.system.DMAException;
import org.jnode.system.DMAManager;
import org.jnode.system.DMAResource;
import org.jnode.system.IOResource;
import org.jnode.system.IRQHandler;
import org.jnode.system.IRQResource;
import org.jnode.system.MemoryResource;
import org.jnode.system.ResourceManager;
import org.jnode.system.ResourceNotFreeException;
import org.jnode.system.ResourceOwner;
import org.jnode.util.NumberUtils;
import org.jnode.util.TimeoutException;
/**
* @author epr
*/
public class FDC implements IRQHandler, FloppyConstants {
/** My logger */
private final Logger log = Logger.getLogger(getClass());
/** 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
*/
public FDC(ResourceOwner owner, boolean primary)
throws ResourceNotFreeException {
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 = (CMOSService)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 = (ResourceManager)InitialNaming.lookup(ResourceManager.NAME);
final DMAManager dmaService = (DMAManager)InitialNaming.lookup(DMAManager.NAME);
// PRESERVE THIS CLAIMING ORDER!
irq = rm.claimIRQ(owner, FLOPPY_IRQ, this, false);
dma = dmaService.claimDMAChannel(owner, FLOPPY_DMA);
io1 = rm.claimIOResource(owner, startPort + OFFSET_RANGE1, NR_PORTS_RANGE1);
io2 = rm.claimIOResource(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;
}
/**
* Send a command to the FDC
* @param command
* @param enableDMA
* @throws FloppyException
*/
protected 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);
}
}
/**
* Setup the floppy DMA channel to transfer from/to the DMA memory buffer
* @param length Number of bytes to transfer
* @param mode DMAResource.MODE_READ or DMAResource.MODE_WRITE
* @throws FloppyException
*/
protected void setupDMA(int length, int mode)
throws FloppyException {
try {
dma.setup(dmaMem, length, mode);
} catch (DMAException ex) {
throw new FloppyException("Cannot setup DMA", ex);
}
}
/**
* Copy from the given byte array into the DMA buffer
* @param src
* @param srcOffset
* @param length
*/
protected void copyToDMA(byte[] src, int srcOffset, int length) {
dmaMem.setBytes(src, srcOffset, 0, length);
}
/**
* Copy from the DMA buffer into the given byte array
* @param dest
* @param destOffset
* @param length
*/
protected 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);
}
/**
* Gets a command status from the FDC
* @param length
* @return
* @throws TimeoutException
* @throws FloppyException
*/
protected 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
* @throws TimeoutException
* @return The contents of the state register
*/
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;
}
/**
* Sets the DOR register
* @param drive
* @param motorOn
* @param dma
*/
protected 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);
}
}
/**
* Gets status register 0
* @return int
* @throws TimeoutException
* @throws FloppyException
*/
protected 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
*/
protected 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.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;
}
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;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?