Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / sound / synth / util_mem.c
1 /*
2  *  Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>
3  *
4  *  Generic memory management routines for soundcard memory allocation
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  */
20
21 #include <linux/mutex.h>
22 #include <linux/init.h>
23 #include <linux/slab.h>
24 #include <linux/module.h>
25 #include <sound/core.h>
26 #include <sound/util_mem.h>
27
28 MODULE_AUTHOR("Takashi Iwai");
29 MODULE_DESCRIPTION("Generic memory management routines for soundcard memory allocation");
30 MODULE_LICENSE("GPL");
31
32 #define get_memblk(p)   list_entry(p, struct snd_util_memblk, list)
33
34 /*
35  * create a new memory manager
36  */
37 struct snd_util_memhdr *
38 snd_util_memhdr_new(int memsize)
39 {
40         struct snd_util_memhdr *hdr;
41
42         hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
43         if (hdr == NULL)
44                 return NULL;
45         hdr->size = memsize;
46         mutex_init(&hdr->block_mutex);
47         INIT_LIST_HEAD(&hdr->block);
48
49         return hdr;
50 }
51
52 /*
53  * free a memory manager
54  */
55 void snd_util_memhdr_free(struct snd_util_memhdr *hdr)
56 {
57         struct list_head *p;
58
59         if (!hdr)
60                 return;
61         /* release all blocks */
62         while ((p = hdr->block.next) != &hdr->block) {
63                 list_del(p);
64                 kfree(get_memblk(p));
65         }
66         kfree(hdr);
67 }
68
69 /*
70  * allocate a memory block (without mutex)
71  */
72 struct snd_util_memblk *
73 __snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
74 {
75         struct snd_util_memblk *blk;
76         unsigned int units, prev_offset;
77         struct list_head *p;
78
79         if (snd_BUG_ON(!hdr || size <= 0))
80                 return NULL;
81
82         /* word alignment */
83         units = size;
84         if (units & 1)
85                 units++;
86         if (units > hdr->size)
87                 return NULL;
88
89         /* look for empty block */
90         prev_offset = 0;
91         list_for_each(p, &hdr->block) {
92                 blk = get_memblk(p);
93                 if (blk->offset - prev_offset >= units)
94                         goto __found;
95                 prev_offset = blk->offset + blk->size;
96         }
97         if (hdr->size - prev_offset < units)
98                 return NULL;
99
100 __found:
101         return __snd_util_memblk_new(hdr, units, p->prev);
102 }
103
104
105 /*
106  * create a new memory block with the given size
107  * the block is linked next to prev
108  */
109 struct snd_util_memblk *
110 __snd_util_memblk_new(struct snd_util_memhdr *hdr, unsigned int units,
111                       struct list_head *prev)
112 {
113         struct snd_util_memblk *blk;
114
115         blk = kmalloc(sizeof(struct snd_util_memblk) + hdr->block_extra_size,
116                       GFP_KERNEL);
117         if (blk == NULL)
118                 return NULL;
119
120         if (prev == &hdr->block)
121                 blk->offset = 0;
122         else {
123                 struct snd_util_memblk *p = get_memblk(prev);
124                 blk->offset = p->offset + p->size;
125         }
126         blk->size = units;
127         list_add(&blk->list, prev);
128         hdr->nblocks++;
129         hdr->used += units;
130         return blk;
131 }
132
133
134 /*
135  * allocate a memory block (with mutex)
136  */
137 struct snd_util_memblk *
138 snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
139 {
140         struct snd_util_memblk *blk;
141         mutex_lock(&hdr->block_mutex);
142         blk = __snd_util_mem_alloc(hdr, size);
143         mutex_unlock(&hdr->block_mutex);
144         return blk;
145 }
146
147
148 /*
149  * remove the block from linked-list and free resource
150  * (without mutex)
151  */
152 void
153 __snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
154 {
155         list_del(&blk->list);
156         hdr->nblocks--;
157         hdr->used -= blk->size;
158         kfree(blk);
159 }
160
161 /*
162  * free a memory block (with mutex)
163  */
164 int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
165 {
166         if (snd_BUG_ON(!hdr || !blk))
167                 return -EINVAL;
168
169         mutex_lock(&hdr->block_mutex);
170         __snd_util_mem_free(hdr, blk);
171         mutex_unlock(&hdr->block_mutex);
172         return 0;
173 }
174
175 /*
176  * return available memory size
177  */
178 int snd_util_mem_avail(struct snd_util_memhdr *hdr)
179 {
180         unsigned int size;
181         mutex_lock(&hdr->block_mutex);
182         size = hdr->size - hdr->used;
183         mutex_unlock(&hdr->block_mutex);
184         return size;
185 }
186
187
188 EXPORT_SYMBOL(snd_util_memhdr_new);
189 EXPORT_SYMBOL(snd_util_memhdr_free);
190 EXPORT_SYMBOL(snd_util_mem_alloc);
191 EXPORT_SYMBOL(snd_util_mem_free);
192 EXPORT_SYMBOL(snd_util_mem_avail);
193 EXPORT_SYMBOL(__snd_util_mem_alloc);
194 EXPORT_SYMBOL(__snd_util_mem_free);
195 EXPORT_SYMBOL(__snd_util_memblk_new);
196
197 /*
198  *  INIT part
199  */
200
201 static int __init alsa_util_mem_init(void)
202 {
203         return 0;
204 }
205
206 static void __exit alsa_util_mem_exit(void)
207 {
208 }
209
210 module_init(alsa_util_mem_init)
211 module_exit(alsa_util_mem_exit)