diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-01-16 22:14:09 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-16 23:15:27 -0800 |
commit | 0d831770b154a057562236e8cf50905c8f1ae1b0 (patch) | |
tree | dc25902b29b09838f2fe32e47be53c951a2fa67e /arch/sh/drivers/dma/dma-api.c | |
parent | 0025835cf20e07056b8521b8c1d7d0bfe07e81f1 (diff) | |
download | op-kernel-dev-0d831770b154a057562236e8cf50905c8f1ae1b0.zip op-kernel-dev-0d831770b154a057562236e8cf50905c8f1ae1b0.tar.gz |
[PATCH] sh: DMA updates
This extends the current SH DMA API somewhat to support a proper virtual
channel abstraction, and also works to represent this through the driver model
by giving each DMAC its own platform device.
There's also a few other minor changes to support a few new CPU subtypes, and
make TEI generation for the SH DMAC configurable.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/sh/drivers/dma/dma-api.c')
-rw-r--r-- | arch/sh/drivers/dma/dma-api.c | 51 |
1 files changed, 37 insertions, 14 deletions
diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c index 96e3036..47c3e83 100644 --- a/arch/sh/drivers/dma/dma-api.c +++ b/arch/sh/drivers/dma/dma-api.c @@ -3,7 +3,7 @@ * * SuperH-specific DMA management API * - * Copyright (C) 2003, 2004 Paul Mundt + * Copyright (C) 2003, 2004, 2005 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -15,6 +15,7 @@ #include <linux/spinlock.h> #include <linux/proc_fs.h> #include <linux/list.h> +#include <linux/platform_device.h> #include <asm/dma.h> DEFINE_SPINLOCK(dma_spin_lock); @@ -55,16 +56,14 @@ static LIST_HEAD(registered_dmac_list); struct dma_info *get_dma_info(unsigned int chan) { - struct list_head *pos, *tmp; + struct dma_info *info; unsigned int total = 0; /* * Look for each DMAC's range to determine who the owner of * the channel is. */ - list_for_each_safe(pos, tmp, ®istered_dmac_list) { - struct dma_info *info = list_entry(pos, struct dma_info, list); - + list_for_each_entry(info, ®istered_dmac_list, list) { total += info->nr_channels; if (chan > total) continue; @@ -75,6 +74,20 @@ struct dma_info *get_dma_info(unsigned int chan) return NULL; } +static unsigned int get_nr_channels(void) +{ + struct dma_info *info; + unsigned int nr = 0; + + if (unlikely(list_empty(®istered_dmac_list))) + return nr; + + list_for_each_entry(info, ®istered_dmac_list, list) + nr += info->nr_channels; + + return nr; +} + struct dma_channel *get_dma_channel(unsigned int chan) { struct dma_info *info = get_dma_info(chan); @@ -173,7 +186,7 @@ int dma_xfer(unsigned int chan, unsigned long from, static int dma_read_proc(char *buf, char **start, off_t off, int len, int *eof, void *data) { - struct list_head *pos, *tmp; + struct dma_info *info; char *p = buf; if (list_empty(®istered_dmac_list)) @@ -182,8 +195,7 @@ static int dma_read_proc(char *buf, char **start, off_t off, /* * Iterate over each registered DMAC */ - list_for_each_safe(pos, tmp, ®istered_dmac_list) { - struct dma_info *info = list_entry(pos, struct dma_info, list); + list_for_each_entry(info, ®istered_dmac_list, list) { int i; /* @@ -205,9 +217,9 @@ static int dma_read_proc(char *buf, char **start, off_t off, #endif -int __init register_dmac(struct dma_info *info) +int register_dmac(struct dma_info *info) { - int i; + unsigned int total_channels, i; INIT_LIST_HEAD(&info->list); @@ -217,6 +229,11 @@ int __init register_dmac(struct dma_info *info) BUG_ON((info->flags & DMAC_CHANNELS_CONFIGURED) && !info->channels); + info->pdev = platform_device_register_simple((char *)info->name, -1, + NULL, 0); + if (IS_ERR(info->pdev)) + return PTR_ERR(info->pdev); + /* * Don't touch pre-configured channels */ @@ -232,10 +249,12 @@ int __init register_dmac(struct dma_info *info) memset(info->channels, 0, size); } + total_channels = get_nr_channels(); for (i = 0; i < info->nr_channels; i++) { struct dma_channel *chan = info->channels + i; chan->chan = i; + chan->vchan = i + total_channels; memcpy(chan->dev_id, "Unused", 7); @@ -245,9 +264,7 @@ int __init register_dmac(struct dma_info *info) init_MUTEX(&chan->sem); init_waitqueue_head(&chan->wait_queue); -#ifdef CONFIG_SYSFS - dma_create_sysfs_files(chan); -#endif + dma_create_sysfs_files(chan, info); } list_add(&info->list, ®istered_dmac_list); @@ -255,12 +272,18 @@ int __init register_dmac(struct dma_info *info) return 0; } -void __exit unregister_dmac(struct dma_info *info) +void unregister_dmac(struct dma_info *info) { + unsigned int i; + + for (i = 0; i < info->nr_channels; i++) + dma_remove_sysfs_files(info->channels + i, info); + if (!(info->flags & DMAC_CHANNELS_CONFIGURED)) kfree(info->channels); list_del(&info->list); + platform_device_unregister(info->pdev); } static int __init dma_api_init(void) |