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

📄 dma.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		chan->end->next = buf;		chan->end = buf;	}	/* if necessary, update the next buffer field */	if (chan->next == NULL)		chan->next = buf;	/* check to see if we can load a buffer */	if (chan->state == S3C2410_DMA_RUNNING) {		if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {				printk(KERN_ERR "dma%d: loadbuffer:"				       "timeout loading buffer\n",				       chan->number);				dbg_showchan(chan);				local_irq_restore(flags);				return -EINVAL;			}		}		while (s3c2410_dma_canload(chan) && chan->next != NULL) {			s3c2410_dma_loadbuffer(chan, chan->next);		}	} else if (chan->state == S3C2410_DMA_IDLE) {		if (chan->flags & S3C2410_DMAF_AUTOSTART) {			s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);		}	}	local_irq_restore(flags);	return 0;}EXPORT_SYMBOL(s3c2410_dma_enqueue);static inline voids3c2410_dma_freebuf(struct s3c2410_dma_buf *buf){	int magicok = (buf->magic == BUF_MAGIC);	buf->magic = -1;	if (magicok) {		kmem_cache_free(dma_kmem, buf);	} else {		printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);	}}/* s3c2410_dma_lastxfer * * called when the system is out of buffers, to ensure that the channel * is prepared for shutdown.*/static inline voids3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan){#if 0	pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",		 chan->number, chan->load_state);#endif	switch (chan->load_state) {	case S3C2410_DMALOAD_NONE:		break;	case S3C2410_DMALOAD_1LOADED:		if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {				/* flag error? */			printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",			       chan->number, __FUNCTION__);			return;		}		break;	case S3C2410_DMALOAD_1LOADED_1RUNNING:		/* I belive in this case we do not have anything to do		 * until the next buffer comes along, and we turn off the		 * reload */		return;	default:		pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",			 chan->number, chan->load_state);		return;	}	/* hopefully this'll shut the damned thing up after the transfer... */	dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);}#define dmadbg2(x...)static irqreturn_ts3c2410_dma_irq(int irq, void *devpw){	struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;	struct s3c2410_dma_buf  *buf;	buf = chan->curr;	dbg_showchan(chan);	/* modify the channel state */	switch (chan->load_state) {	case S3C2410_DMALOAD_1RUNNING:		/* TODO - if we are running only one buffer, we probably		 * want to reload here, and then worry about the buffer		 * callback */		chan->load_state = S3C2410_DMALOAD_NONE;		break;	case S3C2410_DMALOAD_1LOADED:		/* iirc, we should go back to NONE loaded here, we		 * had a buffer, and it was never verified as being		 * loaded.		 */		chan->load_state = S3C2410_DMALOAD_NONE;		break;	case S3C2410_DMALOAD_1LOADED_1RUNNING:		/* we'll worry about checking to see if another buffer is		 * ready after we've called back the owner. This should		 * ensure we do not wait around too long for the DMA		 * engine to start the next transfer		 */		chan->load_state = S3C2410_DMALOAD_1LOADED;		break;	case S3C2410_DMALOAD_NONE:		printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",		       chan->number);		break;	default:		printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",		       chan->number, chan->load_state);		break;	}	if (buf != NULL) {		/* update the chain to make sure that if we load any more		 * buffers when we call the callback function, things should		 * work properly */		chan->curr = buf->next;		buf->next  = NULL;		if (buf->magic != BUF_MAGIC) {			printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",			       chan->number, __FUNCTION__, buf);			return IRQ_HANDLED;		}		s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);		/* free resouces */		s3c2410_dma_freebuf(buf);	} else {	}	/* only reload if the channel is still running... our buffer done	 * routine may have altered the state by requesting the dma channel	 * to stop or shutdown... */	/* todo: check that when the channel is shut-down from inside this	 * function, we cope with unsetting reload, etc */	if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {		unsigned long flags;		switch (chan->load_state) {		case S3C2410_DMALOAD_1RUNNING:			/* don't need to do anything for this state */			break;		case S3C2410_DMALOAD_NONE:			/* can load buffer immediately */			break;		case S3C2410_DMALOAD_1LOADED:			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {				/* flag error? */				printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",				       chan->number, __FUNCTION__);				return IRQ_HANDLED;			}			break;		case S3C2410_DMALOAD_1LOADED_1RUNNING:			goto no_load;		default:			printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",			       chan->number, chan->load_state);			return IRQ_HANDLED;		}		local_irq_save(flags);		s3c2410_dma_loadbuffer(chan, chan->next);		local_irq_restore(flags);	} else {		s3c2410_dma_lastxfer(chan);		/* see if we can stop this channel.. */		if (chan->load_state == S3C2410_DMALOAD_NONE) {			pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",				 chan->number, jiffies);			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,					 S3C2410_DMAOP_STOP);		}	} no_load:	return IRQ_HANDLED;}static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);/* s3c2410_request_dma * * get control of an dma channel*/int s3c2410_dma_request(unsigned int channel,			struct s3c2410_dma_client *client,			void *dev){	struct s3c2410_dma_chan *chan;	unsigned long flags;	int err;	pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",		 channel, client->name, dev);	local_irq_save(flags);	chan = s3c2410_dma_map_channel(channel);	if (chan == NULL) {		local_irq_restore(flags);		return -EBUSY;	}	dbg_showchan(chan);	chan->client = client;	chan->in_use = 1;	if (!chan->irq_claimed) {		pr_debug("dma%d: %s : requesting irq %d\n",			 channel, __FUNCTION__, chan->irq);		chan->irq_claimed = 1;		local_irq_restore(flags);		err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,				  client->name, (void *)chan);		local_irq_save(flags);		if (err) {			chan->in_use = 0;			chan->irq_claimed = 0;			local_irq_restore(flags);			printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",			       client->name, chan->irq, chan->number);			return err;		}		chan->irq_enabled = 1;	}	local_irq_restore(flags);	/* need to setup */	pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);	return 0;}EXPORT_SYMBOL(s3c2410_dma_request);/* s3c2410_dma_free * * release the given channel back to the system, will stop and flush * any outstanding transfers, and ensure the channel is ready for the * next claimant. * * Note, although a warning is currently printed if the freeing client * info is not the same as the registrant's client info, the free is still * allowed to go through.*/int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client){	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);	unsigned long flags;	if (chan == NULL)		return -EINVAL;	local_irq_save(flags);	if (chan->client != client) {		printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",		       channel, chan->client, client);	}	/* sort out stopping and freeing the channel */	if (chan->state != S3C2410_DMA_IDLE) {		pr_debug("%s: need to stop dma channel %p\n",		       __FUNCTION__, chan);		/* possibly flush the channel */		s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);	}	chan->client = NULL;	chan->in_use = 0;	if (chan->irq_claimed)		free_irq(chan->irq, (void *)chan);	chan->irq_claimed = 0;	if (!(channel & DMACH_LOW_LEVEL))		dma_chan_map[channel] = NULL;	local_irq_restore(flags);	return 0;}EXPORT_SYMBOL(s3c2410_dma_free);static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan){	unsigned long flags;	unsigned long tmp;	pr_debug("%s:\n", __FUNCTION__);	dbg_showchan(chan);	local_irq_save(flags);	s3c2410_dma_call_op(chan,  S3C2410_DMAOP_STOP);	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);	tmp |= S3C2410_DMASKTRIG_STOP;	//tmp &= ~S3C2410_DMASKTRIG_ON;	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);#if 0	/* should also clear interrupts, according to WinCE BSP */	tmp = dma_rdreg(chan, S3C2410_DMA_DCON);	tmp |= S3C2410_DCON_NORELOAD;	dma_wrreg(chan, S3C2410_DMA_DCON, tmp);#endif	/* should stop do this, or should we wait for flush? */	chan->state      = S3C2410_DMA_IDLE;	chan->load_state = S3C2410_DMALOAD_NONE;	local_irq_restore(flags);	return 0;}static void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan){	unsigned long tmp;	unsigned int timeout = 0x10000;	while (timeout-- > 0) {		tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);		if (!(tmp & S3C2410_DMASKTRIG_ON))			return;	}	pr_debug("dma%d: failed to stop?\n", chan->number);}/* s3c2410_dma_flush * * stop the channel, and remove all current and pending transfers*/static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan){	struct s3c2410_dma_buf *buf, *next;	unsigned long flags;	pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number);	dbg_showchan(chan);	local_irq_save(flags);	if (chan->state != S3C2410_DMA_IDLE) {		pr_debug("%s: stopping channel...\n", __FUNCTION__ );		s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);	}	buf = chan->curr;	if (buf == NULL)		buf = chan->next;	chan->curr = chan->next = chan->end = NULL;	if (buf != NULL) {		for ( ; buf != NULL; buf = next) {			next = buf->next;			pr_debug("%s: free buffer %p, next %p\n",			       __FUNCTION__, buf, buf->next);			s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);			s3c2410_dma_freebuf(buf);		}	}	dbg_showregs(chan);	s3c2410_dma_waitforstop(chan);#if 0	/* should also clear interrupts, according to WinCE BSP */	{		unsigned long tmp;		tmp = dma_rdreg(chan, S3C2410_DMA_DCON);		tmp |= S3C2410_DCON_NORELOAD;		dma_wrreg(chan, S3C2410_DMA_DCON, tmp);	}#endif	dbg_showregs(chan);	local_irq_restore(flags);	return 0;}static int s3c2410_dma_started(struct s3c2410_dma_chan *chan){	unsigned long flags;	local_irq_save(flags);	dbg_showchan(chan);	/* if we've only loaded one buffer onto the channel, then chec	 * to see if we have another, and if so, try and load it so when	 * the first buffer is finished, the new one will be loaded onto	 * the channel */	if (chan->next != NULL) {		if (chan->load_state == S3C2410_DMALOAD_1LOADED) {			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {				pr_debug("%s: buff not yet loaded, no more todo\n",					 __FUNCTION__);			} else {				chan->load_state = S3C2410_DMALOAD_1RUNNING;				s3c2410_dma_loadbuffer(chan, chan->next);			}		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {			s3c2410_dma_loadbuffer(chan, chan->next);		}	}	local_irq_restore(flags);	return 0;}ints3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op){	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);

⌨️ 快捷键说明

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