欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

dma.java

纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统
JAVA
字号:
/*
 * $Id: DMA.java,v 1.1 2003/11/25 11:42:34 epr Exp $
 */
package org.jnode.system.x86;

import javax.naming.NameNotFoundException;

import org.jnode.naming.InitialNaming;
import org.jnode.system.DMAException;
import org.jnode.system.IOResource;
import org.jnode.system.ResourceManager;
import org.jnode.system.ResourceNotFreeException;
import org.jnode.system.ResourceOwner;
import org.jnode.system.SimpleResourceOwner;
import org.jnode.vm.Address;

/*
 * NOTES about DMA transfers:
 *
 *  controller 1: channels 0-3, byte operations, ports 00-1F
 *  controller 2: channels 4-7, word operations, ports C0-DF
 *
 *  - ALL registers are 8 bits only, regardless of transfer size
 *  - channel 4 is not used - cascades 1 into 2.
 *  - channels 0-3 are byte - addresses/counts are for physical bytes
 *  - channels 5-7 are word - addresses/counts are for physical words
 *  - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
 *  - transfer count loaded to registers is 1 less than actual count
 *  - controller 2 offsets are all even (2x offsets for controller 1)
 *  - page registers for 5-7 don't use data bit 0, represent 128K pages
 *  - page registers for 0-3 use bit 0, represent 64K pages
 *
 * DMA transfers are limited to the lower 16MB of _physical_ memory.  
 * Note that addresses loaded into registers must be _physical_ addresses,
 * not logical addresses (which may differ if paging is active).
 *
 *  Address mapping for channels 0-3:
 *
 *   A23 ... A16 A15 ... A8  A7 ... A0    (Physical addresses)
 *    |  ...  |   |  ... |   |  ... |
 *    |  ...  |   |  ... |   |  ... |
 *    |  ...  |   |  ... |   |  ... |
 *   P7  ...  P0  A7 ... A0  A7 ... A0   
 * |    Page    | Addr MSB | Addr LSB |   (DMA registers)
 *
 *  Address mapping for channels 5-7:
 *
 *   A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0    (Physical addresses)
 *    |  ...  |   \   \   ... \  \  \  ... \  \
 *    |  ...  |    \   \   ... \  \  \  ... \  (not used)
 *    |  ...  |     \   \   ... \  \  \  ... \
 *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0   
 * |      Page      |  Addr MSB   |  Addr LSB  |   (DMA registers)
 *
 * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
 * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
 * the hardware level, so odd-byte transfers aren't possible).
 *
 * Transfer count (_not # bytes_) is limited to 64K, represented as actual
 * count - 1 : 64K => 0xFFFF, 1 => 0x0000.  Thus, count is always 1 or more,
 * and up to 128K bytes may be transferred on channels 5-7 in one operation. 
 *
 * TAKEN FROM Linux kernel.
 */
/**
 * @author epr
 */
public class DMA implements DMAConstants {

	/** Number of channels */
	public static final int MAX = 8;

	/** Page I/O ports */
	private final IOResource pageIO;
	private final IOResource dma1IO;
	private final IOResource dma2IO;

	/**
	 * Create a new instance
	 * @throws DMAException
	 */
	public DMA() throws DMAException {
		final ResourceManager rm;
		try {
			rm = (ResourceManager)InitialNaming.lookup(ResourceManager.NAME);
		} catch (NameNotFoundException ex) {
			throw new DMAException("Cannot find ResourceManager", ex);
		}
		IOResource pageIO = null;
		IOResource dma1IO = null;
		IOResource dma2IO = null;

		try {
			final ResourceOwner owner = new SimpleResourceOwner("DMA-X86");
			pageIO = rm.claimIOResource(owner, 0x81, 0x8f - 0x81 + 1);
			dma1IO = rm.claimIOResource(owner, 0x00, 16);
			dma2IO = rm.claimIOResource(owner, 0xc0, 32);

			this.pageIO = pageIO;
			this.dma1IO = dma1IO;
			this.dma2IO = dma2IO;
			
			for (int dmanr = 0; dmanr < MAX; dmanr++) {
				clearFF(dmanr);
			}

		} catch (ResourceNotFreeException ex) {
			if (pageIO != null) {
				pageIO.release();
			}
			if (dma1IO != null) {
				dma1IO.release();
			}
			if (dma2IO != null) {
				dma2IO.release();
			}
			throw new DMAException("Cannot claim DMA I/O ports", ex);
		}
	}
	
	/**
	 * Release all resources
	 */
	protected final void release() {
		pageIO.release();
		dma1IO.release();
		dma2IO.release();
	}

	/**
	 * Program the page register for a given channel
	 * @param dmanr
	 * @param page
	 */
	private final void setPage(int dmanr, int page) {
		switch (dmanr) {
			case 0 :
				pageIO.outPortByte(DMA_PAGE_0, page);
				break;
			case 1 :
				pageIO.outPortByte(DMA_PAGE_1, page);
				break;
			case 2 :
				pageIO.outPortByte(DMA_PAGE_2, page);
				break;
			case 3 :
				pageIO.outPortByte(DMA_PAGE_3, page);
				break;
			case 5 :
				pageIO.outPortByte(DMA_PAGE_5, page & 0xfe);
				break;
			case 6 :
				pageIO.outPortByte(DMA_PAGE_6, page & 0xfe);
				break;
			case 7 :
				pageIO.outPortByte(DMA_PAGE_7, page & 0xfe);
				break;
			default :
				throw new IllegalArgumentException("Invalid dmanr " + dmanr);
		}
	}

	/**
	 * Program the address register for a given channel
	 * @param dmanr
	 * @param address
	 * @throws DMAException
	 */
	public void setAddress(int dmanr, Address address) throws DMAException {
		final int a32 = Address.as32bit(address);
		final int page = (a32 >> 16);
		
		setPage(dmanr, page);
		if (dmanr <= 3) {
			final int port = DMA_ADDR_0 + ((dmanr & 3) << 1);
			dma1IO.outPortByte(port, a32 & 0xFF);
			dma1IO.outPortByte(port, (a32 >> 8) & 0xFF);
		} else {
			final int port = DMA_ADDR_4 + ((dmanr & 3) << 2);
			dma1IO.outPortByte(port, (a32 >> 1) & 0xFF);
			dma1IO.outPortByte(port, (a32 >> 9) & 0xFF);
		}
	}

	/**
	 * Program the address register for a given channel
	 * @param dmanr
	 * @param length
	 * @throws DMAException
	 */
	public void setLength(int dmanr, int length) throws DMAException {
		length--;
		if (dmanr <= 3) {
			final int port = DMA_CNT_0 + ((dmanr & 3) << 1);
			dma1IO.outPortByte(port, length & 0xFF);
			dma1IO.outPortByte(port, (length >> 8) & 0xFF);
		} else {
			final int port = DMA_CNT_4 + ((dmanr & 3) << 2);
			dma1IO.outPortByte(port, (length >> 1) & 0xFF);
			dma1IO.outPortByte(port, (length >> 9) & 0xFF);
		}
	}
	
	public int getLength(int dmanr) {
		final int port;
		int count;
		if (dmanr <= 3) {
			port = DMA_CNT_0 + ((dmanr & 3) << 1);
		} else {
			port = DMA_CNT_4 + ((dmanr & 3) << 2);
		}
		count = (dma1IO.inPortByte(port) & 0xFF) + 1;
		count += ((dma1IO.inPortByte(port) & 0xFF) << 8);
		if (dmanr <= 3) {
			return count;
		} else {
			return count << 1;
		}		
	}

	/**
	 * Program the mode register for a given channel
	 * @param dmanr
	 * @param mode
	 * @throws DMAException
	 */
	public void setMode(int dmanr, int mode) throws DMAException {
		mode |= (dmanr & 3);
		if (dmanr <= 3) {
			dma1IO.outPortByte(DMA1_MODE_REG, mode);
		} else {
			dma2IO.outPortByte(DMA2_MODE_REG, mode);
		}
	}

	/**
	 * Enable the given channel
	 * @param dmanr
	 */
	public void enable(int dmanr) {
		if (dmanr <= 3) {
			dma1IO.outPortByte(DMA1_MASK_REG, dmanr);
		} else {
			dma2IO.outPortByte(DMA2_MASK_REG, dmanr & 3);
		}
	}

	/**
	 * Disable the given channel
	 * @param dmanr
	 */
	public void disable(int dmanr) {
		if (dmanr <= 3) {
			dma1IO.outPortByte(DMA1_MASK_REG, dmanr | 4);
		} else {
			dma2IO.outPortByte(DMA2_MASK_REG, (dmanr & 3) | 4);
		}
	}

	/**
	 * Clear the 'DMA Pointer Flip Flop'.
	 * Write 0 for LSB/MSB, 1 for MSB/LSB access.
	 * Use this once to initialize the FF to a known state.
	 * After that, keep track of it. :-)
	 * @param dmanr
	 */
	protected final void clearFF(int dmanr) {
		if (dmanr <= 3) {
			dma1IO.outPortByte(DMA1_CLEAR_FF_REG, 0);
		} else {
			dma2IO.outPortByte(DMA2_CLEAR_FF_REG, 0);
		}
	}
	
	/**
	 * Test the combination of address and length
	 * @param dmanr
	 * @param address
	 * @param length
	 * @throws IllegalArgumentException
	 */
	protected final void test(int dmanr, Address address, int length) 
	throws IllegalArgumentException {
		final int maxLength;
		final int pageMask;
		if (dmanr <= 3) {
			maxLength = 64*1024;
			pageMask = 0xff;
		} else {
			maxLength = 128*1024;
			if ((length & 2) != 0) {
				throw new IllegalArgumentException("Invalid length-alignment: " + length);
			}
			pageMask = 0xfe;
		}
		if ((length <= 0) || (length > maxLength)) {
			throw new IllegalArgumentException("Invalid length: " + length);
		}
		
		final int a32 = Address.as32bit(address);
		final int pageStart = (a32 >> 16) & pageMask;
		final int pageEnd = ((a32 + length-1) >> 16) & pageMask;
		if (pageStart != pageEnd) {
			throw new IllegalArgumentException("Invalid address alignment. DMA block cannot cross pages");
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -