DMA(一) - 内核sysdev DMA控制器设备
来源:互联网 发布:sql 别名 后续能否使用 编辑:程序博客网 时间:2024/06/06 03:23
概念
区别两个概念:DMA和DMA控制器
dma_alloc_coherent/dma_map_single/dma_pool_create
以上这3个函数只是将内核虚拟地址映射得到物理地址
对于物理地址的使用则涉及到DMA控制器的操作了,需要将物理地址填写到DMA控制器的对应寄存器,并启动DMA控制器进行传输。内核对DMA控制器的操作也提供了一些函数。
大部分情况下,外设都有自己独立的DMA控制器,如dwc_otg中usb使用的是usb相关的DMA控制器;而有的soc有公共的DMA控制器,如s3c2440,不同的外设使用公共的DMA控制器。
内核sysdev DMA控制器设备
sysdev_class_register, sysdev_register, sysdev_driver_register函数位于drivers/base/sys.c文件。
/* arch/arm/plat-s3c24xx/s3c244x.c */struct sysdev_class s3c2440_sysclass = { .name = "s3c2440-core", .suspend = s3c244x_suspend, .resume = s3c244x_resume};sysdev_class_register(&s3c2440_sysclass);/* arch/arm/mach-s3c2440/s3c2440.c */static struct sys_device s3c2440_sysdev = { .cls = &s3c2440_sysclass,};sysdev_register(&s3c2440_sysdev);/* arch/arm/mach-s3c2440/dma.c */static struct sysdev_driver s3c2440_dma_driver = { .add = s3c2440_dma_add,};sysdev_driver_register(&s3c2440_sysclass, &s3c2440_dma_driver);
系统设备与驱动模型有一点不同,他们不需要动态的驱动绑定,也不能被探测,并且不属于任何类型的外围总线。对系统设备我们仍然有驱动的概念,因为我们仍想执行在这些设备上执行基本的操作。
s3c2440_dma_driver注册到s3c2440_sysclass中的driver链表后,在s3c2440_sysclass的device链表中发现了s3c2440_sysdev,匹配,于是便执行s3c2440_dma_driver中的add函数s3c2440_dma_add.
/* arch/arm/plat-s3c24xx/dma.c */static int __init s3c2440_dma_add(struct sys_device *sysdev){ s3c2410_dma_init(); s3c24xx_dma_order_set(&s3c2440_dma_order); return s3c24xx_dma_init_map(&s3c2440_dma_sel);}
接着调用
/* arch/arm/mach-s3c2440/dma.c */int __init s3c2410_dma_init(void){ return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);}
在s3c24xx_dma_init中初始化了DMA控制器的4个channel到数组s3c2410_chans[]
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)); cp->number = channel; cp->irq = channel + irq;/* dma channel irqs are in order.. */ cp->regs = dma_base + (channel * stride); cp->stats = &cp->stats_store;/* point current stats somewhere */ cp->stats_store.timeout_shortest = LONG_MAX; cp->load_timeout = 1<<18;/* basic channel configuration */ 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;}
之后会将DMA channel中的dev注册到dma class中
struct sysdev_class dma_sysclass = { .name = "s3c24xx-dma", .suspend = s3c2410_dma_suspend, .resume = s3c2410_dma_resume,};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);
0 0
- DMA(一) - 内核sysdev DMA控制器设备
- DMA控制器
- DMA控制器
- DMA控制器
- DMA控制器
- DMA控制器
- msp430之DMA控制器
- DMA控制器的学习
- 基本的DMA控制器
- DMA控制器硬件结构
- DMA控制器的引入
- DMA
- DMA
- DMA
- DMA
- DMA
- DMA
- DMA
- 回溯法之Additive equations
- Linux设备驱动--字符设备驱动程序1
- 6. --SQLite 专属的修改
- testLink的使用
- iomanip头文件
- DMA(一) - 内核sysdev DMA控制器设备
- iperf命令备注
- PAT1002 写出这个数
- JavaScript 控制元素隐藏显示
- android进程间通讯方式
- 1181:变形课
- hdu 5477__A Sweet Journey
- 经典图书清单
- iOS讲解迷惑深入浅出之复杂对象的归档