2019-05-27 08:55:05 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-16 15:20:36 -07:00
/*
* ALSA sequencer MIDI - through client
* Copyright ( c ) 1999 - 2000 by Takashi Iwai < tiwai @ suse . de >
*/
# include <linux/init.h>
# include <linux/slab.h>
2011-07-15 13:13:37 -04:00
# include <linux/module.h>
2005-04-16 15:20:36 -07:00
# include <sound/core.h>
# include "seq_clientmgr.h"
# include <sound/initval.h>
# include <sound/asoundef.h>
/*
Sequencer MIDI - through client
This gives a simple midi - through client . All the normal input events
are redirected to output port immediately .
The routing can be done via aconnect program in alsa - utils .
2021-07-27 12:52:32 +02:00
Each client has a static client number 14 ( = SNDRV_SEQ_CLIENT_DUMMY ) .
2005-04-16 15:20:36 -07:00
If you want to auto - load this module , you may add the following alias
in your / etc / conf . modules file .
2021-07-27 12:52:32 +02:00
alias snd - seq - client - 14 snd - seq - dummy
2005-04-16 15:20:36 -07:00
2021-07-27 12:52:32 +02:00
The module is loaded on demand for client 14 , or / proc / asound / seq /
2005-04-16 15:20:36 -07:00
is accessed . If you don ' t need this module to be loaded , alias
2021-07-27 12:52:32 +02:00
snd - seq - client - 14 as " off " . This will help modprobe .
2005-04-16 15:20:36 -07:00
The number of ports to be created can be specified via the module
parameter " ports " . For example , to create four ports , add the
2012-03-30 13:37:16 -07:00
following option in a configuration file under / etc / modprobe . d / :
2005-04-16 15:20:36 -07:00
option snd - seq - dummy ports = 4
2011-03-30 22:57:33 -03:00
The model option " duplex=1 " enables duplex operation to the port .
2005-04-16 15:20:36 -07:00
In duplex mode , a pair of ports are created instead of single port ,
and events are tunneled between pair - ports . For example , input to
port A is sent to output port of another port B and vice versa .
In duplex mode , each port has DUPLEX capability .
*/
MODULE_AUTHOR ( " Takashi Iwai <tiwai@suse.de> " ) ;
MODULE_DESCRIPTION ( " ALSA sequencer MIDI-through client " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " snd-seq-client- " __stringify ( SNDRV_SEQ_CLIENT_DUMMY ) ) ;
static int ports = 1 ;
2011-12-15 13:49:36 +10:30
static bool duplex ;
2005-04-16 15:20:36 -07:00
module_param ( ports , int , 0444 ) ;
MODULE_PARM_DESC ( ports , " number of ports to be created " ) ;
module_param ( duplex , bool , 0444 ) ;
MODULE_PARM_DESC ( duplex , " create DUPLEX ports " ) ;
2005-11-17 14:04:02 +01:00
struct snd_seq_dummy_port {
2005-04-16 15:20:36 -07:00
int client ;
int port ;
int duplex ;
int connect ;
2005-11-17 14:04:02 +01:00
} ;
2005-04-16 15:20:36 -07:00
static int my_client = - 1 ;
/*
* event input callback - just redirect events to subscribers
*/
static int
2005-11-17 14:04:02 +01:00
dummy_input ( struct snd_seq_event * ev , int direct , void * private_data ,
int atomic , int hop )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:04:02 +01:00
struct snd_seq_dummy_port * p ;
struct snd_seq_event tmpev ;
2005-04-16 15:20:36 -07:00
p = private_data ;
if ( ev - > source . client = = SNDRV_SEQ_CLIENT_SYSTEM | |
ev - > type = = SNDRV_SEQ_EVENT_KERNEL_ERROR )
return 0 ; /* ignore system messages */
tmpev = * ev ;
if ( p - > duplex )
tmpev . source . port = p - > connect ;
else
tmpev . source . port = p - > port ;
tmpev . dest . client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS ;
return snd_seq_kernel_client_dispatch ( p - > client , & tmpev , atomic , hop ) ;
}
/*
* free_private callback
*/
static void
dummy_free ( void * private_data )
{
[ALSA] Remove redundant NULL checks before kfree
Timer Midlevel,ALSA sequencer,ALSA<-OSS sequencer,Digigram VX core
I2C tea6330t,GUS Library,VIA82xx driver,VIA82xx-modem driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,YMFPCI driver
Digigram VX Pocket driver,Common EMU synth,USB generic driver,USB USX2Y
Checking a pointer for NULL before calling kfree() on it is redundant,
kfree() deals with NULL pointers just fine.
This patch removes such checks from sound/
This patch also makes another, but closely related, change.
It avoids casting pointers about to be kfree()'ed.
Signed-off-by: Jesper Juhl <juhl-lkml@dif.dk>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-05-30 17:30:32 +02:00
kfree ( private_data ) ;
2005-04-16 15:20:36 -07:00
}
/*
* create a port
*/
2005-11-17 14:04:02 +01:00
static struct snd_seq_dummy_port __init *
2005-04-16 15:20:36 -07:00
create_port ( int idx , int type )
{
2005-11-17 14:04:02 +01:00
struct snd_seq_port_info pinfo ;
struct snd_seq_port_callback pcb ;
struct snd_seq_dummy_port * rec ;
2005-04-16 15:20:36 -07:00
2021-06-08 16:05:30 +02:00
rec = kzalloc ( sizeof ( * rec ) , GFP_KERNEL ) ;
if ( ! rec )
2005-04-16 15:20:36 -07:00
return NULL ;
rec - > client = my_client ;
rec - > duplex = duplex ;
rec - > connect = 0 ;
memset ( & pinfo , 0 , sizeof ( pinfo ) ) ;
pinfo . addr . client = my_client ;
if ( duplex )
sprintf ( pinfo . name , " Midi Through Port-%d:%c " , idx ,
( type ? ' B ' : ' A ' ) ) ;
else
sprintf ( pinfo . name , " Midi Through Port-%d " , idx ) ;
pinfo . capability = SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ ;
pinfo . capability | = SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE ;
if ( duplex )
pinfo . capability | = SNDRV_SEQ_PORT_CAP_DUPLEX ;
2006-05-02 16:08:41 +02:00
pinfo . type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
| SNDRV_SEQ_PORT_TYPE_SOFTWARE
| SNDRV_SEQ_PORT_TYPE_PORT ;
2005-04-16 15:20:36 -07:00
memset ( & pcb , 0 , sizeof ( pcb ) ) ;
pcb . owner = THIS_MODULE ;
pcb . event_input = dummy_input ;
pcb . private_free = dummy_free ;
pcb . private_data = rec ;
pinfo . kernel = & pcb ;
if ( snd_seq_kernel_client_ctl ( my_client , SNDRV_SEQ_IOCTL_CREATE_PORT , & pinfo ) < 0 ) {
kfree ( rec ) ;
return NULL ;
}
rec - > port = pinfo . addr . port ;
return rec ;
}
/*
* register client and create ports
*/
static int __init
register_client ( void )
{
2005-11-17 14:04:02 +01:00
struct snd_seq_dummy_port * rec1 , * rec2 ;
2005-04-16 15:20:36 -07:00
int i ;
if ( ports < 1 ) {
2014-02-04 18:24:34 +01:00
pr_err ( " ALSA: seq_dummy: invalid number of ports %d \n " , ports ) ;
2005-04-16 15:20:36 -07:00
return - EINVAL ;
}
/* create client */
2005-12-12 09:33:37 +01:00
my_client = snd_seq_create_kernel_client ( NULL , SNDRV_SEQ_CLIENT_DUMMY ,
" Midi Through " ) ;
2005-04-16 15:20:36 -07:00
if ( my_client < 0 )
return my_client ;
/* create ports */
for ( i = 0 ; i < ports ; i + + ) {
rec1 = create_port ( i , 0 ) ;
if ( rec1 = = NULL ) {
snd_seq_delete_kernel_client ( my_client ) ;
return - ENOMEM ;
}
if ( duplex ) {
rec2 = create_port ( i , 1 ) ;
if ( rec2 = = NULL ) {
snd_seq_delete_kernel_client ( my_client ) ;
return - ENOMEM ;
}
rec1 - > connect = rec2 - > port ;
rec2 - > connect = rec1 - > port ;
}
}
return 0 ;
}
/*
* delete client if exists
*/
static void __exit
delete_client ( void )
{
if ( my_client > = 0 )
snd_seq_delete_kernel_client ( my_client ) ;
}
/*
* Init part
*/
static int __init alsa_seq_dummy_init ( void )
{
2015-02-12 14:20:24 +01:00
return register_client ( ) ;
2005-04-16 15:20:36 -07:00
}
static void __exit alsa_seq_dummy_exit ( void )
{
delete_client ( ) ;
}
module_init ( alsa_seq_dummy_init )
module_exit ( alsa_seq_dummy_exit )