⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dma.c

📁 微内核软实时操作系统
💻 C
字号:
/*- * Copyright (c) 2005, Kohsuke Ohtani * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors  *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * dma.c - DMA management routines for intel 8237 controller *//*- ================================================================== *  Memo: * *  [Mode Register] * *      Bits     Function *      -------- Mode Selection *      00          Demand Mode *      01          Single Mode *      10          Block Mode *      11          Cascade Mode *      -------- Address Increment/Decrement *        1         Address Decrement *        0         Address Increment *      -------- Auto-Initialization Enable *         1        Auto-Initialization DMA *         0        Single-Cycle DMA *      -------- Transfer Type *          00      Verify *          01      Write *          10      Read *          11      Illegal *      -------- Channel Selection *            00    Channel 0 (4) *            01    Channel 1 (5) *            10    Channel 2 (6) *            11    Channel 3 (7) * *  [Single Mask Register] * *      Bits     Function *      -------- *      00000    Unused, Set to 0 *      -------- Set/Clear Mask *           1      Set (Disable Channel) *           0      Clear (Enable Channel) *      -------- Channel Selection *            00    Channel 0 (4) *            01    Channel 1 (5) *            10    Channel 2 (6) *            11    Channel 3 (7) * * ================================================================== */#include <driver.h>#include <io.h>#define NR_DMAS		8#define DMA_MAX		(1024 * 64)#define DMA_MASK	(DMA_MAX-1)#define DMA_ALIGN(n)	((((u_long)(n)) + DMA_MASK) & ~DMA_MASK)void dma_stop(int handle);/* * DMA descriptor */struct dma {	int chan;		/* dma channel */	int in_use;		/* true if used */};/* * DMA i/o port */struct dma_port {	int mask;	int mode;	int clear;	int addr;	int count;	int page;};static const struct dma_port dma_regs[] = {/*	mask,  mode,  clear, addr,  count, page */	{0x0a, 0x0b, 0x0c, 0x00, 0x01, 0x87},	/* Channel 0 */	{0x0a, 0x0b, 0x0c, 0x02, 0x03, 0x83},	/* Channel 1 */	{0x0a, 0x0b, 0x0c, 0x04, 0x05, 0x81},	/* Channel 2 */	{0x0a, 0x0b, 0x0c, 0x06, 0x07, 0x82},	/* Channel 3 */	{0xd4, 0xd6, 0xd8, 0xc0, 0xc2, 0x8f},	/* Channel 4 (n/a) */	{0xd4, 0xd6, 0xd8, 0xc4, 0xc6, 0x8b},	/* Channel 5 */	{0xd4, 0xd6, 0xd8, 0xc8, 0xca, 0x89},	/* Channel 6 */	{0xd4, 0xd6, 0xd8, 0xcc, 0xce, 0x8a},	/* Channel 7 */};static struct dma dma_table[NR_DMAS];/* * Attach dma. * Return dma handle on success, or -1 on failure. * DMA4 can not be used with pc. */int dma_attach(int chan){	struct dma *dma;	ASSERT(chan >= 0 && chan < NR_DMAS);	ASSERT(chan != 4);	printk("DMA%d attached\n", chan);	irq_lock();	dma = &dma_table[chan];	if (dma->in_use) {		irq_unlock();		return -1;	} else {		dma->chan = chan;		dma->in_use = 1;	}	dma_stop((int)dma);	irq_unlock();	return (int)dma;}/* * Detach dma. */void dma_detach(int handle){	struct dma *dma = (struct dma *)handle;	ASSERT(dma->in_use);	printk("DMA%d detached\n", dma->chan);	irq_lock();	dma->in_use = 0;	irq_unlock();}void dma_setup(int handle, u_long addr, u_long count, int read){	struct dma *dma = (struct dma *)handle;	const struct dma_port *regs;	u_int chan, bits, mode;	ASSERT(handle);	addr = (u_long)virt_to_phys((void *)addr);	/* dma address must be under 16M. */	ASSERT(addr < 0xffffff);	irq_lock();	chan = (u_int)dma->chan;	regs = &dma_regs[chan];	bits = (chan < 4) ? chan : chan >> 2;	mode = read ? 0x44 : 0x48;	count--;	outb_p(bits | 0x04, regs->mask);	/* Disable channel */	outb_p(0x00, regs->clear);		/* Clear byte pointer flip-flop */	outb_p(bits | mode, regs->mode);	/* Set mode */	outb_p(addr >> 0, regs->addr);		/* Address low */	outb_p(addr >> 8, regs->addr);		/* Address high */	outb_p(addr >> 16, regs->page);		/* Page address */	outb_p(0x00, regs->clear);		/* Clear byte pointer flip-flop */	outb_p(count >> 0, regs->count);	/* Count low */	outb_p(count >> 8, regs->count);	/* Count high */	outb_p(bits, regs->mask);		/* Enable channel */	irq_unlock();}void dma_stop(int handle){	struct dma *dma = (struct dma *)handle;	u_int chan;	u_int bits;	ASSERT(handle);	irq_lock();	chan = dma->chan;	bits = (chan < 4) ? chan : chan >> 2;	outb_p(bits | 0x04, dma_regs[chan].mask);	/* Disable channel */	irq_unlock();}/* * Allocate DMA buffer * * Return page address in 64K byte boundary. * The caller must deallocate the pages by using page_free(). */void *dma_alloc(size_t size){	void *tmp, *base;	if (size > DMA_MAX)		return NULL;	/* Disable interrupts */	irq_lock();	/*	 * Try to allocate temporary buffer for enough size (64K + size).	 */	size = (size_t)PAGE_ALIGN(size);	tmp = page_alloc(DMA_MAX + size);	if (!tmp) {		irq_unlock();		return NULL;	}	page_free(tmp, DMA_MAX + size);	/*	 * Now, we know the free address with 64k boundary.	 */	base = (void *)DMA_ALIGN((u_long)tmp);	page_reserve(base, size);	/* Restore interrupts */	irq_unlock();	return phys_to_virt(base);}

⌨️ 快捷键说明

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