2018-01-11 13:08:40 +03:00
// SPDX-License-Identifier: GPL-2.0+
2010-10-07 22:20:02 +04:00
/* speakup_soft.c - speakup driver to register and make available
* a user space device for software synthesizers . written by : Kirk
* Reiser < kirk @ braille . uwo . ca >
*
* Copyright ( C ) 2003 Kirk Reiser .
*
2022-03-29 22:54:01 +03:00
* this code is specifically written as a driver for the speakup screenreview
2015-10-14 23:28:29 +03:00
* package and is not a general device driver .
*/
2010-10-07 22:20:02 +04:00
# include <linux/unistd.h>
2020-03-25 06:30:08 +03:00
# include <linux/miscdevice.h> /* for misc_register, and MISC_DYNAMIC_MINOR */
2016-11-21 18:19:24 +03:00
# include <linux/poll.h> /* for poll_wait() */
2019-02-28 15:29:04 +03:00
/* schedule(), signal_pending(), TASK_INTERRUPTIBLE */
# include <linux/sched/signal.h>
2010-10-07 22:20:02 +04:00
# include "spk_priv.h"
# include "speakup.h"
# define DRV_VERSION "2.6"
# define PROCSPEECH 0x0d
# define CLEAR_SYNTH 0x18
static int softsynth_probe ( struct spk_synth * synth ) ;
2021-01-27 01:21:44 +03:00
static void softsynth_release ( struct spk_synth * synth ) ;
2010-10-07 22:20:02 +04:00
static int softsynth_is_alive ( struct spk_synth * synth ) ;
2022-08-24 01:25:03 +03:00
static int softsynth_adjust ( struct spk_synth * synth , struct st_var_header * var ) ;
2017-04-29 22:52:58 +03:00
static unsigned char get_index ( struct spk_synth * synth ) ;
2010-10-07 22:20:02 +04:00
2017-03-04 17:01:57 +03:00
static struct miscdevice synth_device , synthu_device ;
2012-09-16 07:18:50 +04:00
static int init_pos ;
2010-10-07 22:20:02 +04:00
static int misc_registered ;
2022-11-10 00:50:54 +03:00
enum default_vars_id {
DIRECT_ID = 0 , CAPS_START_ID , CAPS_STOP_ID ,
PAUSE_ID , RATE_ID , PITCH_ID , INFLECTION_ID ,
VOL_ID , TONE_ID , PUNCT_ID , VOICE_ID ,
FREQUENCY_ID , V_LAST_VAR_ID ,
NB_ID
} ;
static struct var_t vars [ NB_ID ] = {
[ DIRECT_ID ] = { DIRECT , . u . n = { NULL , 0 , 0 , 1 , 0 , 0 , NULL } } ,
[ CAPS_START_ID ] = { CAPS_START , . u . s = { " \x01 +3p " } } ,
[ CAPS_STOP_ID ] = { CAPS_STOP , . u . s = { " \x01 -3p " } } ,
[ PAUSE_ID ] = { PAUSE , . u . n = { " \x01 P " } } ,
[ RATE_ID ] = { RATE , . u . n = { " \x01 %ds " , 2 , 0 , 9 , 0 , 0 , NULL } } ,
[ PITCH_ID ] = { PITCH , . u . n = { " \x01 %dp " , 5 , 0 , 9 , 0 , 0 , NULL } } ,
[ INFLECTION_ID ] = { INFLECTION , . u . n = { " \x01 %dr " , 5 , 0 , 9 , 0 , 0 , NULL } } ,
[ VOL_ID ] = { VOL , . u . n = { " \x01 %dv " , 5 , 0 , 9 , 0 , 0 , NULL } } ,
[ TONE_ID ] = { TONE , . u . n = { " \x01 %dx " , 1 , 0 , 2 , 0 , 0 , NULL } } ,
[ PUNCT_ID ] = { PUNCT , . u . n = { " \x01 %db " , 0 , 0 , 3 , 0 , 0 , NULL } } ,
[ VOICE_ID ] = { VOICE , . u . n = { " \x01 %do " , 0 , 0 , 7 , 0 , 0 , NULL } } ,
[ FREQUENCY_ID ] = { FREQUENCY , . u . n = { " \x01 %df " , 5 , 0 , 9 , 0 , 0 , NULL } } ,
2010-10-07 22:20:02 +04:00
V_LAST_VAR
} ;
2016-11-21 18:19:24 +03:00
/* These attributes will appear in /sys/accessibility/speakup/soft. */
2010-10-07 22:20:02 +04:00
static struct kobj_attribute caps_start_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( caps_start , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute caps_stop_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( caps_stop , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute freq_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( freq , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute pitch_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( pitch , 0644 , spk_var_show , spk_var_store ) ;
2020-04-25 22:32:26 +03:00
static struct kobj_attribute inflection_attribute =
__ATTR ( inflection , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute punct_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( punct , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute rate_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( rate , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute tone_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( tone , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute voice_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( voice , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute vol_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( vol , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
2010-10-15 04:23:57 +04:00
/*
* We should uncomment the following definition , when we agree on a
* method of passing a language designation to the software synthesizer .
* static struct kobj_attribute lang_attribute =
2017-01-28 09:35:01 +03:00
* __ATTR ( lang , 0644 , spk_var_show , spk_var_store ) ;
2010-10-15 04:23:57 +04:00
*/
2010-10-07 22:20:02 +04:00
static struct kobj_attribute delay_time_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( delay_time , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute direct_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( direct , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute full_time_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( full_time , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute jiffy_delta_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( jiffy_delta , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
static struct kobj_attribute trigger_time_attribute =
2017-01-28 09:35:01 +03:00
__ATTR ( trigger_time , 0644 , spk_var_show , spk_var_store ) ;
2010-10-07 22:20:02 +04:00
/*
* Create a group of attributes so that we can create and destroy them all
* at once .
*/
static struct attribute * synth_attrs [ ] = {
& caps_start_attribute . attr ,
& caps_stop_attribute . attr ,
& freq_attribute . attr ,
2010-10-15 04:23:57 +04:00
/* &lang_attribute.attr, */
2010-10-07 22:20:02 +04:00
& pitch_attribute . attr ,
2020-04-25 22:32:26 +03:00
& inflection_attribute . attr ,
2010-10-07 22:20:02 +04:00
& punct_attribute . attr ,
& rate_attribute . attr ,
& tone_attribute . attr ,
& voice_attribute . attr ,
& vol_attribute . attr ,
& delay_time_attribute . attr ,
& direct_attribute . attr ,
& full_time_attribute . attr ,
& jiffy_delta_attribute . attr ,
& trigger_time_attribute . attr ,
NULL , /* need to NULL terminate the list of attributes */
} ;
static struct spk_synth synth_soft = {
. name = " soft " ,
. version = DRV_VERSION ,
. long_name = " software synth " ,
. init = " \01 @ \x01 \x31 y \n " ,
. procspeech = PROCSPEECH ,
. delay = 0 ,
. trigger = 0 ,
. jiffies = 0 ,
. full = 0 ,
. startup = SYNTH_START ,
. checkval = SYNTH_CHECK ,
. vars = vars ,
2017-03-14 16:41:53 +03:00
. io_ops = NULL ,
2010-10-07 22:20:02 +04:00
. probe = softsynth_probe ,
. release = softsynth_release ,
. synth_immediate = NULL ,
. catch_up = NULL ,
. flush = NULL ,
. is_alive = softsynth_is_alive ,
2022-08-24 01:25:03 +03:00
. synth_adjust = softsynth_adjust ,
2010-10-07 22:20:02 +04:00
. read_buff_add = NULL ,
. get_index = get_index ,
. indexing = {
. command = " \x01 %di " ,
. lowindex = 1 ,
. highindex = 5 ,
. currindex = 1 ,
} ,
. attributes = {
. attrs = synth_attrs ,
. name = " soft " ,
} ,
} ;
static char * get_initstring ( void )
{
static char buf [ 40 ] ;
char * cp ;
struct var_t * var ;
2021-07-01 01:42:48 +03:00
size_t len ;
size_t n ;
2010-10-07 22:20:02 +04:00
memset ( buf , 0 , sizeof ( buf ) ) ;
cp = buf ;
2021-07-01 01:42:48 +03:00
len = sizeof ( buf ) ;
2010-10-07 22:20:02 +04:00
var = synth_soft . vars ;
while ( var - > var_id ! = MAXVARS ) {
2016-11-21 18:19:21 +03:00
if ( var - > var_id ! = CAPS_START & & var - > var_id ! = CAPS_STOP & &
2021-07-01 01:42:48 +03:00
var - > var_id ! = PAUSE & & var - > var_id ! = DIRECT ) {
n = scnprintf ( cp , len , var - > u . n . synth_fmt ,
var - > u . n . value ) ;
cp = cp + n ;
len = len - n ;
}
2010-10-07 22:20:02 +04:00
var + + ;
}
2021-07-01 01:42:48 +03:00
cp = cp + scnprintf ( cp , len , " \n " ) ;
2010-10-07 22:20:02 +04:00
return buf ;
}
static int softsynth_open ( struct inode * inode , struct file * fp )
{
unsigned long flags ;
/*if ((fp->f_flags & O_ACCMODE) != O_RDONLY) */
/* return -EPERM; */
2013-05-13 22:31:39 +04:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 22:20:02 +04:00
if ( synth_soft . alive ) {
2013-05-13 22:31:39 +04:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 22:20:02 +04:00
return - EBUSY ;
}
synth_soft . alive = 1 ;
2013-05-13 22:31:39 +04:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 22:20:02 +04:00
return 0 ;
}
static int softsynth_close ( struct inode * inode , struct file * fp )
{
unsigned long flags ;
2014-09-09 22:04:34 +04:00
2013-05-13 22:31:39 +04:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 22:20:02 +04:00
synth_soft . alive = 0 ;
2012-09-16 07:18:50 +04:00
init_pos = 0 ;
2013-05-13 22:31:39 +04:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 22:20:02 +04:00
/* Make sure we let applications go before leaving */
speakup_start_ttys ( ) ;
return 0 ;
}
2017-03-04 17:01:57 +03:00
static ssize_t softsynthx_read ( struct file * fp , char __user * buf , size_t count ,
loff_t * pos , int unicode )
2010-10-07 22:20:02 +04:00
{
int chars_sent = 0 ;
2013-05-22 22:53:09 +04:00
char __user * cp ;
2010-10-07 22:20:02 +04:00
char * init ;
2018-07-13 01:29:36 +03:00
size_t bytes_per_ch = unicode ? 3 : 1 ;
2017-03-04 17:01:57 +03:00
u16 ch ;
2010-10-07 22:20:02 +04:00
int empty ;
unsigned long flags ;
DEFINE_WAIT ( wait ) ;
2018-07-13 01:29:36 +03:00
if ( count < bytes_per_ch )
return - EINVAL ;
2013-05-13 22:31:39 +04:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2019-03-08 01:06:57 +03:00
synth_soft . alive = 1 ;
2010-10-07 22:20:02 +04:00
while ( 1 ) {
prepare_to_wait ( & speakup_event , & wait , TASK_INTERRUPTIBLE ) ;
2019-03-08 01:06:57 +03:00
if ( synth_current ( ) = = & synth_soft ) {
if ( ! unicode )
synth_buffer_skip_nonlatin1 ( ) ;
if ( ! synth_buffer_empty ( ) | | speakup_info . flushing )
break ;
}
2013-05-13 22:31:39 +04:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 22:20:02 +04:00
if ( fp - > f_flags & O_NONBLOCK ) {
finish_wait ( & speakup_event , & wait ) ;
return - EAGAIN ;
}
if ( signal_pending ( current ) ) {
finish_wait ( & speakup_event , & wait ) ;
return - ERESTARTSYS ;
}
schedule ( ) ;
2013-05-13 22:31:39 +04:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 22:20:02 +04:00
}
finish_wait ( & speakup_event , & wait ) ;
cp = buf ;
init = get_initstring ( ) ;
2017-03-04 17:01:57 +03:00
/* Keep 3 bytes available for a 16bit UTF-8-encoded character */
2018-07-13 01:29:36 +03:00
while ( chars_sent < = count - bytes_per_ch ) {
2019-03-08 01:06:57 +03:00
if ( synth_current ( ) ! = & synth_soft )
break ;
2010-10-07 22:20:02 +04:00
if ( speakup_info . flushing ) {
speakup_info . flushing = 0 ;
ch = ' \x18 ' ;
2012-09-16 07:18:50 +04:00
} else if ( init [ init_pos ] ) {
ch = init [ init_pos + + ] ;
2010-10-07 22:20:02 +04:00
} else {
2017-03-04 17:01:57 +03:00
if ( ! unicode )
synth_buffer_skip_nonlatin1 ( ) ;
if ( synth_buffer_empty ( ) )
break ;
2010-10-07 22:20:02 +04:00
ch = synth_buffer_getc ( ) ;
}
2013-05-13 22:31:39 +04:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2017-03-04 17:01:57 +03:00
if ( ( ! unicode & & ch < 0x100 ) | | ( unicode & & ch < 0x80 ) ) {
u_char c = ch ;
if ( copy_to_user ( cp , & c , 1 ) )
return - EFAULT ;
chars_sent + + ;
cp + + ;
} else if ( unicode & & ch < 0x800 ) {
u_char s [ 2 ] = {
0xc0 | ( ch > > 6 ) ,
0x80 | ( ch & 0x3f )
} ;
if ( copy_to_user ( cp , s , sizeof ( s ) ) )
return - EFAULT ;
chars_sent + = sizeof ( s ) ;
cp + = sizeof ( s ) ;
} else if ( unicode ) {
u_char s [ 3 ] = {
0xe0 | ( ch > > 12 ) ,
0x80 | ( ( ch > > 6 ) & 0x3f ) ,
0x80 | ( ch & 0x3f )
} ;
if ( copy_to_user ( cp , s , sizeof ( s ) ) )
return - EFAULT ;
chars_sent + = sizeof ( s ) ;
cp + = sizeof ( s ) ;
}
2013-05-13 22:31:39 +04:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 22:20:02 +04:00
}
* pos + = chars_sent ;
empty = synth_buffer_empty ( ) ;
2013-05-13 22:31:39 +04:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 22:20:02 +04:00
if ( empty ) {
speakup_start_ttys ( ) ;
* pos = 0 ;
}
return chars_sent ;
}
2017-03-04 17:01:57 +03:00
static ssize_t softsynth_read ( struct file * fp , char __user * buf , size_t count ,
loff_t * pos )
{
return softsynthx_read ( fp , buf , count , pos , 0 ) ;
}
static ssize_t softsynthu_read ( struct file * fp , char __user * buf , size_t count ,
loff_t * pos )
{
return softsynthx_read ( fp , buf , count , pos , 1 ) ;
}
2010-10-15 04:23:57 +04:00
static int last_index ;
2010-10-07 22:20:02 +04:00
2013-05-22 22:53:09 +04:00
static ssize_t softsynth_write ( struct file * fp , const char __user * buf ,
size_t count , loff_t * pos )
2010-10-07 22:20:02 +04:00
{
2010-10-15 04:23:57 +04:00
unsigned long supplied_index = 0 ;
int converted ;
2010-10-07 22:20:02 +04:00
2011-06-06 23:32:32 +04:00
converted = kstrtoul_from_user ( buf , count , 0 , & supplied_index ) ;
2010-10-15 04:23:57 +04:00
if ( converted < 0 )
return converted ;
2010-10-07 22:20:02 +04:00
2010-10-15 04:23:57 +04:00
last_index = supplied_index ;
2010-10-07 22:20:02 +04:00
return count ;
}
2017-07-03 13:39:46 +03:00
static __poll_t softsynth_poll ( struct file * fp , struct poll_table_struct * wait )
2010-10-07 22:20:02 +04:00
{
unsigned long flags ;
2017-07-03 13:39:46 +03:00
__poll_t ret = 0 ;
2014-09-09 22:04:34 +04:00
2010-10-07 22:20:02 +04:00
poll_wait ( fp , & speakup_event , wait ) ;
2013-05-13 22:31:39 +04:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2019-03-08 01:06:57 +03:00
if ( synth_current ( ) = = & synth_soft & &
( ! synth_buffer_empty ( ) | | speakup_info . flushing ) )
2018-02-12 01:34:03 +03:00
ret = EPOLLIN | EPOLLRDNORM ;
2013-05-13 22:31:39 +04:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 22:20:02 +04:00
return ret ;
}
2017-04-29 22:52:58 +03:00
static unsigned char get_index ( struct spk_synth * synth )
2010-10-07 22:20:02 +04:00
{
int rv ;
2014-09-09 22:04:34 +04:00
2010-10-07 22:20:02 +04:00
rv = last_index ;
last_index = 0 ;
return rv ;
}
2010-10-15 04:23:57 +04:00
static const struct file_operations softsynth_fops = {
2010-10-07 22:20:02 +04:00
. owner = THIS_MODULE ,
. poll = softsynth_poll ,
. read = softsynth_read ,
. write = softsynth_write ,
. open = softsynth_open ,
. release = softsynth_close ,
} ;
2017-03-04 17:01:57 +03:00
static const struct file_operations softsynthu_fops = {
. owner = THIS_MODULE ,
. poll = softsynth_poll ,
. read = softsynthu_read ,
. write = softsynth_write ,
. open = softsynth_open ,
. release = softsynth_close ,
} ;
2010-10-07 22:20:02 +04:00
static int softsynth_probe ( struct spk_synth * synth )
{
if ( misc_registered ! = 0 )
return 0 ;
memset ( & synth_device , 0 , sizeof ( synth_device ) ) ;
2020-03-25 06:30:08 +03:00
synth_device . minor = MISC_DYNAMIC_MINOR ;
2010-10-07 22:20:02 +04:00
synth_device . name = " softsynth " ;
synth_device . fops = & softsynth_fops ;
if ( misc_register ( & synth_device ) ) {
pr_warn ( " Couldn't initialize miscdevice /dev/softsynth. \n " ) ;
return - ENODEV ;
}
2017-03-04 17:01:57 +03:00
memset ( & synthu_device , 0 , sizeof ( synthu_device ) ) ;
2020-03-25 06:30:08 +03:00
synthu_device . minor = MISC_DYNAMIC_MINOR ;
2017-03-04 17:01:57 +03:00
synthu_device . name = " softsynthu " ;
synthu_device . fops = & softsynthu_fops ;
if ( misc_register ( & synthu_device ) ) {
2022-05-11 06:29:37 +03:00
misc_deregister ( & synth_device ) ;
2020-03-05 10:21:51 +03:00
pr_warn ( " Couldn't initialize miscdevice /dev/softsynthu. \n " ) ;
2017-03-04 17:01:57 +03:00
return - ENODEV ;
}
2010-10-07 22:20:02 +04:00
misc_registered = 1 ;
2020-03-25 06:30:08 +03:00
pr_info ( " initialized device: /dev/softsynth, node (MAJOR 10, MINOR %d) \n " ,
synth_device . minor ) ;
pr_info ( " initialized device: /dev/softsynthu, node (MAJOR 10, MINOR %d) \n " ,
synthu_device . minor ) ;
2010-10-07 22:20:02 +04:00
return 0 ;
}
2021-01-27 01:21:44 +03:00
static void softsynth_release ( struct spk_synth * synth )
2010-10-07 22:20:02 +04:00
{
misc_deregister ( & synth_device ) ;
2017-03-04 17:01:57 +03:00
misc_deregister ( & synthu_device ) ;
2010-10-07 22:20:02 +04:00
misc_registered = 0 ;
pr_info ( " unregistered /dev/softsynth \n " ) ;
2017-03-04 17:01:57 +03:00
pr_info ( " unregistered /dev/softsynthu \n " ) ;
2010-10-07 22:20:02 +04:00
}
static int softsynth_is_alive ( struct spk_synth * synth )
{
if ( synth_soft . alive )
return 1 ;
return 0 ;
}
2022-08-24 01:25:03 +03:00
static int softsynth_adjust ( struct spk_synth * synth , struct st_var_header * var )
{
struct st_var_header * punc_level_var ;
struct var_t * var_data ;
if ( var - > var_id ! = PUNC_LEVEL )
return 0 ;
/* We want to set the the speech synthesis punctuation level
* accordingly , so it properly tunes speaking A_PUNC characters */
var_data = var - > data ;
if ( ! var_data )
return 0 ;
punc_level_var = spk_get_var_header ( PUNCT ) ;
if ( ! punc_level_var )
return 0 ;
spk_set_num_var ( var_data - > u . n . value , punc_level_var , E_SET ) ;
return 1 ;
}
2017-01-28 09:35:01 +03:00
module_param_named ( start , synth_soft . startup , short , 0444 ) ;
2022-11-10 00:50:54 +03:00
module_param_named ( direct , vars [ DIRECT_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( rate , vars [ RATE_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( pitch , vars [ PITCH_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( inflection , vars [ INFLECTION_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( vol , vars [ VOL_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( tone , vars [ TONE_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( punct , vars [ PUNCT_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( voice , vars [ VOICE_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( frequency , vars [ FREQUENCY_ID ] . u . n . default_val , int , 0444 ) ;
2010-10-07 22:20:02 +04:00
MODULE_PARM_DESC ( start , " Start the synthesizer once it is loaded. " ) ;
2022-08-29 23:36:25 +03:00
MODULE_PARM_DESC ( direct , " Set the direct variable on load. " ) ;
2022-11-10 00:50:54 +03:00
MODULE_PARM_DESC ( rate , " Sets the rate of the synthesizer. " ) ;
MODULE_PARM_DESC ( pitch , " Sets the pitch of the synthesizer. " ) ;
MODULE_PARM_DESC ( inflection , " Sets the inflection of the synthesizer. " ) ;
MODULE_PARM_DESC ( vol , " Sets the volume of the speech synthesizer. " ) ;
MODULE_PARM_DESC ( tone , " Sets the tone of the speech synthesizer. " ) ;
MODULE_PARM_DESC ( punct , " Sets the amount of punctuation spoken by the synthesizer. " ) ;
MODULE_PARM_DESC ( voice , " Sets the voice used by the synthesizer. " ) ;
MODULE_PARM_DESC ( frequency , " Sets the frequency of speech synthesizer. " ) ;
2010-10-07 22:20:02 +04:00
2015-03-18 20:43:10 +03:00
module_spk_synth ( synth_soft ) ;
2010-10-07 22:20:02 +04:00
MODULE_AUTHOR ( " Kirk Reiser <kirk@braille.uwo.ca> " ) ;
MODULE_DESCRIPTION ( " Speakup userspace software synthesizer support " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( DRV_VERSION ) ;