diff options
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 96e3036ec2bb..47c3e837599b 100644 --- a/arch/sh/drivers/dma/dma-api.c +++ b/arch/sh/drivers/dma/dma-api.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SuperH-specific DMA management API | 4 | * SuperH-specific DMA management API |
5 | * | 5 | * |
6 | * Copyright (C) 2003, 2004 Paul Mundt | 6 | * Copyright (C) 2003, 2004, 2005 Paul Mundt |
7 | * | 7 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | 8 | * This file is subject to the terms and conditions of the GNU General Public |
9 | * License. See the file "COPYING" in the main directory of this archive | 9 | * License. See the file "COPYING" in the main directory of this archive |
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
16 | #include <linux/proc_fs.h> | 16 | #include <linux/proc_fs.h> |
17 | #include <linux/list.h> | 17 | #include <linux/list.h> |
18 | #include <linux/platform_device.h> | ||
18 | #include <asm/dma.h> | 19 | #include <asm/dma.h> |
19 | 20 | ||
20 | DEFINE_SPINLOCK(dma_spin_lock); | 21 | DEFINE_SPINLOCK(dma_spin_lock); |
@@ -55,16 +56,14 @@ static LIST_HEAD(registered_dmac_list); | |||
55 | 56 | ||
56 | struct dma_info *get_dma_info(unsigned int chan) | 57 | struct dma_info *get_dma_info(unsigned int chan) |
57 | { | 58 | { |
58 | struct list_head *pos, *tmp; | 59 | struct dma_info *info; |
59 | unsigned int total = 0; | 60 | unsigned int total = 0; |
60 | 61 | ||
61 | /* | 62 | /* |
62 | * Look for each DMAC's range to determine who the owner of | 63 | * Look for each DMAC's range to determine who the owner of |
63 | * the channel is. | 64 | * the channel is. |
64 | */ | 65 | */ |
65 | list_for_each_safe(pos, tmp, ®istered_dmac_list) { | 66 | list_for_each_entry(info, ®istered_dmac_list, list) { |
66 | struct dma_info *info = list_entry(pos, struct dma_info, list); | ||
67 | |||
68 | total += info->nr_channels; | 67 | total += info->nr_channels; |
69 | if (chan > total) | 68 | if (chan > total) |
70 | continue; | 69 | continue; |
@@ -75,6 +74,20 @@ struct dma_info *get_dma_info(unsigned int chan) | |||
75 | return NULL; | 74 | return NULL; |
76 | } | 75 | } |
77 | 76 | ||
77 | static unsigned int get_nr_channels(void) | ||
78 | { | ||
79 | struct dma_info *info; | ||
80 | unsigned int nr = 0; | ||
81 | |||
82 | if (unlikely(list_empty(®istered_dmac_list))) | ||
83 | return nr; | ||
84 | |||
85 | list_for_each_entry(info, ®istered_dmac_list, list) | ||
86 | nr += info->nr_channels; | ||
87 | |||
88 | return nr; | ||
89 | } | ||
90 | |||
78 | struct dma_channel *get_dma_channel(unsigned int chan) | 91 | struct dma_channel *get_dma_channel(unsigned int chan) |
79 | { | 92 | { |
80 | struct dma_info *info = get_dma_info(chan); | 93 | struct dma_info *info = get_dma_info(chan); |
@@ -173,7 +186,7 @@ int dma_xfer(unsigned int chan, unsigned long from, | |||
173 | static int dma_read_proc(char *buf, char **start, off_t off, | 186 | static int dma_read_proc(char *buf, char **start, off_t off, |
174 | int len, int *eof, void *data) | 187 | int len, int *eof, void *data) |
175 | { | 188 | { |
176 | struct list_head *pos, *tmp; | 189 | struct dma_info *info; |
177 | char *p = buf; | 190 | char *p = buf; |
178 | 191 | ||
179 | if (list_empty(®istered_dmac_list)) | 192 | if (list_empty(®istered_dmac_list)) |
@@ -182,8 +195,7 @@ static int dma_read_proc(char *buf, char **start, off_t off, | |||
182 | /* | 195 | /* |
183 | * Iterate over each registered DMAC | 196 | * Iterate over each registered DMAC |
184 | */ | 197 | */ |
185 | list_for_each_safe(pos, tmp, ®istered_dmac_list) { | 198 | list_for_each_entry(info, ®istered_dmac_list, list) { |
186 | struct dma_info *info = list_entry(pos, struct dma_info, list); | ||
187 | int i; | 199 | int i; |
188 | 200 | ||
189 | /* | 201 | /* |
@@ -205,9 +217,9 @@ static int dma_read_proc(char *buf, char **start, off_t off, | |||
205 | #endif | 217 | #endif |
206 | 218 | ||
207 | 219 | ||
208 | int __init register_dmac(struct dma_info *info) | 220 | int register_dmac(struct dma_info *info) |
209 | { | 221 | { |
210 | int i; | 222 | unsigned int total_channels, i; |
211 | 223 | ||
212 | INIT_LIST_HEAD(&info->list); | 224 | INIT_LIST_HEAD(&info->list); |
213 | 225 | ||
@@ -217,6 +229,11 @@ int __init register_dmac(struct dma_info *info) | |||
217 | 229 | ||
218 | BUG_ON((info->flags & DMAC_CHANNELS_CONFIGURED) && !info->channels); | 230 | BUG_ON((info->flags & DMAC_CHANNELS_CONFIGURED) && !info->channels); |
219 | 231 | ||
232 | info->pdev = platform_device_register_simple((char *)info->name, -1, | ||
233 | NULL, 0); | ||
234 | if (IS_ERR(info->pdev)) | ||
235 | return PTR_ERR(info->pdev); | ||
236 | |||
220 | /* | 237 | /* |
221 | * Don't touch pre-configured channels | 238 | * Don't touch pre-configured channels |
222 | */ | 239 | */ |
@@ -232,10 +249,12 @@ int __init register_dmac(struct dma_info *info) | |||
232 | memset(info->channels, 0, size); | 249 | memset(info->channels, 0, size); |
233 | } | 250 | } |
234 | 251 | ||
252 | total_channels = get_nr_channels(); | ||
235 | for (i = 0; i < info->nr_channels; i++) { | 253 | for (i = 0; i < info->nr_channels; i++) { |
236 | struct dma_channel *chan = info->channels + i; | 254 | struct dma_channel *chan = info->channels + i; |
237 | 255 | ||
238 | chan->chan = i; | 256 | chan->chan = i; |
257 | chan->vchan = i + total_channels; | ||
239 | 258 | ||
240 | memcpy(chan->dev_id, "Unused", 7); | 259 | memcpy(chan->dev_id, "Unused", 7); |
241 | 260 | ||
@@ -245,9 +264,7 @@ int __init register_dmac(struct dma_info *info) | |||
245 | init_MUTEX(&chan->sem); | 264 | init_MUTEX(&chan->sem); |
246 | init_waitqueue_head(&chan->wait_queue); | 265 | init_waitqueue_head(&chan->wait_queue); |
247 | 266 | ||
248 | #ifdef CONFIG_SYSFS | 267 | dma_create_sysfs_files(chan, info); |
249 | dma_create_sysfs_files(chan); | ||
250 | #endif | ||
251 | } | 268 | } |
252 | 269 | ||
253 | list_add(&info->list, ®istered_dmac_list); | 270 | list_add(&info->list, ®istered_dmac_list); |
@@ -255,12 +272,18 @@ int __init register_dmac(struct dma_info *info) | |||
255 | return 0; | 272 | return 0; |
256 | } | 273 | } |
257 | 274 | ||
258 | void __exit unregister_dmac(struct dma_info *info) | 275 | void unregister_dmac(struct dma_info *info) |
259 | { | 276 | { |
277 | unsigned int i; | ||
278 | |||
279 | for (i = 0; i < info->nr_channels; i++) | ||
280 | dma_remove_sysfs_files(info->channels + i, info); | ||
281 | |||
260 | if (!(info->flags & DMAC_CHANNELS_CONFIGURED)) | 282 | if (!(info->flags & DMAC_CHANNELS_CONFIGURED)) |
261 | kfree(info->channels); | 283 | kfree(info->channels); |
262 | 284 | ||
263 | list_del(&info->list); | 285 | list_del(&info->list); |
286 | platform_device_unregister(info->pdev); | ||
264 | } | 287 | } |
265 | 288 | ||
266 | static int __init dma_api_init(void) | 289 | static int __init dma_api_init(void) |