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

📄 dma-g2.c

📁 linux内核源码
💻 C
字号:
/* * arch/sh/drivers/dma/dma-g2.c * * G2 bus DMA support * * Copyright (C) 2003 - 2006  Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. */#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/interrupt.h>#include <asm/cacheflush.h>#include <asm/mach/sysasic.h>#include <asm/mach/dma.h>#include <asm/dma.h>struct g2_channel {	unsigned long g2_addr;		/* G2 bus address */	unsigned long root_addr;	/* Root bus (SH-4) address */	unsigned long size;		/* Size (in bytes), 32-byte aligned */	unsigned long direction;	/* Transfer direction */	unsigned long ctrl;		/* Transfer control */	unsigned long chan_enable;	/* Channel enable */	unsigned long xfer_enable;	/* Transfer enable */	unsigned long xfer_stat;	/* Transfer status */} __attribute__ ((aligned(32)));struct g2_status {	unsigned long g2_addr;	unsigned long root_addr;	unsigned long size;	unsigned long status;} __attribute__ ((aligned(16)));struct g2_dma_info {	struct g2_channel channel[G2_NR_DMA_CHANNELS];	unsigned long pad1[G2_NR_DMA_CHANNELS];	unsigned long wait_state;	unsigned long pad2[10];	unsigned long magic;	struct g2_status status[G2_NR_DMA_CHANNELS];} __attribute__ ((aligned(256)));static volatile struct g2_dma_info *g2_dma = (volatile struct g2_dma_info *)0xa05f7800;#define g2_bytes_remaining(i) \	((g2_dma->channel[i].size - \	  g2_dma->status[i].size) & 0x0fffffff)static irqreturn_t g2_dma_interrupt(int irq, void *dev_id){	int i;	for (i = 0; i < G2_NR_DMA_CHANNELS; i++) {		if (g2_dma->status[i].status & 0x20000000) {			unsigned int bytes = g2_bytes_remaining(i);			if (likely(bytes == 0)) {				struct dma_info *info = dev_id;				struct dma_channel *chan = info->channels + i;				wake_up(&chan->wait_queue);				return IRQ_HANDLED;			}		}	}	return IRQ_NONE;}static int g2_enable_dma(struct dma_channel *chan){	unsigned int chan_nr = chan->chan;	g2_dma->channel[chan_nr].chan_enable = 1;	g2_dma->channel[chan_nr].xfer_enable = 1;	return 0;}static int g2_disable_dma(struct dma_channel *chan){	unsigned int chan_nr = chan->chan;	g2_dma->channel[chan_nr].chan_enable = 0;	g2_dma->channel[chan_nr].xfer_enable = 0;	return 0;}static int g2_xfer_dma(struct dma_channel *chan){	unsigned int chan_nr = chan->chan;	if (chan->sar & 31) {		printk("g2dma: unaligned source 0x%lx\n", chan->sar);		return -EINVAL;	}	if (chan->dar & 31) {		printk("g2dma: unaligned dest 0x%lx\n", chan->dar);		return -EINVAL;	}	/* Align the count */	if (chan->count & 31)		chan->count = (chan->count + (32 - 1)) & ~(32 - 1);	/* Fixup destination */	chan->dar += 0xa0800000;	/* Fixup direction */	chan->mode = !chan->mode;	flush_icache_range((unsigned long)chan->sar, chan->count);	g2_disable_dma(chan);	g2_dma->channel[chan_nr].g2_addr   = chan->dar & 0x1fffffe0;	g2_dma->channel[chan_nr].root_addr = chan->sar & 0x1fffffe0;	g2_dma->channel[chan_nr].size	   = (chan->count & ~31) | 0x80000000;	g2_dma->channel[chan_nr].direction = chan->mode;	/*	 * bit 0 - ???	 * bit 1 - if set, generate a hardware event on transfer completion	 * bit 2 - ??? something to do with suspend?	 */	g2_dma->channel[chan_nr].ctrl	= 5; /* ?? */	g2_enable_dma(chan);	/* debug cruft */	pr_debug("count, sar, dar, mode, ctrl, chan, xfer: %ld, 0x%08lx, "		 "0x%08lx, %ld, %ld, %ld, %ld\n",		 g2_dma->channel[chan_nr].size,		 g2_dma->channel[chan_nr].root_addr,		 g2_dma->channel[chan_nr].g2_addr,		 g2_dma->channel[chan_nr].direction,		 g2_dma->channel[chan_nr].ctrl,		 g2_dma->channel[chan_nr].chan_enable,		 g2_dma->channel[chan_nr].xfer_enable);	return 0;}static int g2_get_residue(struct dma_channel *chan){	return g2_bytes_remaining(chan->chan);}static struct dma_ops g2_dma_ops = {	.xfer		= g2_xfer_dma,	.get_residue	= g2_get_residue,};static struct dma_info g2_dma_info = {	.name		= "g2_dmac",	.nr_channels	= 4,	.ops		= &g2_dma_ops,	.flags		= DMAC_CHANNELS_TEI_CAPABLE,};static int __init g2_dma_init(void){	int ret;	ret = request_irq(HW_EVENT_G2_DMA, g2_dma_interrupt, IRQF_DISABLED,			  "g2 DMA handler", &g2_dma_info);	if (unlikely(ret))		return -EINVAL;	/* Magic */	g2_dma->wait_state	= 27;	g2_dma->magic		= 0x4659404f;	ret = register_dmac(&g2_dma_info);	if (unlikely(ret != 0))		free_irq(HW_EVENT_G2_DMA, 0);	return ret;}static void __exit g2_dma_exit(void){	free_irq(HW_EVENT_G2_DMA, 0);	unregister_dmac(&g2_dma_info);}subsys_initcall(g2_dma_init);module_exit(g2_dma_exit);MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");MODULE_DESCRIPTION("G2 bus DMA driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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