2005-04-16 15:20:36 -07:00
/*
* 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 " ) ;
2005-11-17 14:04:02 +01:00
static void snd_instr_lock_ops ( struct snd_seq_kinstr_list * list )
2005-04-16 15:20:36 -07:00
{
if ( ! ( list - > flags & SNDRV_SEQ_INSTR_FLG_DIRECT ) ) {
spin_lock_irqsave ( & list - > ops_lock , list - > ops_flags ) ;
} else {
2006-01-16 16:29:08 +01:00
mutex_lock ( & list - > ops_mutex ) ;
2005-04-16 15:20:36 -07:00
}
}
2005-11-17 14:04:02 +01:00
static void snd_instr_unlock_ops ( struct snd_seq_kinstr_list * list )
2005-04-16 15:20:36 -07:00
{
if ( ! ( list - > flags & SNDRV_SEQ_INSTR_FLG_DIRECT ) ) {
spin_unlock_irqrestore ( & list - > ops_lock , list - > ops_flags ) ;
} else {
2006-01-16 16:29:08 +01:00
mutex_unlock ( & list - > ops_mutex ) ;
2005-04-16 15:20:36 -07:00
}
}
2005-11-17 14:04:02 +01:00
static struct snd_seq_kinstr * snd_seq_instr_new ( int add_len , int atomic )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:04:02 +01:00
struct snd_seq_kinstr * instr ;
2005-04-16 15:20:36 -07:00
2005-11-17 14:04:02 +01:00
instr = kzalloc ( sizeof ( struct snd_seq_kinstr ) + add_len , atomic ? GFP_ATOMIC : GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( instr = = NULL )
return NULL ;
instr - > add_len = add_len ;
return instr ;
}
2005-11-17 14:04:02 +01:00
static int snd_seq_instr_free ( struct snd_seq_kinstr * instr , int atomic )
2005-04-16 15:20:36 -07:00
{
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 ;
}
2005-11-17 14:04:02 +01:00
struct snd_seq_kinstr_list * snd_seq_instr_list_new ( void )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:04:02 +01:00
struct snd_seq_kinstr_list * list ;
2005-04-16 15:20:36 -07:00
2005-11-17 14:04:02 +01:00
list = kzalloc ( sizeof ( struct snd_seq_kinstr_list ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( list = = NULL )
return NULL ;
spin_lock_init ( & list - > lock ) ;
spin_lock_init ( & list - > ops_lock ) ;
2006-01-16 16:29:08 +01:00
mutex_init ( & list - > ops_mutex ) ;
2005-04-16 15:20:36 -07:00
list - > owner = - 1 ;
return list ;
}
2005-11-17 14:04:02 +01:00
void snd_seq_instr_list_free ( struct snd_seq_kinstr_list * * list_ptr )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:04:02 +01:00
struct snd_seq_kinstr_list * list ;
struct snd_seq_kinstr * instr ;
struct snd_seq_kcluster * cluster ;
2005-04-16 15:20:36 -07:00
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 ) ;
2005-10-24 15:02:37 +02:00
schedule_timeout_interruptible ( 1 ) ;
2005-04-16 15:20:36 -07:00
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 ) ;
}
2005-11-17 14:04:02 +01:00
static int instr_free_compare ( struct snd_seq_kinstr * instr ,
struct snd_seq_instr_header * ifree ,
2005-04-16 15:20:36 -07:00
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 ;
}
2005-11-17 14:04:02 +01:00
int snd_seq_instr_list_free_cond ( struct snd_seq_kinstr_list * list ,
struct snd_seq_instr_header * ifree ,
2005-04-16 15:20:36 -07:00
int client ,
int atomic )
{
2005-11-17 14:04:02 +01:00
struct snd_seq_kinstr * instr , * prev , * next , * flist ;
2005-04-16 15:20:36 -07:00
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 ;
2005-10-24 15:02:37 +02:00
while ( instr - > use )
schedule_timeout_interruptible ( 1 ) ;
2005-04-16 15:20:36 -07:00
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 ;
}
2005-11-17 14:04:02 +01:00
static int compute_hash_instr_key ( struct snd_seq_instr * instr )
2005-04-16 15:20:36 -07:00
{
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 0
static 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 ) ;
}
# endif
2005-11-17 14:04:02 +01:00
static int compare_instr ( struct snd_seq_instr * i1 , struct snd_seq_instr * i2 , int exact )
2005-04-16 15:20:36 -07:00
{
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 ;
}
}
2005-11-17 14:04:02 +01:00
struct snd_seq_kinstr * snd_seq_instr_find ( struct snd_seq_kinstr_list * list ,
struct snd_seq_instr * instr ,
int exact ,
int follow_alias )
2005-04-16 15:20:36 -07:00
{
unsigned long flags ;
int depth = 0 ;
2005-11-17 14:04:02 +01:00
struct snd_seq_kinstr * result ;
2005-04-16 15:20:36 -07:00
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 ) ) {
2005-11-17 14:04:02 +01:00
instr = ( struct snd_seq_instr * ) KINSTR_DATA ( result ) ;
2005-04-16 15:20:36 -07:00
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 ;
}
2005-11-17 14:04:02 +01:00
void snd_seq_instr_free_use ( struct snd_seq_kinstr_list * list ,
struct snd_seq_kinstr * instr )
2005-04-16 15:20:36 -07:00
{
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 ) ;
}
2005-11-17 14:04:02 +01:00
static struct snd_seq_kinstr_ops * instr_ops ( struct snd_seq_kinstr_ops * ops ,
char * instr_type )
2005-04-16 15:20:36 -07:00
{
while ( ops ) {
if ( ! strcmp ( ops - > instr_type , instr_type ) )
return ops ;
ops = ops - > next ;
}
return NULL ;
}
2005-11-17 14:04:02 +01:00
static int instr_result ( struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int type , int result ,
int atomic )
{
2005-11-17 14:04:02 +01:00
struct snd_seq_event sev ;
2005-04-16 15:20:36 -07:00
memset ( & sev , 0 , sizeof ( sev ) ) ;
sev . type = SNDRV_SEQ_EVENT_RESULT ;
sev . flags = SNDRV_SEQ_TIME_STAMP_REAL | SNDRV_SEQ_EVENT_LENGTH_FIXED |
SNDRV_SEQ_PRIORITY_NORMAL ;
sev . source = ev - > dest ;
sev . dest = ev - > source ;
sev . data . result . event = type ;
sev . data . result . result = result ;
#if 0
printk ( " instr result - type = %i, result = %i, queue = %i, source.client:port = %i:%i, dest.client:port = %i:%i \n " ,
type , result ,
sev . queue ,
sev . source . client , sev . source . port ,
sev . dest . client , sev . dest . port ) ;
# endif
return snd_seq_kernel_client_dispatch ( sev . source . client , & sev , atomic , 0 ) ;
}
2005-11-17 14:04:02 +01:00
static int instr_begin ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
unsigned long flags ;
spin_lock_irqsave ( & list - > lock , flags ) ;
if ( list - > owner > = 0 & & list - > owner ! = ev - > source . client ) {
spin_unlock_irqrestore ( & list - > lock , flags ) ;
return instr_result ( ev , SNDRV_SEQ_EVENT_INSTR_BEGIN , - EBUSY , atomic ) ;
}
list - > owner = ev - > source . client ;
spin_unlock_irqrestore ( & list - > lock , flags ) ;
return instr_result ( ev , SNDRV_SEQ_EVENT_INSTR_BEGIN , 0 , atomic ) ;
}
2005-11-17 14:04:02 +01:00
static int instr_end ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
unsigned long flags ;
/* TODO: timeout handling */
spin_lock_irqsave ( & list - > lock , flags ) ;
if ( list - > owner = = ev - > source . client ) {
list - > owner = - 1 ;
spin_unlock_irqrestore ( & list - > lock , flags ) ;
return instr_result ( ev , SNDRV_SEQ_EVENT_INSTR_END , 0 , atomic ) ;
}
spin_unlock_irqrestore ( & list - > lock , flags ) ;
return instr_result ( ev , SNDRV_SEQ_EVENT_INSTR_END , - EINVAL , atomic ) ;
}
2005-11-17 14:04:02 +01:00
static int instr_info ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
return - ENXIO ;
}
2005-11-17 14:04:02 +01:00
static int instr_format_info ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
return - ENXIO ;
}
2005-11-17 14:04:02 +01:00
static int instr_reset ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
return - ENXIO ;
}
2005-11-17 14:04:02 +01:00
static int instr_status ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
return - ENXIO ;
}
2005-11-17 14:04:02 +01:00
static int instr_put ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
unsigned long flags ;
2005-11-17 14:04:02 +01:00
struct snd_seq_instr_header put ;
struct snd_seq_kinstr * instr ;
2005-04-16 15:20:36 -07:00
int result = - EINVAL , len , key ;
if ( ( ev - > flags & SNDRV_SEQ_EVENT_LENGTH_MASK ) ! = SNDRV_SEQ_EVENT_LENGTH_VARUSR )
goto __return ;
2005-11-17 14:04:02 +01:00
if ( ev - > data . ext . len < sizeof ( struct snd_seq_instr_header ) )
2005-04-16 15:20:36 -07:00
goto __return ;
2005-11-17 14:04:02 +01:00
if ( copy_from_user ( & put , ( void __user * ) ev - > data . ext . ptr ,
sizeof ( struct snd_seq_instr_header ) ) ) {
2005-04-16 15:20:36 -07:00
result = - EFAULT ;
goto __return ;
}
snd_instr_lock_ops ( list ) ;
if ( put . id . instr . std & 0xff000000 ) { /* private instrument */
put . id . instr . std & = 0x00ffffff ;
put . id . instr . std | = ( unsigned int ) ev - > source . client < < 24 ;
}
if ( ( instr = snd_seq_instr_find ( list , & put . id . instr , 1 , 0 ) ) ) {
snd_seq_instr_free_use ( list , instr ) ;
snd_instr_unlock_ops ( list ) ;
result = - EBUSY ;
goto __return ;
}
ops = instr_ops ( ops , put . data . data . format ) ;
if ( ops = = NULL ) {
snd_instr_unlock_ops ( list ) ;
goto __return ;
}
len = ops - > add_len ;
if ( put . data . type = = SNDRV_SEQ_INSTR_ATYPE_ALIAS )
2005-11-17 14:04:02 +01:00
len = sizeof ( struct snd_seq_instr ) ;
2005-04-16 15:20:36 -07:00
instr = snd_seq_instr_new ( len , atomic ) ;
if ( instr = = NULL ) {
snd_instr_unlock_ops ( list ) ;
result = - ENOMEM ;
goto __return ;
}
instr - > ops = ops ;
instr - > instr = put . id . instr ;
strlcpy ( instr - > name , put . data . name , sizeof ( instr - > name ) ) ;
instr - > type = put . data . type ;
if ( instr - > type = = SNDRV_SEQ_INSTR_ATYPE_DATA ) {
result = ops - > put ( ops - > private_data ,
instr ,
2005-11-17 14:04:02 +01:00
( void __user * ) ev - > data . ext . ptr + sizeof ( struct snd_seq_instr_header ) ,
ev - > data . ext . len - sizeof ( struct snd_seq_instr_header ) ,
2005-04-16 15:20:36 -07:00
atomic ,
put . cmd ) ;
if ( result < 0 ) {
snd_seq_instr_free ( instr , atomic ) ;
snd_instr_unlock_ops ( list ) ;
goto __return ;
}
}
key = compute_hash_instr_key ( & instr - > instr ) ;
spin_lock_irqsave ( & list - > lock , flags ) ;
instr - > next = list - > hash [ key ] ;
list - > hash [ key ] = instr ;
list - > count + + ;
spin_unlock_irqrestore ( & list - > lock , flags ) ;
snd_instr_unlock_ops ( list ) ;
result = 0 ;
__return :
instr_result ( ev , SNDRV_SEQ_EVENT_INSTR_PUT , result , atomic ) ;
return result ;
}
2005-11-17 14:04:02 +01:00
static int instr_get ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
return - ENXIO ;
}
2005-11-17 14:04:02 +01:00
static int instr_free ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
2005-11-17 14:04:02 +01:00
struct snd_seq_instr_header ifree ;
struct snd_seq_kinstr * instr , * prev ;
2005-04-16 15:20:36 -07:00
int result = - EINVAL ;
unsigned long flags ;
unsigned int hash ;
if ( ( ev - > flags & SNDRV_SEQ_EVENT_LENGTH_MASK ) ! = SNDRV_SEQ_EVENT_LENGTH_VARUSR )
goto __return ;
2005-11-17 14:04:02 +01:00
if ( ev - > data . ext . len < sizeof ( struct snd_seq_instr_header ) )
2005-04-16 15:20:36 -07:00
goto __return ;
2005-11-17 14:04:02 +01:00
if ( copy_from_user ( & ifree , ( void __user * ) ev - > data . ext . ptr ,
sizeof ( struct snd_seq_instr_header ) ) ) {
2005-04-16 15:20:36 -07:00
result = - EFAULT ;
goto __return ;
}
if ( ifree . cmd = = SNDRV_SEQ_INSTR_FREE_CMD_ALL | |
ifree . cmd = = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE | |
ifree . cmd = = SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER ) {
result = snd_seq_instr_list_free_cond ( list , & ifree , ev - > dest . client , atomic ) ;
goto __return ;
}
if ( ifree . cmd = = SNDRV_SEQ_INSTR_FREE_CMD_SINGLE ) {
if ( ifree . id . instr . std & 0xff000000 ) {
ifree . id . instr . std & = 0x00ffffff ;
ifree . id . instr . std | = ( unsigned int ) ev - > source . client < < 24 ;
}
hash = compute_hash_instr_key ( & ifree . id . instr ) ;
snd_instr_lock_ops ( list ) ;
spin_lock_irqsave ( & list - > lock , flags ) ;
instr = list - > hash [ hash ] ;
prev = NULL ;
while ( instr ) {
if ( ! compare_instr ( & instr - > instr , & ifree . id . instr , 1 ) )
goto __free_single ;
prev = instr ;
instr = instr - > next ;
}
result = - ENOENT ;
spin_unlock_irqrestore ( & list - > lock , flags ) ;
snd_instr_unlock_ops ( list ) ;
goto __return ;
__free_single :
if ( prev ) {
prev - > next = instr - > next ;
} else {
list - > hash [ hash ] = instr - > next ;
}
if ( instr - > ops & & instr - > ops - > notify )
2005-11-17 14:04:02 +01:00
instr - > ops - > notify ( instr - > ops - > private_data , instr ,
SNDRV_SEQ_INSTR_NOTIFY_REMOVE ) ;
2005-04-16 15:20:36 -07:00
while ( instr - > use ) {
spin_unlock_irqrestore ( & list - > lock , flags ) ;
2005-10-24 15:02:37 +02:00
schedule_timeout_interruptible ( 1 ) ;
2005-04-16 15:20:36 -07:00
spin_lock_irqsave ( & list - > lock , flags ) ;
}
spin_unlock_irqrestore ( & list - > lock , flags ) ;
result = snd_seq_instr_free ( instr , atomic ) ;
snd_instr_unlock_ops ( list ) ;
goto __return ;
}
__return :
instr_result ( ev , SNDRV_SEQ_EVENT_INSTR_FREE , result , atomic ) ;
return result ;
}
2005-11-17 14:04:02 +01:00
static int instr_list ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
return - ENXIO ;
}
2005-11-17 14:04:02 +01:00
static int instr_cluster ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int atomic , int hop )
{
return - ENXIO ;
}
2005-11-17 14:04:02 +01:00
int snd_seq_instr_event ( struct snd_seq_kinstr_ops * ops ,
struct snd_seq_kinstr_list * list ,
struct snd_seq_event * ev ,
2005-04-16 15:20:36 -07:00
int client ,
int atomic ,
int hop )
{
int direct = 0 ;
snd_assert ( ops ! = NULL & & list ! = NULL & & ev ! = NULL , return - EINVAL ) ;
if ( snd_seq_ev_is_direct ( ev ) ) {
direct = 1 ;
switch ( ev - > type ) {
case SNDRV_SEQ_EVENT_INSTR_BEGIN :
return instr_begin ( ops , list , ev , atomic , hop ) ;
case SNDRV_SEQ_EVENT_INSTR_END :
return instr_end ( ops , list , ev , atomic , hop ) ;
}
}
if ( ( list - > flags & SNDRV_SEQ_INSTR_FLG_DIRECT ) & & ! direct )
return - EINVAL ;
switch ( ev - > type ) {
case SNDRV_SEQ_EVENT_INSTR_INFO :
return instr_info ( ops , list , ev , atomic , hop ) ;
case SNDRV_SEQ_EVENT_INSTR_FINFO :
return instr_format_info ( ops , list , ev , atomic , hop ) ;
case SNDRV_SEQ_EVENT_INSTR_RESET :
return instr_reset ( ops , list , ev , atomic , hop ) ;
case SNDRV_SEQ_EVENT_INSTR_STATUS :
return instr_status ( ops , list , ev , atomic , hop ) ;
case SNDRV_SEQ_EVENT_INSTR_PUT :
return instr_put ( ops , list , ev , atomic , hop ) ;
case SNDRV_SEQ_EVENT_INSTR_GET :
return instr_get ( ops , list , ev , atomic , hop ) ;
case SNDRV_SEQ_EVENT_INSTR_FREE :
return instr_free ( ops , list , ev , atomic , hop ) ;
case SNDRV_SEQ_EVENT_INSTR_LIST :
return instr_list ( ops , list , ev , atomic , hop ) ;
case SNDRV_SEQ_EVENT_INSTR_CLUSTER :
return instr_cluster ( ops , list , ev , atomic , hop ) ;
}
return - EINVAL ;
}
/*
* Init part
*/
static int __init alsa_seq_instr_init ( void )
{
return 0 ;
}
static void __exit alsa_seq_instr_exit ( void )
{
}
module_init ( alsa_seq_instr_init )
module_exit ( alsa_seq_instr_exit )
EXPORT_SYMBOL ( snd_seq_instr_list_new ) ;
EXPORT_SYMBOL ( snd_seq_instr_list_free ) ;
EXPORT_SYMBOL ( snd_seq_instr_list_free_cond ) ;
EXPORT_SYMBOL ( snd_seq_instr_find ) ;
EXPORT_SYMBOL ( snd_seq_instr_free_use ) ;
EXPORT_SYMBOL ( snd_seq_instr_event ) ;