首先介绍一下DMA,S3C2440A支持位于系统总线和外围总线之间的4通道DMA控制器,每个通道都可以在系统总线或外围总线上的设备之间传输数据。每个通道可以对下面4种情况进行传输:
1.源和目的都在系统总线上
2.源在系统总线而目的在外围总线
3.源在外围总线而目的在系统总线
4.源和目的都在外围总线
下图是请求源为硬件模式时的每个通道的请求源:
DMA使用3个状态的有限状态机:
1.初始状态,DMA等待DMA请求,一旦请求到达DMA进入状态2,DMA ACK与INT REQ为0。
2.在这个状态,DMA ACK置为1并且计数器CURR_TC的值被从DCON[19:0]载入,注意DMA ACK保持为1直到它被清除。
3.在这个状态,处理DMA原子操作的子状态机被初始化。子状态机从源地址读取数据,然后写入目的地址。在这个操作中,要考虑数据的大小和传输的大小(单个/突发),这个操作重复执行直到计数器(CURR_TC)变成0在全服务模式,而只执行一次在单服务模式。当子状态机结束每一次原子操作的时候主状态机减少CURR_TC的值。另外,主状态机发出INT REQ信号当CURR_TC变成0并且DCON[29]位被置位1时。并且,清除DMA ACK,如果下面两个条件之一满足的话:
1)在全服务模式下CURR_TC变成0
2)在单服务模式下结束原子操作
注意在单服务模式下,主有限状态机的3个状态被执行然后停止,等待另一个DMA REQ。如果DMA REQ到来,所有的3个状态被重复执行。所以在每次原子操作中DMA ACK被置位,然后又被清除。与之对比,在全服务模式,主有限状态机等在状态3直到CURR_TC变成0。所以,DMA ACK在传输期间被置位,到TC为0时被清除。
然而,不管哪个服务模式,INT REQ被发出只有当CURR_TC变成0时。
如下图,是基本的DMA时序:
nXDREQ生效后等待至少2个时钟周期,nXDACK响应并开始生效,但要知道延时至少3个时钟周期,DMA控制器才可获得总线的控制权,进行读写操作一次。
下面来分析内核DMA驱动源码:
首先来看一下DMA驱动是怎样注册的:
这里使用了系统设备的概念,通过内核中源码的注释我们看看什么是系统设备。系统设备与驱动模型有一点不同,他们不需要动态的驱动绑定,也不能被探测,并且不属于任何类型的外围总线。对系统设备我们仍然有驱动的概念,因为我们仍想执行在这些设备上执行基本的操作。
在arch/arm/plat-s3c24xx/s3c244x.c中,注册了系统设备的类:
[c-sharp] view plain copy print ?
- struct sysdev_class s3c2440_sysclass = {
- .name = "s3c2440-core",
- .suspend = s3c244x_suspend,
- .resume = s3c244x_resume
- };
- static int __init s3c2440_core_init(void)
- {
- return sysdev_class_register(&s3c2440_sysclass);
- }
[c-sharp] view plain copy print ?
- struct sysdev_class s3c2440_sysclass = {
- .name = "s3c2440-core",
- .suspend = s3c244x_suspend,
- .resume = s3c244x_resume
- };
- static int __init s3c2440_core_init(void)
- {
- return sysdev_class_register(&s3c2440_sysclass);
- }
在arch/arm/mach-s3c2410/dma.c中,注册了dma的驱动:
[c-sharp] view plain copy print ?
- #if defined(CONFIG_CPU_S3C2410)
- static struct sysdev_driver s3c2410_dma_driver = {
- .add = s3c2410_dma_add,
- };
[c-sharp] view plain copy print ?
- #if defined(CONFIG_CPU_S3C2410)
- static struct sysdev_driver s3c2410_dma_driver = {
- .add = s3c2410_dma_add,
- };
把dma驱动注册到设备类下:
[c-sharp] view plain copy print ?
- static int __init s3c2410_dma_drvinit(void)
- {
- return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver);
- }
[c-sharp] view plain copy print ?
- static int __init s3c2410_dma_drvinit(void)
- {
- return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver);
- }
先来看一下系统设备类:
[c-sharp] view plain copy print ?
- struct sysdev_class {
- const char *name;
- struct list_head drivers;
-
-
- int (*shutdown)(struct sys_device *);
- int (*suspend)(struct sys_device *, pm_message_t state);
- int (*resume)(struct sys_device *);
- struct kset kset;
- };
[c-sharp] view plain copy print ?
- struct sysdev_class {
- const char *name;
- struct list_head drivers;
-
-
- int (*shutdown)(struct sys_device *);
- int (*suspend)(struct sys_device *, pm_message_t state);
- int (*resume)(struct sys_device *);
- struct kset kset;
- };
这个结构体有一个drivers双向循环链表,注册到这个类的驱动都挂在这里。
下面分析一下dma驱动是怎样注册的:
[c-sharp] view plain copy print ?
- int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
- {
- 。。。。。。。。。。。
- if (cls && kset_get(&cls->kset)) {
-
- list_add_tail(&drv->entry, &cls->drivers);
-
-
- if (drv->add) {
- struct sys_device *dev;
- list_for_each_entry(dev, &cls->kset.list, kobj.entry)
- drv->add(dev);
- }
- } else {
- err = -EINVAL;
- WARN(1, KERN_ERR "%s: invalid device class/n", __func__);
- }
- mutex_unlock(&sysdev_drivers_lock);
- return err;
- }
[c-sharp] view plain copy print ?
- int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
- {
- 。。。。。。。。。。。
- if (cls && kset_get(&cls->kset)) {
-
- list_add_tail(&drv->entry, &cls->drivers);
-
-
- if (drv->add) {
- struct sys_device *dev;
- list_for_each_entry(dev, &cls->kset.list, kobj.entry)
- drv->add(dev);
- }
- } else {
- err = -EINVAL;
- WARN(1, KERN_ERR "%s: invalid device class/n", __func__);
- }
- mutex_unlock(&sysdev_drivers_lock);
- return err;
- }
在arch/arm/mach-s3c2440/s3c2440.c中,注册了一个系统设备s3c2440_sysdev,
[c-sharp] view plain copy print ?
- static struct sys_device s3c2440_sysdev = {
- .cls = &s3c2440_sysclass,
- };
- int __init s3c2440_init(void)
- {
- 。。。。。。。。
- return sysdev_register(&s3c2440_sysdev);
- }
[c-sharp] view plain copy print ?
- static struct sys_device s3c2440_sysdev = {
- .cls = &s3c2440_sysclass,
- };
- int __init s3c2440_init(void)
- {
- 。。。。。。。。
- return sysdev_register(&s3c2440_sysdev);
- }
注意系统设备这个结构体,里边封装了一个系统设备类。
[c-sharp] view plain copy print ?
- struct sys_device {
- u32 id;
- struct sysdev_class * cls;
- struct kobject kobj;
- };
[c-sharp] view plain copy print ?
- struct sys_device {
- u32 id;
- struct sysdev_class * cls;
- struct kobject kobj;
- };
下面来看一下系统设备的注册,系统设备是一个虚拟设备,这里的目的就是为了调用driver的add函数。
[c-sharp] view plain copy print ?
- int sysdev_register(struct sys_device *sysdev){
- 。。。。。。。。。。。。
-
- list_for_each_entry(drv, &cls->drivers, entry) {
-
- if (drv->add)
- drv->add(sysdev);
- }
- 。。。。。。。。。。。。。
- }
[c-sharp] view plain copy print ?
- int sysdev_register(struct sys_device *sysdev){
- 。。。。。。。。。。。。
-
- list_for_each_entry(drv, &cls->drivers, entry) {
-
- if (drv->add)
- drv->add(sysdev);
- }
- 。。。。。。。。。。。。。
- }
下面来分析一下这个add函数。看上边的那个dma驱动的结构体,指明了add函数为s3c2410_dma_add:
[c-sharp] view plain copy print ?
- static int __init s3c2410_dma_add(struct sys_device *sysdev)
- {
- s3c2410_dma_init(); (一)
- s3c24xx_dma_order_set(&s3c2410_dma_order); (二)
- return s3c24xx_dma_init_map(&s3c2410_dma_sel); (三)
- }
[c-sharp] view plain copy print ?
- static int __init s3c2410_dma_add(struct sys_device *sysdev)
- {
- s3c2410_dma_init(); (一)
- s3c24xx_dma_order_set(&s3c2410_dma_order); (二)
- return s3c24xx_dma_init_map(&s3c2410_dma_sel); (三)
- }
分别对s3c2410_dma_add中的3个函数进行分析:
(一)
[c-sharp] view plain copy print ?
- int __init s3c2410_dma_init(void)
- {
-
- return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);
- }
[c-sharp] view plain copy print ?
- int __init s3c2410_dma_init(void)
- {
-
- return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);
- }
[c-sharp] view plain copy print ?
- 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;
- cp->regs = dma_base + (channel * stride);
-
-
- cp->stats = &cp->stats_store;
- cp->stats_store.timeout_shortest = LONG_MAX;
-
-
-
- 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;
- }
[c-sharp] view plain copy print ?
- 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;
- cp->regs = dma_base + (channel * stride);
-
-
- cp->stats = &cp->stats_store;
- cp->stats_store.timeout_shortest = LONG_MAX;
-
-
-
- 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;
- }
这里使用到了一个s3c2410_dma_chan结构体,struct s3c2410_dma_chan记录dma通道信息,内容如下:
[c-sharp] view plain copy print ?
- 151 struct s3c2410_dma_chan {
- 152
- 153 unsigned char number;
- 154 unsigned char in_use;
- 155 unsigned char irq_claimed;
- 156 unsigned char irq_enabled;
- 157 unsigned char xfer_unit;
- 158
- 159
- 160
- 161 enum s3c2410_dma_state state;
- 162 enum s3c2410_dma_loadst load_state;
- 163 struct s3c2410_dma_client *client;
- 164
- 165
- 166 enum s3c2410_dmasrc source;
- 167 enum dma_ch req_ch;
- 168 unsigned long dev_addr;
- 169 unsigned long load_timeout;
- 170 unsigned int flags;
- 171
- 172 struct s3c24xx_dma_map *map;
- 173
- 174
- 175 void __iomem *regs;
- 176 void __iomem *addr_reg;
- 177 unsigned int irq; 中断号
- 178 unsigned long dcon; /默认控制寄存器的值
- 179
- 180
- 181 s3c2410_dma_cbfn_t callback_fn; 传输完成回调函数
- 182 s3c2410_dma_opfn_t op_fn; 操作完成回调函数*/
- 183
- 184
- 185 struct s3c2410_dma_stats *stats;
- 186 struct s3c2410_dma_stats stats_store;
- 187
- 188
- 189 struct s3c2410_dma_buf *curr;
- 190 struct s3c2410_dma_buf *next;
- 191 struct s3c2410_dma_buf *end; dma缓冲区链表
- 192
- 193
- 194 struct sys_device dev;
- 195 };
[c-sharp] view plain copy print ?
- 151 struct s3c2410_dma_chan {
- 152
- 153 unsigned char number;
- 154 unsigned char in_use;
- 155 unsigned char irq_claimed;
- 156 unsigned char irq_enabled;
- 157 unsigned char xfer_unit;
- 158
- 159
- 160
- 161 enum s3c2410_dma_state state;
- 162 enum s3c2410_dma_loadst load_state;
- 163 struct s3c2410_dma_client *client;
- 164
- 165
- 166 enum s3c2410_dmasrc source;
- 167 enum dma_ch req_ch;
- 168 unsigned long dev_addr;
- 169 unsigned long load_timeout;
- 170 unsigned int flags;
- 171
- 172 struct s3c24xx_dma_map *map;
- 173
- 174
- 175 void __iomem *regs;
- 176 void __iomem *addr_reg;
- 177 unsigned int irq; 中断号
- 178 unsigned long dcon; /默认控制寄存器的值
- 179
- 180
- 181 s3c2410_dma_cbfn_t callback_fn; 传输完成回调函数
- 182 s3c2410_dma_opfn_t op_fn; 操作完成回调函数*/
- 183
- 184
- 185 struct s3c2410_dma_stats *stats;
- 186 struct s3c2410_dma_stats stats_store;
- 187
- 188
- 189 struct s3c2410_dma_buf *curr;
- 190 struct s3c2410_dma_buf *next;
- 191 struct s3c2410_dma_buf *end; dma缓冲区链表
- 192
- 193
- 194 struct sys_device dev;
- 195 };
(二)
先看下边一个结构体,s3c2410_dma_order。这个是建立目标板dma源与硬件的dma通道的关联。
[c-sharp] view plain copy print ?
- static struct s3c24xx_dma_order __initdata s3c2410_dma_order = {
- .channels = {
- [DMACH_SDI] = {
- .list = {
- [0] = 3 | DMA_CH_VALID,
- [1] = 2 | DMA_CH_VALID,
- [2] = 0 | DMA_CH_VALID,
- },
- },
- [DMACH_I2S_IN] = {
- .list = {
- [0] = 1 | DMA_CH_VALID,
- [1] = 2 | DMA_CH_VALID,
- },
- },
- },
- };
[c-sharp] view plain copy print ?
- static struct s3c24xx_dma_order __initdata s3c2410_dma_order = {
- .channels = {
- [DMACH_SDI] = {
- .list = {
- [0] = 3 | DMA_CH_VALID,
- [1] = 2 | DMA_CH_VALID,
- [2] = 0 | DMA_CH_VALID,
- },
- },
- [DMACH_I2S_IN] = {
- .list = {
- [0] = 1 | DMA_CH_VALID,
- [1] = 2 | DMA_CH_VALID,
- },
- },
- },
- };
分析这里SDI可以是使用通道3,2,0,为什么从大到小排列,是因为某些dma请求只能使用dma0,dma1等较小的通道号,比如外部总线dma只能只用dma0,为了避免sdi占用,这里就采用的这种排列。
[c-sharp] view plain copy print ?
- [DMACH_SDI] = {
- .list = {
- [0] = 3 | DMA_CH_VALID,
- [1] = 2 | DMA_CH_VALID,
- [2] = 0 | DMA_CH_VALID,
- },
- },
[c-sharp] view plain copy print ?
- [DMACH_SDI] = {
- .list = {
- [0] = 3 | DMA_CH_VALID,
- [1] = 2 | DMA_CH_VALID,
- [2] = 0 | DMA_CH_VALID,
- },
- },
注意这个结构体是用__initdata修饰的,所以在初始化后会被释放掉。下边这个函数重新分配内存保存这个结构体就是这个原因。
[c-sharp] view plain copy print ?
- 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;
- }
[c-sharp] view plain copy print ?
- 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;
- }
(三)
[c-sharp] view plain copy print ?
- struct s3c24xx_dma_map {
- const char *name;
- struct s3c24xx_dma_addr hw_addr;
-
- unsigned long channels[S3C2410_DMA_CHANNELS];
- unsigned long channels_rx[S3C2410_DMA_CHANNELS];
- };
-
- struct s3c24xx_dma_selection {
- struct s3c24xx_dma_map *map;
- unsigned long map_size;
- unsigned long dcon_mask;
-
- void (*select)(struct s3c2410_dma_chan *chan,
- struct s3c24xx_dma_map *map);
-
- void (*direction)(struct s3c2410_dma_chan *chan,
- struct s3c24xx_dma_map *map,
- enum s3c2410_dmasrc dir);
- };
[c-sharp] view plain copy print ?
- struct s3c24xx_dma_map {
- const char *name;
- struct s3c24xx_dma_addr hw_addr;
-
- unsigned long channels[S3C2410_DMA_CHANNELS];
- unsigned long channels_rx[S3C2410_DMA_CHANNELS];
- };
-
- struct s3c24xx_dma_selection {
- struct s3c24xx_dma_map *map;
- unsigned long map_size;
- unsigned long dcon_mask;
-
- void (*select)(struct s3c2410_dma_chan *chan,
- struct s3c24xx_dma_map *map);
-
- void (*direction)(struct s3c2410_dma_chan *chan,
- struct s3c24xx_dma_map *map,
- enum s3c2410_dmasrc dir);
- };
建立芯片本身的dma源与硬件dma通道的视图。
[c-sharp] view plain copy print ?
- 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;
- }
- static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
- .select = s3c2410_dma_select,
- .dcon_mask = 7 << 24,
- .map = s3c2410_dma_mappings,
- .map_size = ARRAY_SIZE(s3c2410_dma_mappings),
- };
- static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
- struct s3c24xx_dma_map *map)
- {
- chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
- }
- static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
- [DMACH_XD0] = {
- .name = "xdreq0",
- .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
- },
- [DMACH_XD1] = {
- .name = "xdreq1",
- .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
- },
- [DMACH_SDI] = {
- .name = "sdi",
- .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
- .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
- .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
- .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
- },
- [DMACH_SPI0] = {
- .name = "spi0",
- .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
- .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
- },
- [DMACH_SPI1] = {
- .name = "spi1",
- .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
- .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
- },
- [DMACH_UART0] = {
- .name = "uart0",
- .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
- .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
- },
- [DMACH_UART1] = {
- .name = "uart1",
- .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
- .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
- },
- [DMACH_UART2] = {
- .name = "uart2",
- .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
- .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
- },
- [DMACH_TIMER] = {
- .name = "timer",
- .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
- .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
- .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
- },
- [DMACH_I2S_IN] = {
- .name = "i2s-sdi",
- .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
- .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
- .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
- },
- [DMACH_I2S_OUT] = {
- .name = "i2s-sdo",
- .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
- },
- [DMACH_USB_EP1] = {
- .name = "usb-ep1",
- .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
- },
- [DMACH_USB_EP2] = {
- .name = "usb-ep2",
- .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
- },
- [DMACH_USB_EP3] = {
- .name = "usb-ep3",
- .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
- },
- [DMACH_USB_EP4] = {
- .name = "usb-ep4",
- .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
- },
- };
DMA通道的使用:申请通道,申请中断,设置寄存器,安装回调函数,设置标志,将数据放入队列,最后就是调用static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)来开始DMA的传输了。
首先看通道的申请:
[c-sharp] view plain copy print ?
- 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, __func__, 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);
-
-
-
- pr_debug("%s: channel initialised, %p/n", __func__, chan);
-
- return chan->number | DMACH_LOW_LEVEL;
- }
[c-sharp] view plain copy print ?
- 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, __func__, 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);
-
-
-
- pr_debug("%s: channel initialised, %p/n", __func__, chan);
-
- return chan->number | DMACH_LOW_LEVEL;
- }
下面的函数是找通道好,先在板子通道映射中找,再在芯片通道映射中找。
[c-sharp] view plain copy print ?
- 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;
-
-
-
- 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;
- }
-
- 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;
-
-
- found:
-
- dmach = &s3c2410_chans[ch];
- dmach->map = ch_map;
- dma_chan_map[channel] = dmach;
-
-
-
- (dma_sel.select)(dmach, ch_map);
-
- return dmach;
- }
[c-sharp] view plain copy print ?
- 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;
-
-
-
- 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;
- }
-
- 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;
-
-
- found:
-
- dmach = &s3c2410_chans[ch];
- dmach->map = ch_map;
- dma_chan_map[channel] = dmach;
-
-
-
- (dma_sel.select)(dmach, ch_map);
-
- return dmach;
- }
设置寄存器,设置寄存器的工作由s3c2410_dma_devconfig和s3c2410_dma_config完成:
[c-sharp] view plain copy print ?
- 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",
- __func__, (int)source, hwcfg, devaddr);
-
- chan->source = source;
- chan->dev_addr = devaddr;
- chan->hw_cfg = hwcfg;
-
- switch (source) {
- case S3C2410_DMASRC_HW:
-
- pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d/n",
- __func__, 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);
- break;
-
- case S3C2410_DMASRC_MEM:
-
- pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d/n",
- __func__, 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);
- break;
-
- default:
- printk(KERN_ERR "dma%d: invalid source type (%d)/n",
- channel, source);
-
- return -EINVAL;
- }
-
- if (dma_sel.direction != NULL)
- (dma_sel.direction)(chan, chan->map, source);
-
- return 0;
- }
[c-sharp] view plain copy print ?
- 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",
- __func__, (int)source, hwcfg, devaddr);
-
- chan->source = source;
- chan->dev_addr = devaddr;
- chan->hw_cfg = hwcfg;
-
- switch (source) {
- case S3C2410_DMASRC_HW:
-
- pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d/n",
- __func__, 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);
- break;
-
- case S3C2410_DMASRC_MEM:
-
- pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d/n",
- __func__, 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);
- break;
-
- default:
- printk(KERN_ERR "dma%d: invalid source type (%d)/n",
- channel, source);
-
- return -EINVAL;
- }
-
- if (dma_sel.direction != NULL)
- (dma_sel.direction)(chan, chan->map, source);
-
- return 0;
- }
[c-sharp] view plain copy print ?
- int s3c2410_dma_config(unsigned int 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",
- __func__, channel, xferunit, dcon);
-
- if (chan == NULL)
- return -EINVAL;
-
- pr_debug("%s: Initial dcon is %08x/n", __func__, dcon);
-
- dcon |= chan->dcon & dma_sel.dcon_mask;
-
- pr_debug("%s: New dcon is %08x/n", __func__, 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", __func__, xferunit);
- return -EINVAL;
- }
-
- dcon |= S3C2410_DCON_HWTRIG;
- dcon |= S3C2410_DCON_INTREQ;
-
- pr_debug("%s: dcon now %08x/n", __func__, dcon);
-
- chan->dcon = dcon;
- chan->xfer_unit = xferunit;
-
- return 0;
- }
[c-sharp] view plain copy print ?
- int s3c2410_dma_config(unsigned int 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",
- __func__, channel, xferunit, dcon);
-
- if (chan == NULL)
- return -EINVAL;
-
- pr_debug("%s: Initial dcon is %08x/n", __func__, dcon);
-
- dcon |= chan->dcon & dma_sel.dcon_mask;
-
- pr_debug("%s: New dcon is %08x/n", __func__, 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", __func__, xferunit);
- return -EINVAL;
- }
-
- dcon |= S3C2410_DCON_HWTRIG;
- dcon |= S3C2410_DCON_INTREQ;
-
- pr_debug("%s: dcon now %08x/n", __func__, dcon);
-
- chan->dcon = dcon;
- chan->xfer_unit = xferunit;
-
- return 0;
- }
设置回调函数:
[c-sharp] view plain copy print ?
- int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
- {
- 。。。。。。。
- chan->callback_fn = rtn;
-
- return 0;
- }
[c-sharp] view plain copy print ?
- int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
- {
- 。。。。。。。
- chan->callback_fn = rtn;
-
- return 0;
- }
设置标志:
[c-sharp] view plain copy print ?
- int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
- {
- 。。。。。。。。。。。。。。
- chan->flags = flags;
-
- return 0;
- }
[c-sharp] view plain copy print ?
- int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
- {
- 。。。。。。。。。。。。。。
- chan->flags = flags;
-
- return 0;
- }
将数据放入队列,先看一下一个结构:
[c-sharp] view plain copy print ?
- struct s3c2410_dma_buf {
- struct s3c2410_dma_buf *next;
- int magic;
- int size;
- dma_addr_t data;
- dma_addr_t ptr;
- void *id;
- };
[c-sharp] view plain copy print ?
- struct s3c2410_dma_buf {
- struct s3c2410_dma_buf *next;
- int magic;
- int size;
- dma_addr_t data;
- dma_addr_t ptr;
- void *id;
- };
每个struct s3c2410_dma_chan维护了一个缓冲区队列,每个缓冲区用上边的结构表示。在struct s3c2410_dma_chan中的结构是:
[c-sharp] view plain copy print ?
-
- struct s3c2410_dma_buf *curr;
- struct s3c2410_dma_buf *next;
- struct s3c2410_dma_buf *end;
[c-sharp] view plain copy print ?
-
- struct s3c2410_dma_buf *curr;
- struct s3c2410_dma_buf *next;
- struct s3c2410_dma_buf *end;
下边这个函数就是完成将s3c2410_dma_buf放入这个队列中排队:
[c-sharp] view plain copy print ?
- int s3c2410_dma_enqueue(unsigned int channel, void *id,
- dma_addr_t data, int size)
- {
-
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
- struct s3c2410_dma_buf *buf;
- unsigned long flags;
-
- if (chan == NULL)
- return -EINVAL;
-
- pr_debug("%s: id=%p, data=%08x, size=%d/n",
- __func__, id, (unsigned int)data, size);
-
- buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
- if (buf == NULL) {
- pr_debug("%s: out of memory (%ld alloc)/n",
- __func__, (long)sizeof(*buf));
- return -ENOMEM;
- }
-
-
-
-
- buf->next = NULL;
- buf->data = buf->ptr = data;
- buf->size = size;
- buf->id = id;
- buf->magic = BUF_MAGIC;
-
- local_irq_save(flags);
-
- if (chan->curr == NULL) {
-
- pr_debug("%s: buffer %p queued onto empty channel/n",
- __func__, buf);
-
- chan->curr = buf;
- chan->end = buf;
- chan->next = NULL;
- } else {
- pr_debug("dma%d: %s: buffer %p queued onto non-empty channel/n",
- chan->number, __func__, buf);
-
- if (chan->end == NULL)
- pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?/n",
- chan->number, __func__, chan);
-
- chan->end->next = buf;
- chan->end = buf;
- }
-
-
- if (chan->next == NULL)
- chan->next = buf;
-
- 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 | DMACH_LOW_LEVEL,
- S3C2410_DMAOP_START);
- }
- }
-
- local_irq_restore(flags);
- return 0;
- }
[c-sharp] view plain copy print ?
- int s3c2410_dma_enqueue(unsigned int channel, void *id,
- dma_addr_t data, int size)
- {
-
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
- struct s3c2410_dma_buf *buf;
- unsigned long flags;
-
- if (chan == NULL)
- return -EINVAL;
-
- pr_debug("%s: id=%p, data=%08x, size=%d/n",
- __func__, id, (unsigned int)data, size);
-
- buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
- if (buf == NULL) {
- pr_debug("%s: out of memory (%ld alloc)/n",
- __func__, (long)sizeof(*buf));
- return -ENOMEM;
- }
-
-
-
-
- buf->next = NULL;
- buf->data = buf->ptr = data;
- buf->size = size;
- buf->id = id;
- buf->magic = BUF_MAGIC;
-
- local_irq_save(flags);
-
- if (chan->curr == NULL) {
-
- pr_debug("%s: buffer %p queued onto empty channel/n",
- __func__, buf);
-
- chan->curr = buf;
- chan->end = buf;
- chan->next = NULL;
- } else {
- pr_debug("dma%d: %s: buffer %p queued onto non-empty channel/n",
- chan->number, __func__, buf);
-
- if (chan->end == NULL)
- pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?/n",
- chan->number, __func__, chan);
-
- chan->end->next = buf;
- chan->end = buf;
- }
-
-
- if (chan->next == NULL)
- chan->next = buf;
-
- 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 | DMACH_LOW_LEVEL,
- S3C2410_DMAOP_START);
- }
- }
-
- local_irq_restore(flags);
- return 0;
- }
channel在运行的时候会有很多状态,在arch/arm/mach-s3c2410/include/mach/dma.h,注意已经很清楚了,我就不多解释了。
[c-sharp] view plain copy print ?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- enum s3c2410_dma_loadst {
- S3C2410_DMALOAD_NONE,
- S3C2410_DMALOAD_1LOADED,
- S3C2410_DMALOAD_1RUNNING,
- S3C2410_DMALOAD_1LOADED_1RUNNING,
- };
[c-sharp] view plain copy print ?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- enum s3c2410_dma_loadst {
- S3C2410_DMALOAD_NONE,
- S3C2410_DMALOAD_1LOADED,
- S3C2410_DMALOAD_1RUNNING,
- S3C2410_DMALOAD_1LOADED_1RUNNING,
- };
中断处理函数:
[c-sharp] view plain copy print ?
- static irqreturn_t
- s3c2410_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);
-
-
-
- switch (chan->load_state) {
- case S3C2410_DMALOAD_1RUNNING:
-
-
-
-
- chan->load_state = S3C2410_DMALOAD_NONE;
- break;
-
- case S3C2410_DMALOAD_1LOADED:
-
-
-
-
-
- chan->load_state = S3C2410_DMALOAD_NONE;
- break;
-
- case S3C2410_DMALOAD_1LOADED_1RUNNING:
-
-
-
-
-
-
- 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) {
-
-
-
-
- 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, __func__, buf);
- return IRQ_HANDLED;
- }
-
- s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
-
-
- s3c2410_dma_freebuf(buf);
- } else {
- }
-
-
-
-
-
-
-
-
- if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
- unsigned long flags;
-
- switch (chan->load_state) {
- case S3C2410_DMALOAD_1RUNNING:
-
- break;
-
- case S3C2410_DMALOAD_NONE:
-
- break;
-
- case S3C2410_DMALOAD_1LOADED:
- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-
- printk(KERN_ERR "dma%d: timeout waiting for load (%s)/n",
- chan->number, __func__);
- 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);
-
-
- 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;
- }
[c-sharp] view plain copy print ?
- static irqreturn_t
- s3c2410_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);
-
-
-
- switch (chan->load_state) {
- case S3C2410_DMALOAD_1RUNNING:
-
-
-
-
- chan->load_state = S3C2410_DMALOAD_NONE;
- break;
-
- case S3C2410_DMALOAD_1LOADED:
-
-
-
-
-
- chan->load_state = S3C2410_DMALOAD_NONE;
- break;
-
- case S3C2410_DMALOAD_1LOADED_1RUNNING:
-
-
-
-
-
-
- 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) {
-
-
-
-
- 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, __func__, buf);
- return IRQ_HANDLED;
- }
-
- s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
-
-
- s3c2410_dma_freebuf(buf);
- } else {
- }
-
-
-
-
-
-
-
-
- if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
- unsigned long flags;
-
- switch (chan->load_state) {
- case S3C2410_DMALOAD_1RUNNING:
-
- break;
-
- case S3C2410_DMALOAD_NONE:
-
- break;
-
- case S3C2410_DMALOAD_1LOADED:
- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-
- printk(KERN_ERR "dma%d: timeout waiting for load (%s)/n",
- chan->number, __func__);
- 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);
-
-
- 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;
- }
可以选择不同的dma操作:
[c-sharp] view plain copy print ?
- int
- s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
- {
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
- 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;
- }