Blame view

sound/synth/util_mem.c 4.55 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   *  Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>
   *
   *  Generic memory management routines for soundcard memory allocation
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
ef9f0a42d   Ingo Molnar   [ALSA] semaphore ...
20
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  #include <linux/init.h>
  #include <linux/slab.h>
da155d5b4   Paul Gortmaker   sound: Add module...
23
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
  #include <sound/core.h>
  #include <sound/util_mem.h>
  
  MODULE_AUTHOR("Takashi Iwai");
  MODULE_DESCRIPTION("Generic memory management routines for soundcard memory allocation");
  MODULE_LICENSE("GPL");
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
30
  #define get_memblk(p)	list_entry(p, struct snd_util_memblk, list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
  
  /*
   * create a new memory manager
   */
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
35
  struct snd_util_memhdr *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
  snd_util_memhdr_new(int memsize)
  {
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
38
  	struct snd_util_memhdr *hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

561b220a4   Takashi Iwai   [ALSA] Replace wi...
40
  	hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
  	if (hdr == NULL)
  		return NULL;
  	hdr->size = memsize;
ef9f0a42d   Ingo Molnar   [ALSA] semaphore ...
44
  	mutex_init(&hdr->block_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
52
  	INIT_LIST_HEAD(&hdr->block);
  
  	return hdr;
  }
  
  /*
   * free a memory manager
   */
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
53
  void snd_util_memhdr_free(struct snd_util_memhdr *hdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
  {
  	struct list_head *p;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
56
57
  	if (!hdr)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
63
64
65
66
67
68
  	/* release all blocks */
  	while ((p = hdr->block.next) != &hdr->block) {
  		list_del(p);
  		kfree(get_memblk(p));
  	}
  	kfree(hdr);
  }
  
  /*
   * allocate a memory block (without mutex)
   */
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
69
70
  struct snd_util_memblk *
  __snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  {
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
72
73
  	struct snd_util_memblk *blk;
  	unsigned int units, prev_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  	struct list_head *p;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
75
76
  	if (snd_BUG_ON(!hdr || size <= 0))
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  
  	/* word alignment */
  	units = size;
  	if (units & 1)
  		units++;
  	if (units > hdr->size)
  		return NULL;
  
  	/* look for empty block */
  	prev_offset = 0;
  	list_for_each(p, &hdr->block) {
  		blk = get_memblk(p);
  		if (blk->offset - prev_offset >= units)
  			goto __found;
  		prev_offset = blk->offset + blk->size;
  	}
  	if (hdr->size - prev_offset < units)
  		return NULL;
  
  __found:
  	return __snd_util_memblk_new(hdr, units, p->prev);
  }
  
  
  /*
   * create a new memory block with the given size
   * the block is linked next to prev
   */
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
105
106
  struct snd_util_memblk *
  __snd_util_memblk_new(struct snd_util_memhdr *hdr, unsigned int units,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
  		      struct list_head *prev)
  {
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
109
  	struct snd_util_memblk *blk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110

03da312ac   Takashi Iwai   [ALSA] Remove xxx...
111
112
  	blk = kmalloc(sizeof(struct snd_util_memblk) + hdr->block_extra_size,
  		      GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  	if (blk == NULL)
  		return NULL;
8e6c962cd   Adrian Bunk   [ALSA] sound/synt...
115
  	if (prev == &hdr->block)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
  		blk->offset = 0;
  	else {
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
118
  		struct snd_util_memblk *p = get_memblk(prev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
125
126
127
128
129
130
131
  		blk->offset = p->offset + p->size;
  	}
  	blk->size = units;
  	list_add(&blk->list, prev);
  	hdr->nblocks++;
  	hdr->used += units;
  	return blk;
  }
  
  
  /*
   * allocate a memory block (with mutex)
   */
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
132
133
  struct snd_util_memblk *
  snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  {
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
135
  	struct snd_util_memblk *blk;
ef9f0a42d   Ingo Molnar   [ALSA] semaphore ...
136
  	mutex_lock(&hdr->block_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  	blk = __snd_util_mem_alloc(hdr, size);
ef9f0a42d   Ingo Molnar   [ALSA] semaphore ...
138
  	mutex_unlock(&hdr->block_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
143
144
145
146
147
  	return blk;
  }
  
  
  /*
   * remove the block from linked-list and free resource
   * (without mutex)
   */
  void
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
148
  __snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
153
154
155
156
157
158
  {
  	list_del(&blk->list);
  	hdr->nblocks--;
  	hdr->used -= blk->size;
  	kfree(blk);
  }
  
  /*
   * free a memory block (with mutex)
   */
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
159
  int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  {
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
161
162
  	if (snd_BUG_ON(!hdr || !blk))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163

ef9f0a42d   Ingo Molnar   [ALSA] semaphore ...
164
  	mutex_lock(&hdr->block_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  	__snd_util_mem_free(hdr, blk);
ef9f0a42d   Ingo Molnar   [ALSA] semaphore ...
166
  	mutex_unlock(&hdr->block_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
171
172
  	return 0;
  }
  
  /*
   * return available memory size
   */
03da312ac   Takashi Iwai   [ALSA] Remove xxx...
173
  int snd_util_mem_avail(struct snd_util_memhdr *hdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
  {
  	unsigned int size;
ef9f0a42d   Ingo Molnar   [ALSA] semaphore ...
176
  	mutex_lock(&hdr->block_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  	size = hdr->size - hdr->used;
ef9f0a42d   Ingo Molnar   [ALSA] semaphore ...
178
  	mutex_unlock(&hdr->block_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  	return size;
  }
  
  
  EXPORT_SYMBOL(snd_util_memhdr_new);
  EXPORT_SYMBOL(snd_util_memhdr_free);
  EXPORT_SYMBOL(snd_util_mem_alloc);
  EXPORT_SYMBOL(snd_util_mem_free);
  EXPORT_SYMBOL(snd_util_mem_avail);
  EXPORT_SYMBOL(__snd_util_mem_alloc);
  EXPORT_SYMBOL(__snd_util_mem_free);
  EXPORT_SYMBOL(__snd_util_memblk_new);
  
  /*
   *  INIT part
   */
  
  static int __init alsa_util_mem_init(void)
  {
  	return 0;
  }
  
  static void __exit alsa_util_mem_exit(void)
  {
  }
  
  module_init(alsa_util_mem_init)
  module_exit(alsa_util_mem_exit)