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

📄 dma.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
字号:
/* * linux/arch/arm/mach-s3c2410/dma.c * * Copyright (C) 2001 MIZI Research, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * * * History * * 2002-01-xx: 辫刮辟 *    - dma-sa1100.c甫 曼绊秦辑 绢蠢沥档 悼累窍档废 父店. * * 2002-03-20: Janghoon Lyu <nandy@mizi.com> *    - change queue structure *        The S3C2400's DMA controller has not internal hardware buffer. * * 2002-04-09: Janghoon Lyu <nandy@mizi.com> *    - BUG: UDA1330阑 捞侩秦辑 MP3颇老阑 敲饭捞窍绰 档吝俊 DMA-done 牢磐反飘 *           甫 初摹绰 版快啊 乐促. *      WORKAROUD: timer甫 窍唱 滴绢辑 DMA-done 牢磐反飘甫 初磨 版快, 捞甫 汗盔 *                 秦霖促. * * 2002-04-24: Janghoon Lyu <nandy@mizi.com> *    - USB甫 困秦辑 DMA备炼甫 函版窍看嚼聪促. *    - 角力肺 抛胶飘啊 鞘夸钦聪促. * * 2002-05-02: Janghoon Lyu <nandy@mizi.com> *    - 捞傈俊绰 窜规氢父阑 绊妨沁绰 R/W甫 葛滴 绊妨茄 备炼肺 函版 *    - BUG: DMA 盲澄篮 4俺 牢单 鸥捞赣绰 窍唱 挥? 备炼 绊磨 巴 * * 2002-05-07: Janghoon Lyu <nandy@mizi.com> *    - 促矫 货肺款 备炼肺(炔家厘丛 酒捞叼绢) *    - 鸥捞赣绰 咯傈洒 阂救... * * 2002-05-09: Janghoon Lyu <nandy@mizi.com> *    - s3c2400_dma_set_callback() 窃荐甫 request_dma()肺 烹钦 *    - 鸥捞赣 包访等 何盒 HOOK_LOST_INT肺 沥府 *    - 鸥捞赣 包府绰 咯傈洒 救登绊 乐澜. BIG BUG... *    - 俺急秦焊妨绊 矫档甫 秦好绰单, 磊铰磊冠.  *       flush()且 锭 timer甫 贸府甫 秦 拎具 登绰扒啊? * * 2002-05-28: Janghoon Lyu <nandy@mizi.com> *    - S3C2400俊 巴阑 S3C2410栏肺 颗辫 * * TODO: *   - sleep & wakeup 且 锭狼 内靛甫 眠啊秦具 钦聪促. */#include <linux/module.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/errno.h>#include <asm/irq.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/dma.h>#include "dma.h"/* debug macros */#undef DEBUG#ifdef DEBUG#define DPRINTK( s, arg... )  printk( "dma<%s>: " s, dma->device_id , ##arg )#else#define DPRINTK( x... )#endif/* * DMA processing... */static void process_dma(s3c2410_dma_t *dma){	dma_buf_t *buf, *next_buf;	dma_regs_t *regs = dma->regs;	int data_size, data_cnt; /* DMA request啊 惯积 且 锭 焊郴绰 单捞磐 农扁 */	dma_device_t *device;	buf = dma->head;	if (buf && (!dma->active)) {		if (buf->write) {			device = &dma->write;			regs->DISRCC = device->src_ctl;			regs->DISRC = DMA_BASE_ADDR(buf->dma_start);			regs->DIDSTC = device->dst_ctl;			regs->DIDST = device->dst;		} else {			device = &dma->read;			regs->DISRCC = device->src_ctl;			regs->DISRC = device->src;			regs->DIDSTC = device->dst_ctl;			regs->DIDST = DMA_BASE_ADDR(buf->dma_start);		}		data_size = readDSZ(device->ctl);		switch(data_size) {			case DSZ_BYTE: data_cnt = TX_CNT(buf->size); break;			case DSZ_HALFWORD: data_cnt = TX_CNT(buf->size/2); break;			default: data_cnt = TX_CNT(buf->size/4); break;		}		regs->DCON = device->ctl | data_cnt;		regs->DMASKTRIG = (DMA_STOP_CLR | CHANNEL_ON | DMA_SW_REQ_CLR);		dma->curr = buf;		next_buf = dma->head->next;		dma->head = next_buf;		if (!next_buf)			dma->tail = NULL;		dma->active = 1;		dma->queue_count--;		DPRINTK("start dma_ptr=%#x size=%d\n", buf->dma_start, buf->size);		DPRINTK("number of buffers in queue: %ld\n", dma->queue_count);#ifdef HOOK_LOST_INT		if (buf->write) start_dma_timer();#endif	}}static inline void s3c2410_dma_done(s3c2410_dma_t *dma){	dma_buf_t *buf = dma->curr;	dma_callback_t callback;	if (buf->write) callback = dma->write.callback;	else callback = dma->read.callback;#ifdef HOOK_LOST_INT	stop_dma_timer();#endif	DPRINTK("IRQ: b=%#x st=%ld\n", (int)buf->id, (long)dma->regs->DSTAT);	if (callback)		callback(buf->id, buf->size);	kfree(buf);	dma->active = 0;	process_dma(dma);}static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs){	s3c2410_dma_t *dma = (s3c2410_dma_t *)dev_id;	DPRINTK(__FUNCTION__"\n");	s3c2410_dma_done(dma);}#ifdef HOOK_LOST_INTstatic void dma_timer_irq_handler(int irq, void *dev_id, struct pt_regs *regs){	s3c2410_dma_t *dma = NULL;	int channel;	//DPRINTK("in timer interrupts\r\n");	for (channel = 0; channel < MAX_S3C2410_DMA_CHANNELS; channel++) {		dma = &dma_chan[channel];		if ((dma->in_use == 1) && (dma->regs->DSTAT == 0x0) && (dma->active)) {			DPRINTK(__FUNCTION__" channel=%d\n", (int)channel);			s3c2410_dma_done(dma);		}	}}#endif/* * DMA interface functions */static int fill_dma_source(int channel, const char *dev_name, 			   dma_device_t *write, dma_device_t *read){	int source;	dma_type_t *dma_type = dma_types[channel];	for(source=0;source<4;source++) {		if (strcmp(dma_type[source].name, dev_name) == 0)			break;	}	if (source >= 4) return -1;	dma_type += source;	write->src = dma_type->write_src;	write->dst = dma_type->write_dst;	write->ctl = dma_type->write_ctl;	write->src_ctl = dma_type->write_src_ctl;	write->dst_ctl = dma_type->write_dst_ctl;	read->src = dma_type->read_src;	read->dst = dma_type->read_dst;	read->ctl = dma_type->read_ctl;	read->src_ctl = dma_type->read_src_ctl;	read->dst_ctl = dma_type->read_dst_ctl;	return 0;}static spinlock_t dma_list_lock;int s3c2410_request_dma(const char *device_id, dmach_t channel,			dma_callback_t write_cb, dma_callback_t read_cb){	s3c2410_dma_t *dma;	int err;	if ((channel < 0) || (channel >= MAX_S3C2410_DMA_CHANNELS)) {		printk(KERN_ERR "%s: not support #%d DMA channel\n", device_id, channel);		return  -ENODEV;	}	err = 0;	spin_lock(&dma_list_lock);	dma = &dma_chan[channel];	if (dma->in_use) {		printk(KERN_ERR "%s: DMA channel is busy\n", device_id);		err = -EBUSY;	} else {		dma->in_use = 1;	}	spin_unlock(&dma_list_lock);	if (err)		return err;	err = fill_dma_source(channel, device_id, &dma->write, &dma->read);	if (err < 0) {		printk(KERN_ERR "%s: can not found this devcie\n", device_id);		dma->in_use = 0;		return err;	}	err = request_irq(dma->irq, dma_irq_handler, 0 * SA_INTERRUPT,					  device_id, (void *)dma);	if (err) {		printk( KERN_ERR			"%s: unable to request IRQ %d for DMA channel\n",			device_id, dma->irq);		dma->in_use = 0;		return err;	}	dma->device_id = device_id;	dma->head = dma->tail = dma->curr = NULL;	dma->write.callback = write_cb;	dma->read.callback = read_cb;	DPRINTK("write cb = %p, read cb = %p\n", dma->write.callback, dma->read.callback);	DPRINTK("requested\n");	return 0;}int s3c2410_dma_queue_buffer(dmach_t channel, void *buf_id,			     dma_addr_t data, int size, int write){	s3c2410_dma_t *dma;	dma_buf_t *buf;	int flags;	dma = &dma_chan[channel];	if ((channel >= MAX_S3C2410_DMA_CHANNELS) || (!dma->in_use))		return -EINVAL;	buf = kmalloc(sizeof(*buf), GFP_ATOMIC);	if (!buf)		return -ENOMEM;	buf->next = NULL;	buf->ref = 0;	buf->dma_start = data;	buf->size = size;	buf->id = buf_id;	buf->write = write;	DPRINTK("queueing b=%#x, a=%#x, s=%d, w=%d\n", (int) buf_id, data, size, write);	local_irq_save(flags);	if (dma->tail)		dma->tail->next = buf;	else		dma->head = buf;		dma->tail = buf;	buf->next = NULL;	dma->queue_count++;	DPRINTK("number of buffers in queue: %ld\n", dma->queue_count);	process_dma(dma);	local_irq_restore(flags);	return 0;}/* * dma_get_current()甫 龋免茄 饶 dma_stop()阑 龋免秦具 钦聪促. * 开鉴栏肺 窍搁 盔窍绰 蔼捞 救 唱棵荐档 乐嚼聪促. */int s3c2410_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr){	s3c2410_dma_t *dma = &dma_chan[channel];	dma_regs_t *regs;	int flags, ret;	if ((channel >= MAX_S3C2410_DMA_CHANNELS) || (!dma->in_use)) 		return -EINVAL;	regs = dma->regs;	local_irq_save(flags);	if (dma->curr) {		dma_buf_t *buf = dma->curr;		int status = regs->DSTAT;		if (buf_id)			*buf_id = buf->id;		if (status > 0)			*addr = regs->DCSRC;		DPRINTK("curr_pos: b=%#x a=%#x\n", (int)dma->curr->id, *addr);		ret = 0;	} else if (dma->head && !dma->active) {		dma_buf_t *buf = dma->head;		if (buf_id)			*buf_id = buf->id;		*addr = buf->dma_start;		ret = 0;	} else {		if (buf_id)			*buf_id = NULL;		*addr = 0;		ret = -ENXIO;	}	local_irq_restore(flags);	return ret;}/* * 秦寸 盲澄狼 DMA controller甫 沥瘤矫诺聪促. * dma_resume()俊 措秦辑绰 酒流 绊妨啊 救 登绢乐嚼聪促. */int s3c2410_dma_stop(dmach_t channel){	s3c2410_dma_t *dma = &dma_chan[channel];	dma_buf_t *buf = dma->curr;	dma_regs_t *regs = dma->regs;	dma_callback_t callback;	int flags;	if (!dma->active)		return 0;	local_irq_save(flags);#ifdef HOOK_LOST_INT	stop_dma_timer();#endif	regs->DMASKTRIG = DMA_STOP; 	if (buf->write) callback = dma->write.callback;	else callback = dma->read.callback;	if (callback)		callback(buf->id, buf->size);	kfree(buf);	dma->active = 0;	process_dma(dma);	local_irq_restore(flags);	DPRINTK("dma stopped\n");	return 0;}int s3c2410_dma_flush_all(dmach_t channel){	s3c2410_dma_t *dma = &dma_chan[channel];	dma_buf_t *buf, *next_buf;	int flags;	if ((channel >= MAX_S3C2410_DMA_CHANNELS) || (!dma->in_use))		return -EINVAL;	local_irq_save(flags);	dma->regs->DMASKTRIG = DMASKTRIG_STOP;	buf = dma->head;	dma->head = dma->tail = dma->curr = NULL;	dma->active = 0;	dma->queue_count = 0;	dma->active = 0;	local_irq_restore(flags);	while (buf) {		next_buf = buf->next;		kfree(buf);		buf = next_buf;	}	DPRINTK("flushed\n");	return 0;}void s3c2410_free_dma(dmach_t channel){	s3c2410_dma_t *dma;	if (channel >= MAX_S3C2410_DMA_CHANNELS)		return;	dma = &dma_chan[channel];	if (!dma->in_use) {		printk(KERN_ERR "Trying to free DMA%d\n", channel);		return;	}	s3c2410_dma_flush_all(channel);	free_irq(dma->irq, (void *)dma);	dma->in_use = 0;#ifdef HOOK_LOST_INT	stop_dma_timer();#endif	DPRINTK("freed\n");}EXPORT_SYMBOL(s3c2410_request_dma);EXPORT_SYMBOL(s3c2410_dma_queue_buffer);EXPORT_SYMBOL(s3c2410_dma_get_current);EXPORT_SYMBOL(s3c2410_dma_stop);EXPORT_SYMBOL(s3c2410_dma_flush_all);EXPORT_SYMBOL(s3c2410_free_dma);static int __init s3c2410_init_dma(void){	int channel;#ifdef HOOK_LOST_INT	int ret;#endif	for (channel = 0; channel < (MAX_S3C2410_DMA_CHANNELS); channel++) {		dma_chan[channel].regs =				(dma_regs_t *)io_p2v(0x4b000000 + 0x40 * channel);		dma_chan[channel].irq = IRQ_DMA0 + channel;		dma_chan[channel].channel = channel;	}#ifdef HOOK_LOST_INT	/* 鞘夸茄啊? 犬牢 荤混侩 */	stop_dma_timer();	ret = request_irq(IRQ_TIMER3, dma_timer_irq_handler, SA_INTERRUPT,			  "DMA timer", NULL);	if (ret)		printk(__FUNCTION__ " : could not allocate IRQ (errno %d)\n", ret);#endif	return 0;}__initcall(s3c2410_init_dma);

⌨️ 快捷键说明

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