📄 seq_instr.c
字号:
/* * Generic Instrument routines for ALSA sequencer * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <sound/driver.h>#include <linux/init.h>#include <linux/slab.h>#include <sound/core.h>#include "seq_clientmgr.h"#include <sound/seq_instr.h>#include <sound/initval.h>MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer instrument library.");MODULE_LICENSE("GPL");static void snd_instr_lock_ops(snd_seq_kinstr_list_t *list){ if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) { spin_lock_irqsave(&list->ops_lock, list->ops_flags); } else { down(&list->ops_mutex); }}static void snd_instr_unlock_ops(snd_seq_kinstr_list_t *list){ if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) { spin_unlock_irqrestore(&list->ops_lock, list->ops_flags); } else { up(&list->ops_mutex); }}static snd_seq_kinstr_t *snd_seq_instr_new(int add_len, int atomic){ snd_seq_kinstr_t *instr; instr = kzalloc(sizeof(snd_seq_kinstr_t) + add_len, atomic ? GFP_ATOMIC : GFP_KERNEL); if (instr == NULL) return NULL; instr->add_len = add_len; return instr;}static int snd_seq_instr_free(snd_seq_kinstr_t *instr, int atomic){ int result = 0; if (instr == NULL) return -EINVAL; if (instr->ops && instr->ops->remove) result = instr->ops->remove(instr->ops->private_data, instr, 1); if (!result) kfree(instr); return result;}snd_seq_kinstr_list_t *snd_seq_instr_list_new(void){ snd_seq_kinstr_list_t *list; list = kzalloc(sizeof(snd_seq_kinstr_list_t), GFP_KERNEL); if (list == NULL) return NULL; spin_lock_init(&list->lock); spin_lock_init(&list->ops_lock); init_MUTEX(&list->ops_mutex); list->owner = -1; return list;}void snd_seq_instr_list_free(snd_seq_kinstr_list_t **list_ptr){ snd_seq_kinstr_list_t *list; snd_seq_kinstr_t *instr; snd_seq_kcluster_t *cluster; int idx; unsigned long flags; if (list_ptr == NULL) return; list = *list_ptr; *list_ptr = NULL; if (list == NULL) return; for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) { while ((instr = list->hash[idx]) != NULL) { list->hash[idx] = instr->next; list->count--; spin_lock_irqsave(&list->lock, flags); while (instr->use) { spin_unlock_irqrestore(&list->lock, flags); schedule_timeout_interruptible(1); spin_lock_irqsave(&list->lock, flags); } spin_unlock_irqrestore(&list->lock, flags); if (snd_seq_instr_free(instr, 0)<0) snd_printk(KERN_WARNING "instrument free problem\n"); } while ((cluster = list->chash[idx]) != NULL) { list->chash[idx] = cluster->next; list->ccount--; kfree(cluster); } } kfree(list);}static int instr_free_compare(snd_seq_kinstr_t *instr, snd_seq_instr_header_t *ifree, unsigned int client){ switch (ifree->cmd) { case SNDRV_SEQ_INSTR_FREE_CMD_ALL: /* all, except private for other clients */ if ((instr->instr.std & 0xff000000) == 0) return 0; if (((instr->instr.std >> 24) & 0xff) == client) return 0; return 1; case SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE: /* all my private instruments */ if ((instr->instr.std & 0xff000000) == 0) return 1; if (((instr->instr.std >> 24) & 0xff) == client) return 0; return 1; case SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER: /* all my private instruments */ if ((instr->instr.std & 0xff000000) == 0) { if (instr->instr.cluster == ifree->id.cluster) return 0; return 1; } if (((instr->instr.std >> 24) & 0xff) == client) { if (instr->instr.cluster == ifree->id.cluster) return 0; } return 1; } return 1;}int snd_seq_instr_list_free_cond(snd_seq_kinstr_list_t *list, snd_seq_instr_header_t *ifree, int client, int atomic){ snd_seq_kinstr_t *instr, *prev, *next, *flist; int idx; unsigned long flags; snd_instr_lock_ops(list); for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) { spin_lock_irqsave(&list->lock, flags); instr = list->hash[idx]; prev = flist = NULL; while (instr) { while (instr && instr_free_compare(instr, ifree, (unsigned int)client)) { prev = instr; instr = instr->next; } if (instr == NULL) continue; if (instr->ops && instr->ops->notify) instr->ops->notify(instr->ops->private_data, instr, SNDRV_SEQ_INSTR_NOTIFY_REMOVE); next = instr->next; if (prev == NULL) { list->hash[idx] = next; } else { prev->next = next; } list->count--; instr->next = flist; flist = instr; instr = next; } spin_unlock_irqrestore(&list->lock, flags); while (flist) { instr = flist; flist = instr->next; while (instr->use) schedule_timeout_interruptible(1); if (snd_seq_instr_free(instr, atomic)<0) snd_printk(KERN_WARNING "instrument free problem\n"); instr = next; } } snd_instr_unlock_ops(list); return 0; }static int compute_hash_instr_key(snd_seq_instr_t *instr){ int result; result = instr->bank | (instr->prg << 16); result += result >> 24; result += result >> 16; result += result >> 8; return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1);}#if 0static int compute_hash_cluster_key(snd_seq_instr_cluster_t cluster){ int result; result = cluster; result += result >> 24; result += result >> 16; result += result >> 8; return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1);}#endifstatic int compare_instr(snd_seq_instr_t *i1, snd_seq_instr_t *i2, int exact){ if (exact) { if (i1->cluster != i2->cluster || i1->bank != i2->bank || i1->prg != i2->prg) return 1; if ((i1->std & 0xff000000) != (i2->std & 0xff000000)) return 1; if (!(i1->std & i2->std)) return 1; return 0; } else { unsigned int client_check; if (i2->cluster && i1->cluster != i2->cluster) return 1; client_check = i2->std & 0xff000000; if (client_check) { if ((i1->std & 0xff000000) != client_check) return 1; } else { if ((i1->std & i2->std) != i2->std) return 1; } return i1->bank != i2->bank || i1->prg != i2->prg; }}snd_seq_kinstr_t *snd_seq_instr_find(snd_seq_kinstr_list_t *list, snd_seq_instr_t *instr, int exact, int follow_alias){ unsigned long flags; int depth = 0; snd_seq_kinstr_t *result; if (list == NULL || instr == NULL) return NULL; spin_lock_irqsave(&list->lock, flags); __again: result = list->hash[compute_hash_instr_key(instr)]; while (result) { if (!compare_instr(&result->instr, instr, exact)) { if (follow_alias && (result->type == SNDRV_SEQ_INSTR_ATYPE_ALIAS)) { instr = (snd_seq_instr_t *)KINSTR_DATA(result); if (++depth > 10) goto __not_found; goto __again; } result->use++; spin_unlock_irqrestore(&list->lock, flags); return result; } result = result->next; } __not_found: spin_unlock_irqrestore(&list->lock, flags); return NULL;}void snd_seq_instr_free_use(snd_seq_kinstr_list_t *list, snd_seq_kinstr_t *instr){ unsigned long flags; if (list == NULL || instr == NULL) return; spin_lock_irqsave(&list->lock, flags); if (instr->use <= 0) { snd_printk(KERN_ERR "free_use: fatal!!! use = %i, name = '%s'\n", instr->use, instr->name); } else { instr->use--; } spin_unlock_irqrestore(&list->lock, flags);}static snd_seq_kinstr_ops_t *instr_ops(snd_seq_kinstr_ops_t *ops, char *instr_type){ while (ops) { if (!strcmp(ops->instr_type, instr_type)) return ops; ops = ops->next; } return NULL;}static int instr_result(snd_seq_event_t *ev, int type, int result,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -