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

📄 dma.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (chan == NULL)		return -EINVAL;	switch (op) {	case S3C2410_DMAOP_START:		return s3c2410_dma_start(chan);	case S3C2410_DMAOP_STOP:		return s3c2410_dma_dostop(chan);	case S3C2410_DMAOP_PAUSE:	case S3C2410_DMAOP_RESUME:		return -ENOENT;	case S3C2410_DMAOP_FLUSH:		return s3c2410_dma_flush(chan);	case S3C2410_DMAOP_STARTED:		return s3c2410_dma_started(chan);	case S3C2410_DMAOP_TIMEOUT:		return 0;	}	return -ENOENT;      /* unknown, don't bother */}EXPORT_SYMBOL(s3c2410_dma_ctrl);/* DMA configuration for each channel * * DISRCC -> source of the DMA (AHB,APB) * DISRC  -> source address of the DMA * DIDSTC -> destination of the DMA (AHB,APD) * DIDST  -> destination address of the DMA*//* s3c2410_dma_config * * xfersize:     size of unit in bytes (1,2,4) * dcon:         base value of the DCONx register*/int s3c2410_dma_config(dmach_t channel,		       int xferunit,		       int dcon){	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);	pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",		 __FUNCTION__, channel, xferunit, dcon);	if (chan == NULL)		return -EINVAL;	pr_debug("%s: Initial dcon is %08x\n", __FUNCTION__, dcon);	dcon |= chan->dcon & dma_sel.dcon_mask;	pr_debug("%s: New dcon is %08x\n", __FUNCTION__, dcon);	switch (xferunit) {	case 1:		dcon |= S3C2410_DCON_BYTE;		break;	case 2:		dcon |= S3C2410_DCON_HALFWORD;		break;	case 4:		dcon |= S3C2410_DCON_WORD;		break;	default:		pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit);		return -EINVAL;	}	dcon |= S3C2410_DCON_HWTRIG;	dcon |= S3C2410_DCON_INTREQ;	pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon);	chan->dcon = dcon;	chan->xfer_unit = xferunit;	return 0;}EXPORT_SYMBOL(s3c2410_dma_config);int s3c2410_dma_setflags(dmach_t channel, unsigned int flags){	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);	if (chan == NULL)		return -EINVAL;	pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);	chan->flags = flags;	return 0;}EXPORT_SYMBOL(s3c2410_dma_setflags);/* do we need to protect the settings of the fields from * irq?*/int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn){	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);	if (chan == NULL)		return -EINVAL;	pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);	chan->op_fn = rtn;	return 0;}EXPORT_SYMBOL(s3c2410_dma_set_opfn);int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn){	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);	if (chan == NULL)		return -EINVAL;	pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);	chan->callback_fn = rtn;	return 0;}EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);/* s3c2410_dma_devconfig * * configure the dma source/destination hardware type and address * * source:    S3C2410_DMASRC_HW: source is hardware *            S3C2410_DMASRC_MEM: source is memory * * hwcfg:     the value for xxxSTCn register, *            bit 0: 0=increment pointer, 1=leave pointer *            bit 1: 0=source is AHB, 1=source is APB * * devaddr:   physical address of the source*/int s3c2410_dma_devconfig(int channel,			  enum s3c2410_dmasrc source,			  int hwcfg,			  unsigned long devaddr){	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);	if (chan == NULL)		return -EINVAL;	pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",		 __FUNCTION__, (int)source, hwcfg, devaddr);	chan->source = source;	chan->dev_addr = devaddr;	switch (source) {	case S3C2410_DMASRC_HW:		/* source is hardware */		pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",			 __FUNCTION__, devaddr, hwcfg);		dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);		dma_wrreg(chan, S3C2410_DMA_DISRC,  devaddr);		dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);		return 0;	case S3C2410_DMASRC_MEM:		/* source is memory */		pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",			  __FUNCTION__, devaddr, hwcfg);		dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));		dma_wrreg(chan, S3C2410_DMA_DIDST,  devaddr);		dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);		return 0;	}	printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);	return -EINVAL;}EXPORT_SYMBOL(s3c2410_dma_devconfig);/* s3c2410_dma_getposition * * returns the current transfer points for the dma source and destination*/int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst){ 	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);	if (chan == NULL)		return -EINVAL;	if (src != NULL) 		*src = dma_rdreg(chan, S3C2410_DMA_DCSRC); 	if (dst != NULL) 		*dst = dma_rdreg(chan, S3C2410_DMA_DCDST); 	return 0;}EXPORT_SYMBOL(s3c2410_dma_getposition);/* system device class */#ifdef CONFIG_PMstatic int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state){	struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev);	printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);	if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {		/* the dma channel is still working, which is probably		 * a bad thing to do over suspend/resume. We stop the		 * channel and assume that the client is either going to		 * retry after resume, or that it is broken.		 */		printk(KERN_INFO "dma: stopping channel %d due to suspend\n",		       cp->number);		s3c2410_dma_dostop(cp);	}	return 0;}static int s3c2410_dma_resume(struct sys_device *dev){	return 0;}#else#define s3c2410_dma_suspend NULL#define s3c2410_dma_resume  NULL#endif /* CONFIG_PM */struct sysdev_class dma_sysclass = {	set_kset_name("s3c24xx-dma"),	.suspend	= s3c2410_dma_suspend,	.resume		= s3c2410_dma_resume,};/* kmem cache implementation */static void s3c2410_dma_cache_ctor(struct kmem_cache *c, void *p){	memset(p, 0, sizeof(struct s3c2410_dma_buf));}/* initialisation code */static int __init s3c24xx_dma_sysclass_init(void){	int ret = sysdev_class_register(&dma_sysclass);	if (ret != 0)		printk(KERN_ERR "dma sysclass registration failed\n");	return ret;}core_initcall(s3c24xx_dma_sysclass_init);static int __init s3c24xx_dma_sysdev_register(void){	struct s3c2410_dma_chan *cp = s3c2410_chans;	int channel, ret;	for (channel = 0; channel < dma_channels; cp++, channel++) {		cp->dev.cls = &dma_sysclass;		cp->dev.id  = channel;		ret = sysdev_register(&cp->dev);		if (ret) {			printk(KERN_ERR "error registering dev for dma %d\n",			       channel); 			return ret;		}	}	return 0;}late_initcall(s3c24xx_dma_sysdev_register);int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq,			    unsigned int stride){	struct s3c2410_dma_chan *cp;	int channel;	int ret;	printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");	dma_channels = channels;	dma_base = ioremap(S3C24XX_PA_DMA, stride * channels);	if (dma_base == NULL) {		printk(KERN_ERR "dma failed to remap register block\n");		return -ENOMEM;	}	dma_kmem = kmem_cache_create("dma_desc",				     sizeof(struct s3c2410_dma_buf), 0,				     SLAB_HWCACHE_ALIGN,				     s3c2410_dma_cache_ctor);	if (dma_kmem == NULL) {		printk(KERN_ERR "dma failed to make kmem cache\n");		ret = -ENOMEM;		goto err;	}	for (channel = 0; channel < channels;  channel++) {		cp = &s3c2410_chans[channel];		memset(cp, 0, sizeof(struct s3c2410_dma_chan));		/* dma channel irqs are in order.. */		cp->number = channel;		cp->irq    = channel + irq;		cp->regs   = dma_base + (channel * stride);		/* point current stats somewhere */		cp->stats  = &cp->stats_store;		cp->stats_store.timeout_shortest = LONG_MAX;		/* basic channel configuration */		cp->load_timeout = 1<<18;		printk("DMA channel %d at %p, irq %d\n",		       cp->number, cp->regs, cp->irq);	}	return 0; err:	kmem_cache_destroy(dma_kmem);	iounmap(dma_base);	dma_base = NULL;	return ret;}int __init s3c2410_dma_init(void){	return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);}static inline int is_channel_valid(unsigned int channel){	return (channel & DMA_CH_VALID);}static struct s3c24xx_dma_order *dma_order;/* s3c2410_dma_map_channel() * * turn the virtual channel number into a real, and un-used hardware * channel. * * first, try the dma ordering given to us by either the relevant * dma code, or the board. Then just find the first usable free * channel*/static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel){	struct s3c24xx_dma_order_ch *ord = NULL;	struct s3c24xx_dma_map *ch_map;	struct s3c2410_dma_chan *dmach;	int ch;	if (dma_sel.map == NULL || channel > dma_sel.map_size)		return NULL;	ch_map = dma_sel.map + channel;	/* first, try the board mapping */	if (dma_order) {		ord = &dma_order->channels[channel];		for (ch = 0; ch < dma_channels; ch++) {			if (!is_channel_valid(ord->list[ch]))				continue;			if (s3c2410_chans[ord->list[ch]].in_use == 0) {				ch = ord->list[ch] & ~DMA_CH_VALID;				goto found;			}		}		if (ord->flags & DMA_CH_NEVER)			return NULL;	}	/* second, search the channel map for first free */	for (ch = 0; ch < dma_channels; ch++) {		if (!is_channel_valid(ch_map->channels[ch]))			continue;		if (s3c2410_chans[ch].in_use == 0) {			printk("mapped channel %d to %d\n", channel, ch);			break;		}	}	if (ch >= dma_channels)		return NULL;	/* update our channel mapping */ found:	dmach = &s3c2410_chans[ch];	dma_chan_map[channel] = dmach;	/* select the channel */	(dma_sel.select)(dmach, ch_map);	return dmach;}static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch){	return 0;}int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel){	struct s3c24xx_dma_map *nmap;	size_t map_sz = sizeof(*nmap) * sel->map_size;	int ptr;	nmap = kmalloc(map_sz, GFP_KERNEL);	if (nmap == NULL)		return -ENOMEM;	memcpy(nmap, sel->map, map_sz);	memcpy(&dma_sel, sel, sizeof(*sel));	dma_sel.map = nmap;	for (ptr = 0; ptr < sel->map_size; ptr++)		s3c24xx_dma_check_entry(nmap+ptr, ptr);	return 0;}int __init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord){	struct s3c24xx_dma_order *nord = dma_order;	if (nord == NULL)		nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL);	if (nord == NULL) {		printk(KERN_ERR "no memory to store dma channel order\n");		return -ENOMEM;	}	dma_order = nord;	memcpy(nord, ord, sizeof(struct s3c24xx_dma_order));	return 0;}

⌨️ 快捷键说明

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