0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/mutex.h>
0009 #include <linux/init.h>
0010 #include <linux/slab.h>
0011 #include <linux/module.h>
0012 #include <sound/core.h>
0013 #include <sound/util_mem.h>
0014
0015 MODULE_AUTHOR("Takashi Iwai");
0016 MODULE_DESCRIPTION("Generic memory management routines for soundcard memory allocation");
0017 MODULE_LICENSE("GPL");
0018
0019 #define get_memblk(p) list_entry(p, struct snd_util_memblk, list)
0020
0021
0022
0023
0024 struct snd_util_memhdr *
0025 snd_util_memhdr_new(int memsize)
0026 {
0027 struct snd_util_memhdr *hdr;
0028
0029 hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
0030 if (hdr == NULL)
0031 return NULL;
0032 hdr->size = memsize;
0033 mutex_init(&hdr->block_mutex);
0034 INIT_LIST_HEAD(&hdr->block);
0035
0036 return hdr;
0037 }
0038
0039
0040
0041
0042 void snd_util_memhdr_free(struct snd_util_memhdr *hdr)
0043 {
0044 struct list_head *p;
0045
0046 if (!hdr)
0047 return;
0048
0049 while ((p = hdr->block.next) != &hdr->block) {
0050 list_del(p);
0051 kfree(get_memblk(p));
0052 }
0053 kfree(hdr);
0054 }
0055
0056
0057
0058
0059 struct snd_util_memblk *
0060 __snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
0061 {
0062 struct snd_util_memblk *blk;
0063 unsigned int units, prev_offset;
0064 struct list_head *p;
0065
0066 if (snd_BUG_ON(!hdr || size <= 0))
0067 return NULL;
0068
0069
0070 units = size;
0071 if (units & 1)
0072 units++;
0073 if (units > hdr->size)
0074 return NULL;
0075
0076
0077 prev_offset = 0;
0078 list_for_each(p, &hdr->block) {
0079 blk = get_memblk(p);
0080 if (blk->offset - prev_offset >= units)
0081 goto __found;
0082 prev_offset = blk->offset + blk->size;
0083 }
0084 if (hdr->size - prev_offset < units)
0085 return NULL;
0086
0087 __found:
0088 return __snd_util_memblk_new(hdr, units, p->prev);
0089 }
0090
0091
0092
0093
0094
0095
0096 struct snd_util_memblk *
0097 __snd_util_memblk_new(struct snd_util_memhdr *hdr, unsigned int units,
0098 struct list_head *prev)
0099 {
0100 struct snd_util_memblk *blk;
0101
0102 blk = kmalloc(sizeof(struct snd_util_memblk) + hdr->block_extra_size,
0103 GFP_KERNEL);
0104 if (blk == NULL)
0105 return NULL;
0106
0107 if (prev == &hdr->block)
0108 blk->offset = 0;
0109 else {
0110 struct snd_util_memblk *p = get_memblk(prev);
0111 blk->offset = p->offset + p->size;
0112 }
0113 blk->size = units;
0114 list_add(&blk->list, prev);
0115 hdr->nblocks++;
0116 hdr->used += units;
0117 return blk;
0118 }
0119
0120
0121
0122
0123
0124 struct snd_util_memblk *
0125 snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
0126 {
0127 struct snd_util_memblk *blk;
0128 mutex_lock(&hdr->block_mutex);
0129 blk = __snd_util_mem_alloc(hdr, size);
0130 mutex_unlock(&hdr->block_mutex);
0131 return blk;
0132 }
0133
0134
0135
0136
0137
0138
0139 void
0140 __snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
0141 {
0142 list_del(&blk->list);
0143 hdr->nblocks--;
0144 hdr->used -= blk->size;
0145 kfree(blk);
0146 }
0147
0148
0149
0150
0151 int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
0152 {
0153 if (snd_BUG_ON(!hdr || !blk))
0154 return -EINVAL;
0155
0156 mutex_lock(&hdr->block_mutex);
0157 __snd_util_mem_free(hdr, blk);
0158 mutex_unlock(&hdr->block_mutex);
0159 return 0;
0160 }
0161
0162
0163
0164
0165 int snd_util_mem_avail(struct snd_util_memhdr *hdr)
0166 {
0167 unsigned int size;
0168 mutex_lock(&hdr->block_mutex);
0169 size = hdr->size - hdr->used;
0170 mutex_unlock(&hdr->block_mutex);
0171 return size;
0172 }
0173
0174
0175 EXPORT_SYMBOL(snd_util_memhdr_new);
0176 EXPORT_SYMBOL(snd_util_memhdr_free);
0177 EXPORT_SYMBOL(snd_util_mem_alloc);
0178 EXPORT_SYMBOL(snd_util_mem_free);
0179 EXPORT_SYMBOL(snd_util_mem_avail);
0180 EXPORT_SYMBOL(__snd_util_mem_alloc);
0181 EXPORT_SYMBOL(__snd_util_mem_free);
0182 EXPORT_SYMBOL(__snd_util_memblk_new);