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 <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)
 212