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