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

📄 dma.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
}/** * imx_dma_enable - function to start i.MX DMA channel operation * @dma_ch: i.MX DMA channel number * * The channel has to be allocated by driver through imx_dma_request() * or imx_dma_request_by_prio() function. * The transfer parameters has to be set to the channel registers through * call of the imx_dma_setup_single() or imx_dma_setup_sg() function * and registers %BLR(dma_ch), %RSSR(dma_ch) and %CCR(dma_ch) has to * be set prior this function call by the channel user. */void imx_dma_enable(imx_dmach_t dma_ch){	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];	unsigned long flags;	pr_debug("imxdma%d: imx_dma_enable\n", dma_ch);	if (!imxdma->name) {		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",		       __FUNCTION__, dma_ch);		return;	}	local_irq_save(flags);	DISR = (1 << dma_ch);	DIMR &= ~(1 << dma_ch);	CCR(dma_ch) |= CCR_CEN;	local_irq_restore(flags);}/** * imx_dma_disable - stop, finish i.MX DMA channel operatin * @dma_ch: i.MX DMA channel number */void imx_dma_disable(imx_dmach_t dma_ch){	unsigned long flags;	pr_debug("imxdma%d: imx_dma_disable\n", dma_ch);	local_irq_save(flags);	DIMR |= (1 << dma_ch);	CCR(dma_ch) &= ~CCR_CEN;	DISR = (1 << dma_ch);	local_irq_restore(flags);}/** * imx_dma_request - request/allocate specified channel number * @dma_ch: i.MX DMA channel number * @name: the driver/caller own non-%NULL identification */int imx_dma_request(imx_dmach_t dma_ch, const char *name){	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];	unsigned long flags;	/* basic sanity checks */	if (!name)		return -EINVAL;	if (dma_ch >= IMX_DMA_CHANNELS) {		printk(KERN_CRIT "%s: called for  non-existed channel %d\n",		       __FUNCTION__, dma_ch);		return -EINVAL;	}	local_irq_save(flags);	if (imxdma->name) {		local_irq_restore(flags);		return -ENODEV;	}	imxdma->name = name;	imxdma->irq_handler = NULL;	imxdma->err_handler = NULL;	imxdma->data = NULL;	imxdma->sg = NULL;	local_irq_restore(flags);	return 0;}/** * imx_dma_free - release previously acquired channel * @dma_ch: i.MX DMA channel number */void imx_dma_free(imx_dmach_t dma_ch){	unsigned long flags;	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];	if (!imxdma->name) {		printk(KERN_CRIT		       "%s: trying to free channel %d which is already freed\n",		       __FUNCTION__, dma_ch);		return;	}	local_irq_save(flags);	/* Disable interrupts */	DIMR |= (1 << dma_ch);	CCR(dma_ch) &= ~CCR_CEN;	imxdma->name = NULL;	local_irq_restore(flags);}/** * imx_dma_request_by_prio - find and request some of free channels best suiting requested priority * @dma_ch: i.MX DMA channel number * @name: the driver/caller own non-%NULL identification * @prio: one of the hardware distinguished priority level: *        %DMA_PRIO_HIGH, %DMA_PRIO_MEDIUM, %DMA_PRIO_LOW * * This function tries to find free channel in the specified priority group * if the priority cannot be achieved it tries to look for free channel * in the higher and then even lower priority groups. * * Return value: If there is no free channel to allocate, -%ENODEV is returned. *               Zero value indicates successful channel allocation. */intimx_dma_request_by_prio(imx_dmach_t * pdma_ch, const char *name,			imx_dma_prio prio){	int i;	int best;	switch (prio) {	case (DMA_PRIO_HIGH):		best = 8;		break;	case (DMA_PRIO_MEDIUM):		best = 4;		break;	case (DMA_PRIO_LOW):	default:		best = 0;		break;	}	for (i = best; i < IMX_DMA_CHANNELS; i++) {		if (!imx_dma_request(i, name)) {			*pdma_ch = i;			return 0;		}	}	for (i = best - 1; i >= 0; i--) {		if (!imx_dma_request(i, name)) {			*pdma_ch = i;			return 0;		}	}	printk(KERN_ERR "%s: no free DMA channel found\n", __FUNCTION__);	return -ENODEV;}static irqreturn_t dma_err_handler(int irq, void *dev_id){	int i, disr = DISR;	struct imx_dma_channel *channel;	unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;	int errcode;	DISR = disr & err_mask;	for (i = 0; i < IMX_DMA_CHANNELS; i++) {		if(!(err_mask & (1 << i)))			continue;		channel = &imx_dma_channels[i];		errcode = 0;		if (DBTOSR & (1 << i)) {			DBTOSR = (1 << i);			errcode |= IMX_DMA_ERR_BURST;		}		if (DRTOSR & (1 << i)) {			DRTOSR = (1 << i);			errcode |= IMX_DMA_ERR_REQUEST;		}		if (DSESR & (1 << i)) {			DSESR = (1 << i);			errcode |= IMX_DMA_ERR_TRANSFER;		}		if (DBOSR & (1 << i)) {			DBOSR = (1 << i);			errcode |= IMX_DMA_ERR_BUFFER;		}		/*		 * The cleaning of @sg field would be questionable		 * there, because its value can help to compute		 * remaining/transferred bytes count in the handler		 */		/*imx_dma_channels[i].sg = NULL;*/		if (channel->name && channel->err_handler) {			channel->err_handler(i, channel->data, errcode);			continue;		}		imx_dma_channels[i].sg = NULL;		printk(KERN_WARNING		       "DMA timeout on channel %d (%s) -%s%s%s%s\n",		       i, channel->name,		       errcode&IMX_DMA_ERR_BURST?    " burst":"",		       errcode&IMX_DMA_ERR_REQUEST?  " request":"",		       errcode&IMX_DMA_ERR_TRANSFER? " transfer":"",		       errcode&IMX_DMA_ERR_BUFFER?   " buffer":"");	}	return IRQ_HANDLED;}static irqreturn_t dma_irq_handler(int irq, void *dev_id){	int i, disr = DISR;	pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n",		     disr);	DISR = disr;	for (i = 0; i < IMX_DMA_CHANNELS; i++) {		if (disr & (1 << i)) {			struct imx_dma_channel *channel = &imx_dma_channels[i];			if (channel->name) {				if (imx_dma_sg_next(i, CNTR(i))) {					CCR(i) &= ~CCR_CEN;					mb();					CCR(i) |= CCR_CEN;				} else {					if (channel->irq_handler)						channel->irq_handler(i,							channel->data);				}			} else {				/*				 * IRQ for an unregistered DMA channel:				 * let's clear the interrupts and disable it.				 */				printk(KERN_WARNING				       "spurious IRQ for DMA channel %d\n", i);			}		}	}	return IRQ_HANDLED;}static int __init imx_dma_init(void){	int ret;	int i;	/* reset DMA module */	DCR = DCR_DRST;	ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);	if (ret) {		printk(KERN_CRIT "Wow!  Can't register IRQ for DMA\n");		return ret;	}	ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL);	if (ret) {		printk(KERN_CRIT "Wow!  Can't register ERRIRQ for DMA\n");		free_irq(DMA_INT, NULL);	}	/* enable DMA module */	DCR = DCR_DEN;	/* clear all interrupts */	DISR = (1 << IMX_DMA_CHANNELS) - 1;	/* enable interrupts */	DIMR = (1 << IMX_DMA_CHANNELS) - 1;	for (i = 0; i < IMX_DMA_CHANNELS; i++) {		imx_dma_channels[i].sg = NULL;		imx_dma_channels[i].dma_num = i;	}	return ret;}arch_initcall(imx_dma_init);EXPORT_SYMBOL(imx_dma_setup_single);EXPORT_SYMBOL(imx_dma_setup_sg);EXPORT_SYMBOL(imx_dma_setup_handlers);EXPORT_SYMBOL(imx_dma_enable);EXPORT_SYMBOL(imx_dma_disable);EXPORT_SYMBOL(imx_dma_request);EXPORT_SYMBOL(imx_dma_free);EXPORT_SYMBOL(imx_dma_request_by_prio);EXPORT_SYMBOL(imx_dma_channels);

⌨️ 快捷键说明

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