Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0004  *  GUS's memory allocation routines / bottom layer
0005  */
0006 
0007 #include <linux/slab.h>
0008 #include <linux/string.h>
0009 #include <sound/core.h>
0010 #include <sound/gus.h>
0011 #include <sound/info.h>
0012 
0013 #ifdef CONFIG_SND_DEBUG
0014 static void snd_gf1_mem_info_read(struct snd_info_entry *entry, 
0015                   struct snd_info_buffer *buffer);
0016 #endif
0017 
0018 void snd_gf1_mem_lock(struct snd_gf1_mem * alloc, int xup)
0019 {
0020     if (!xup) {
0021         mutex_lock(&alloc->memory_mutex);
0022     } else {
0023         mutex_unlock(&alloc->memory_mutex);
0024     }
0025 }
0026 
0027 static struct snd_gf1_mem_block *
0028 snd_gf1_mem_xalloc(struct snd_gf1_mem *alloc, struct snd_gf1_mem_block *block,
0029            const char *name)
0030 {
0031     struct snd_gf1_mem_block *pblock, *nblock;
0032 
0033     nblock = kmalloc(sizeof(struct snd_gf1_mem_block), GFP_KERNEL);
0034     if (nblock == NULL)
0035         return NULL;
0036     *nblock = *block;
0037     nblock->name = kstrdup(name, GFP_KERNEL);
0038     if (!nblock->name) {
0039         kfree(nblock);
0040         return NULL;
0041     }
0042 
0043     pblock = alloc->first;
0044     while (pblock) {
0045         if (pblock->ptr > nblock->ptr) {
0046             nblock->prev = pblock->prev;
0047             nblock->next = pblock;
0048             pblock->prev = nblock;
0049             if (pblock == alloc->first)
0050                 alloc->first = nblock;
0051             else
0052                 nblock->prev->next = nblock;
0053             mutex_unlock(&alloc->memory_mutex);
0054             return nblock;
0055         }
0056         pblock = pblock->next;
0057     }
0058     nblock->next = NULL;
0059     if (alloc->last == NULL) {
0060         nblock->prev = NULL;
0061         alloc->first = alloc->last = nblock;
0062     } else {
0063         nblock->prev = alloc->last;
0064         alloc->last->next = nblock;
0065         alloc->last = nblock;
0066     }
0067     return nblock;
0068 }
0069 
0070 int snd_gf1_mem_xfree(struct snd_gf1_mem * alloc, struct snd_gf1_mem_block * block)
0071 {
0072     if (block->share) { /* ok.. shared block */
0073         block->share--;
0074         mutex_unlock(&alloc->memory_mutex);
0075         return 0;
0076     }
0077     if (alloc->first == block) {
0078         alloc->first = block->next;
0079         if (block->next)
0080             block->next->prev = NULL;
0081     } else {
0082         block->prev->next = block->next;
0083         if (block->next)
0084             block->next->prev = block->prev;
0085     }
0086     if (alloc->last == block) {
0087         alloc->last = block->prev;
0088         if (block->prev)
0089             block->prev->next = NULL;
0090     } else {
0091         block->next->prev = block->prev;
0092         if (block->prev)
0093             block->prev->next = block->next;
0094     }
0095     kfree(block->name);
0096     kfree(block);
0097     return 0;
0098 }
0099 
0100 static struct snd_gf1_mem_block *snd_gf1_mem_look(struct snd_gf1_mem * alloc,
0101                          unsigned int address)
0102 {
0103     struct snd_gf1_mem_block *block;
0104 
0105     for (block = alloc->first; block; block = block->next) {
0106         if (block->ptr == address) {
0107             return block;
0108         }
0109     }
0110     return NULL;
0111 }
0112 
0113 static struct snd_gf1_mem_block *snd_gf1_mem_share(struct snd_gf1_mem * alloc,
0114                           unsigned int *share_id)
0115 {
0116     struct snd_gf1_mem_block *block;
0117 
0118     if (!share_id[0] && !share_id[1] &&
0119         !share_id[2] && !share_id[3])
0120         return NULL;
0121     for (block = alloc->first; block; block = block->next)
0122         if (!memcmp(share_id, block->share_id,
0123                 sizeof(block->share_id)))
0124             return block;
0125     return NULL;
0126 }
0127 
0128 static int snd_gf1_mem_find(struct snd_gf1_mem * alloc,
0129                 struct snd_gf1_mem_block * block,
0130                 unsigned int size, int w_16, int align)
0131 {
0132     struct snd_gf1_bank_info *info = w_16 ? alloc->banks_16 : alloc->banks_8;
0133     unsigned int idx, boundary;
0134     int size1;
0135     struct snd_gf1_mem_block *pblock;
0136     unsigned int ptr1, ptr2;
0137 
0138     if (w_16 && align < 2)
0139         align = 2;
0140     block->flags = w_16 ? SNDRV_GF1_MEM_BLOCK_16BIT : 0;
0141     block->owner = SNDRV_GF1_MEM_OWNER_DRIVER;
0142     block->share = 0;
0143     block->share_id[0] = block->share_id[1] =
0144     block->share_id[2] = block->share_id[3] = 0;
0145     block->name = NULL;
0146     block->prev = block->next = NULL;
0147     for (pblock = alloc->first, idx = 0; pblock; pblock = pblock->next) {
0148         while (pblock->ptr >= (boundary = info[idx].address + info[idx].size))
0149             idx++;
0150         while (pblock->ptr + pblock->size >= (boundary = info[idx].address + info[idx].size))
0151             idx++;
0152         ptr2 = boundary;
0153         if (pblock->next) {
0154             if (pblock->ptr + pblock->size == pblock->next->ptr)
0155                 continue;
0156             if (pblock->next->ptr < boundary)
0157                 ptr2 = pblock->next->ptr;
0158         }
0159         ptr1 = ALIGN(pblock->ptr + pblock->size, align);
0160         if (ptr1 >= ptr2)
0161             continue;
0162         size1 = ptr2 - ptr1;
0163         if ((int)size <= size1) {
0164             block->ptr = ptr1;
0165             block->size = size;
0166             return 0;
0167         }
0168     }
0169     while (++idx < 4) {
0170         if (size <= info[idx].size) {
0171             /* I assume that bank address is already aligned.. */
0172             block->ptr = info[idx].address;
0173             block->size = size;
0174             return 0;
0175         }
0176     }
0177     return -ENOMEM;
0178 }
0179 
0180 struct snd_gf1_mem_block *snd_gf1_mem_alloc(struct snd_gf1_mem * alloc, int owner,
0181                        char *name, int size, int w_16, int align,
0182                        unsigned int *share_id)
0183 {
0184     struct snd_gf1_mem_block block, *nblock;
0185 
0186     snd_gf1_mem_lock(alloc, 0);
0187     if (share_id != NULL) {
0188         nblock = snd_gf1_mem_share(alloc, share_id);
0189         if (nblock != NULL) {
0190             if (size != (int)nblock->size) {
0191                 /* TODO: remove in the future */
0192                 snd_printk(KERN_ERR "snd_gf1_mem_alloc - share: sizes differ\n");
0193                 goto __std;
0194             }
0195             nblock->share++;
0196             snd_gf1_mem_lock(alloc, 1);
0197             return NULL;
0198         }
0199     }
0200       __std:
0201     if (snd_gf1_mem_find(alloc, &block, size, w_16, align) < 0) {
0202         snd_gf1_mem_lock(alloc, 1);
0203         return NULL;
0204     }
0205     if (share_id != NULL)
0206         memcpy(&block.share_id, share_id, sizeof(block.share_id));
0207     block.owner = owner;
0208     nblock = snd_gf1_mem_xalloc(alloc, &block, name);
0209     snd_gf1_mem_lock(alloc, 1);
0210     return nblock;
0211 }
0212 
0213 int snd_gf1_mem_free(struct snd_gf1_mem * alloc, unsigned int address)
0214 {
0215     int result;
0216     struct snd_gf1_mem_block *block;
0217 
0218     snd_gf1_mem_lock(alloc, 0);
0219     block = snd_gf1_mem_look(alloc, address);
0220     if (block) {
0221         result = snd_gf1_mem_xfree(alloc, block);
0222         snd_gf1_mem_lock(alloc, 1);
0223         return result;
0224     }
0225     snd_gf1_mem_lock(alloc, 1);
0226     return -EINVAL;
0227 }
0228 
0229 int snd_gf1_mem_init(struct snd_gus_card * gus)
0230 {
0231     struct snd_gf1_mem *alloc;
0232     struct snd_gf1_mem_block block;
0233 
0234     alloc = &gus->gf1.mem_alloc;
0235     mutex_init(&alloc->memory_mutex);
0236     alloc->first = alloc->last = NULL;
0237     if (!gus->gf1.memory)
0238         return 0;
0239 
0240     memset(&block, 0, sizeof(block));
0241     block.owner = SNDRV_GF1_MEM_OWNER_DRIVER;
0242     if (gus->gf1.enh_mode) {
0243         block.ptr = 0;
0244         block.size = 1024;
0245         if (!snd_gf1_mem_xalloc(alloc, &block, "InterWave LFOs"))
0246             return -ENOMEM;
0247     }
0248     block.ptr = gus->gf1.default_voice_address;
0249     block.size = 4;
0250     if (!snd_gf1_mem_xalloc(alloc, &block, "Voice default (NULL's)"))
0251         return -ENOMEM;
0252 #ifdef CONFIG_SND_DEBUG
0253     snd_card_ro_proc_new(gus->card, "gusmem", gus, snd_gf1_mem_info_read);
0254 #endif
0255     return 0;
0256 }
0257 
0258 int snd_gf1_mem_done(struct snd_gus_card * gus)
0259 {
0260     struct snd_gf1_mem *alloc;
0261     struct snd_gf1_mem_block *block, *nblock;
0262 
0263     alloc = &gus->gf1.mem_alloc;
0264     block = alloc->first;
0265     while (block) {
0266         nblock = block->next;
0267         snd_gf1_mem_xfree(alloc, block);
0268         block = nblock;
0269     }
0270     return 0;
0271 }
0272 
0273 #ifdef CONFIG_SND_DEBUG
0274 static void snd_gf1_mem_info_read(struct snd_info_entry *entry, 
0275                   struct snd_info_buffer *buffer)
0276 {
0277     struct snd_gus_card *gus;
0278     struct snd_gf1_mem *alloc;
0279     struct snd_gf1_mem_block *block;
0280     unsigned int total, used;
0281     int i;
0282 
0283     gus = entry->private_data;
0284     alloc = &gus->gf1.mem_alloc;
0285     mutex_lock(&alloc->memory_mutex);
0286     snd_iprintf(buffer, "8-bit banks       : \n    ");
0287     for (i = 0; i < 4; i++)
0288         snd_iprintf(buffer, "0x%06x (%04ik)%s", alloc->banks_8[i].address, alloc->banks_8[i].size >> 10, i + 1 < 4 ? "," : "");
0289     snd_iprintf(buffer, "\n"
0290             "16-bit banks      : \n    ");
0291     for (i = total = 0; i < 4; i++) {
0292         snd_iprintf(buffer, "0x%06x (%04ik)%s", alloc->banks_16[i].address, alloc->banks_16[i].size >> 10, i + 1 < 4 ? "," : "");
0293         total += alloc->banks_16[i].size;
0294     }
0295     snd_iprintf(buffer, "\n");
0296     used = 0;
0297     for (block = alloc->first, i = 0; block; block = block->next, i++) {
0298         used += block->size;
0299         snd_iprintf(buffer, "Block %i onboard 0x%x size %i (0x%x):\n", i, block->ptr, block->size, block->size);
0300         if (block->share ||
0301             block->share_id[0] || block->share_id[1] ||
0302             block->share_id[2] || block->share_id[3])
0303             snd_iprintf(buffer, "  Share           : %i [id0 0x%x] [id1 0x%x] [id2 0x%x] [id3 0x%x]\n",
0304                 block->share,
0305                 block->share_id[0], block->share_id[1],
0306                 block->share_id[2], block->share_id[3]);
0307         snd_iprintf(buffer, "  Flags           :%s\n",
0308         block->flags & SNDRV_GF1_MEM_BLOCK_16BIT ? " 16-bit" : "");
0309         snd_iprintf(buffer, "  Owner           : ");
0310         switch (block->owner) {
0311         case SNDRV_GF1_MEM_OWNER_DRIVER:
0312             snd_iprintf(buffer, "driver - %s\n", block->name);
0313             break;
0314         case SNDRV_GF1_MEM_OWNER_WAVE_SIMPLE:
0315             snd_iprintf(buffer, "SIMPLE wave\n");
0316             break;
0317         case SNDRV_GF1_MEM_OWNER_WAVE_GF1:
0318             snd_iprintf(buffer, "GF1 wave\n");
0319             break;
0320         case SNDRV_GF1_MEM_OWNER_WAVE_IWFFFF:
0321             snd_iprintf(buffer, "IWFFFF wave\n");
0322             break;
0323         default:
0324             snd_iprintf(buffer, "unknown\n");
0325         }
0326     }
0327     snd_iprintf(buffer, "  Total: memory = %i, used = %i, free = %i\n",
0328             total, used, total - used);
0329     mutex_unlock(&alloc->memory_mutex);
0330 #if 0
0331     ultra_iprintf(buffer, "  Verify: free = %i, max 8-bit block = %i, max 16-bit block = %i\n",
0332               ultra_memory_free_size(card, &card->gf1.mem_alloc),
0333           ultra_memory_free_block(card, &card->gf1.mem_alloc, 0),
0334          ultra_memory_free_block(card, &card->gf1.mem_alloc, 1));
0335 #endif
0336 }
0337 #endif