Linux Audio

Check our new training course

In-person Linux kernel drivers training

Jun 16-20, 2025
Register
Loading...
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>
  4 *
  5 *  Generic memory management routines for soundcard memory allocation
  6 */
  7
  8#include <linux/mutex.h>
  9#include <linux/init.h>
 10#include <linux/slab.h>
 11#include <linux/module.h>
 12#include <sound/core.h>
 13#include <sound/util_mem.h>
 14
 15MODULE_AUTHOR("Takashi Iwai");
 16MODULE_DESCRIPTION("Generic memory management routines for soundcard memory allocation");
 17MODULE_LICENSE("GPL");
 18
 19#define get_memblk(p)	list_entry(p, struct snd_util_memblk, list)
 20
 21/*
 22 * create a new memory manager
 23 */
 24struct snd_util_memhdr *
 25snd_util_memhdr_new(int memsize)
 26{
 27	struct snd_util_memhdr *hdr;
 28
 29	hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
 30	if (hdr == NULL)
 31		return NULL;
 32	hdr->size = memsize;
 33	mutex_init(&hdr->block_mutex);
 34	INIT_LIST_HEAD(&hdr->block);
 35
 36	return hdr;
 37}
 38
 39/*
 40 * free a memory manager
 41 */
 42void snd_util_memhdr_free(struct snd_util_memhdr *hdr)
 43{
 44	struct list_head *p;
 45
 46	if (!hdr)
 47		return;
 48	/* release all blocks */
 49	while ((p = hdr->block.next) != &hdr->block) {
 50		list_del(p);
 51		kfree(get_memblk(p));
 52	}
 53	kfree(hdr);
 54}
 55
 56/*
 57 * allocate a memory block (without mutex)
 58 */
 59struct snd_util_memblk *
 60__snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
 61{
 62	struct snd_util_memblk *blk;
 63	unsigned int units, prev_offset;
 64	struct list_head *p;
 65
 66	if (snd_BUG_ON(!hdr || size <= 0))
 67		return NULL;
 68
 69	/* word alignment */
 70	units = size;
 71	if (units & 1)
 72		units++;
 73	if (units > hdr->size)
 74		return NULL;
 75
 76	/* look for empty block */
 77	prev_offset = 0;
 78	list_for_each(p, &hdr->block) {
 79		blk = get_memblk(p);
 80		if (blk->offset - prev_offset >= units)
 81			goto __found;
 82		prev_offset = blk->offset + blk->size;
 83	}
 84	if (hdr->size - prev_offset < units)
 85		return NULL;
 86
 87__found:
 88	return __snd_util_memblk_new(hdr, units, p->prev);
 89}
 90
 91
 92/*
 93 * create a new memory block with the given size
 94 * the block is linked next to prev
 95 */
 96struct snd_util_memblk *
 97__snd_util_memblk_new(struct snd_util_memhdr *hdr, unsigned int units,
 98		      struct list_head *prev)
 99{
100	struct snd_util_memblk *blk;
101
102	blk = kmalloc(sizeof(struct snd_util_memblk) + hdr->block_extra_size,
103		      GFP_KERNEL);
104	if (blk == NULL)
105		return NULL;
106
107	if (prev == &hdr->block)
108		blk->offset = 0;
109	else {
110		struct snd_util_memblk *p = get_memblk(prev);
111		blk->offset = p->offset + p->size;
112	}
113	blk->size = units;
114	list_add(&blk->list, prev);
115	hdr->nblocks++;
116	hdr->used += units;
117	return blk;
118}
119
120
121/*
122 * allocate a memory block (with mutex)
123 */
124struct snd_util_memblk *
125snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
126{
127	struct snd_util_memblk *blk;
128	mutex_lock(&hdr->block_mutex);
129	blk = __snd_util_mem_alloc(hdr, size);
130	mutex_unlock(&hdr->block_mutex);
131	return blk;
132}
133
134
135/*
136 * remove the block from linked-list and free resource
137 * (without mutex)
138 */
139void
140__snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
141{
142	list_del(&blk->list);
143	hdr->nblocks--;
144	hdr->used -= blk->size;
145	kfree(blk);
146}
147
148/*
149 * free a memory block (with mutex)
150 */
151int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
152{
153	if (snd_BUG_ON(!hdr || !blk))
154		return -EINVAL;
155
156	mutex_lock(&hdr->block_mutex);
157	__snd_util_mem_free(hdr, blk);
158	mutex_unlock(&hdr->block_mutex);
159	return 0;
160}
161
162/*
163 * return available memory size
164 */
165int snd_util_mem_avail(struct snd_util_memhdr *hdr)
166{
167	unsigned int size;
168	mutex_lock(&hdr->block_mutex);
169	size = hdr->size - hdr->used;
170	mutex_unlock(&hdr->block_mutex);
171	return size;
172}
173
174
175EXPORT_SYMBOL(snd_util_memhdr_new);
176EXPORT_SYMBOL(snd_util_memhdr_free);
177EXPORT_SYMBOL(snd_util_mem_alloc);
178EXPORT_SYMBOL(snd_util_mem_free);
179EXPORT_SYMBOL(snd_util_mem_avail);
180EXPORT_SYMBOL(__snd_util_mem_alloc);
181EXPORT_SYMBOL(__snd_util_mem_free);
182EXPORT_SYMBOL(__snd_util_memblk_new);
  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
 28MODULE_AUTHOR("Takashi Iwai");
 29MODULE_DESCRIPTION("Generic memory management routines for soundcard memory allocation");
 30MODULE_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 */
 37struct snd_util_memhdr *
 38snd_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 */
 55void 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 */
 72struct 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 */
109struct 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 */
137struct snd_util_memblk *
138snd_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 */
152void
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 */
164int 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 */
178int 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
188EXPORT_SYMBOL(snd_util_memhdr_new);
189EXPORT_SYMBOL(snd_util_memhdr_free);
190EXPORT_SYMBOL(snd_util_mem_alloc);
191EXPORT_SYMBOL(snd_util_mem_free);
192EXPORT_SYMBOL(snd_util_mem_avail);
193EXPORT_SYMBOL(__snd_util_mem_alloc);
194EXPORT_SYMBOL(__snd_util_mem_free);
195EXPORT_SYMBOL(__snd_util_memblk_new);
196
197/*
198 *  INIT part
199 */
200
201static int __init alsa_util_mem_init(void)
202{
203	return 0;
204}
205
206static void __exit alsa_util_mem_exit(void)
207{
208}
209
210module_init(alsa_util_mem_init)
211module_exit(alsa_util_mem_exit)