linux/drivers/staging/speakup/synth.c
<<
>>
Prefs
   1#include <linux/types.h>
   2#include <linux/ctype.h>        /* for isdigit() and friends */
   3#include <linux/fs.h>
   4#include <linux/mm.h>           /* for verify_area */
   5#include <linux/errno.h>        /* for -EBUSY */
   6#include <linux/ioport.h>       /* for check_region, request_region */
   7#include <linux/interrupt.h>
   8#include <linux/delay.h>        /* for loops_per_sec */
   9#include <linux/kmod.h>
  10#include <linux/jiffies.h>
  11#include <linux/uaccess.h> /* for copy_from_user */
  12#include <linux/sched.h>
  13#include <linux/timer.h>
  14#include <linux/kthread.h>
  15
  16#include "spk_priv.h"
  17#include "speakup.h"
  18#include "serialio.h"
  19
  20#define MAXSYNTHS       16      /* Max number of synths in array. */
  21static struct spk_synth *synths[MAXSYNTHS];
  22struct spk_synth *synth;
  23char pitch_buff[32] = "";
  24static int module_status;
  25int quiet_boot;
  26
  27struct speakup_info_t speakup_info = {
  28        .spinlock = __SPIN_LOCK_UNLOCKED(speakup_info.spinlock),
  29        .flushing = 0,
  30};
  31EXPORT_SYMBOL_GPL(speakup_info);
  32
  33static int do_synth_init(struct spk_synth *in_synth);
  34
  35int serial_synth_probe(struct spk_synth *synth)
  36{
  37        struct serial_state *ser;
  38        int failed = 0;
  39
  40        if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) {
  41                ser = spk_serial_init(synth->ser);
  42                if (ser == NULL) {
  43                        failed = -1;
  44                } else {
  45                        outb_p(0, ser->port);
  46                        mdelay(1);
  47                        outb_p('\r', ser->port);
  48                }
  49        } else {
  50                failed = -1;
  51                pr_warn("ttyS%i is an invalid port\n", synth->ser);
  52        }
  53        if (failed) {
  54                pr_info("%s: not found\n", synth->long_name);
  55                return -ENODEV;
  56        }
  57        pr_info("%s: ttyS%i, Driver Version %s\n",
  58                        synth->long_name, synth->ser, synth->version);
  59        synth->alive = 1;
  60        return 0;
  61}
  62EXPORT_SYMBOL_GPL(serial_synth_probe);
  63
  64/* Main loop of the progression thread: keep eating from the buffer
  65 * and push to the serial port, waiting as needed
  66 *
  67 * For devices that have a "full" notification mecanism, the driver can
  68 * adapt the loop the way they prefer.
  69 */
  70void spk_do_catch_up(struct spk_synth *synth)
  71{
  72        u_char ch;
  73        unsigned long flags;
  74        unsigned long jiff_max;
  75        struct var_t *delay_time;
  76        struct var_t *full_time;
  77        struct var_t *jiffy_delta;
  78        int jiffy_delta_val;
  79        int delay_time_val;
  80        int full_time_val;
  81
  82        jiffy_delta = get_var(JIFFY);
  83        full_time = get_var(FULL);
  84        delay_time = get_var(DELAY);
  85
  86        spk_lock(flags);
  87        jiffy_delta_val = jiffy_delta->u.n.value;
  88        spk_unlock(flags);
  89
  90        jiff_max = jiffies + jiffy_delta_val;
  91        while (!kthread_should_stop()) {
  92                spk_lock(flags);
  93                if (speakup_info.flushing) {
  94                        speakup_info.flushing = 0;
  95                        spk_unlock(flags);
  96                        synth->flush(synth);
  97                        continue;
  98                }
  99                if (synth_buffer_empty()) {
 100                        spk_unlock(flags);
 101                        break;
 102                }
 103                ch = synth_buffer_peek();
 104                set_current_state(TASK_INTERRUPTIBLE);
 105                full_time_val = full_time->u.n.value;
 106                spk_unlock(flags);
 107                if (ch == '\n')
 108                        ch = synth->procspeech;
 109                if (!spk_serial_out(ch)) {
 110                        schedule_timeout(msecs_to_jiffies(full_time_val));
 111                        continue;
 112                }
 113                if ((jiffies >= jiff_max) && (ch == SPACE)) {
 114                        spk_lock(flags);
 115                        jiffy_delta_val = jiffy_delta->u.n.value;
 116                        delay_time_val = delay_time->u.n.value;
 117                        full_time_val = full_time->u.n.value;
 118                        spk_unlock(flags);
 119                        if (spk_serial_out(synth->procspeech))
 120                                schedule_timeout(
 121                                        msecs_to_jiffies(delay_time_val));
 122                        else
 123                                schedule_timeout(
 124                                        msecs_to_jiffies(full_time_val));
 125                        jiff_max = jiffies + jiffy_delta_val;
 126                }
 127                set_current_state(TASK_RUNNING);
 128                spk_lock(flags);
 129                synth_buffer_getc();
 130                spk_unlock(flags);
 131        }
 132        spk_serial_out(synth->procspeech);
 133}
 134EXPORT_SYMBOL_GPL(spk_do_catch_up);
 135
 136const char *spk_synth_immediate(struct spk_synth *synth, const char *buff)
 137{
 138        u_char ch;
 139        while ((ch = *buff)) {
 140                if (ch == '\n')
 141                        ch = synth->procspeech;
 142                if (wait_for_xmitr())
 143                        outb(ch, speakup_info.port_tts);
 144                else
 145                        return buff;
 146                buff++;
 147        }
 148        return 0;
 149}
 150EXPORT_SYMBOL_GPL(spk_synth_immediate);
 151
 152void spk_synth_flush(struct spk_synth *synth)
 153{
 154        spk_serial_out(synth->clear);
 155}
 156EXPORT_SYMBOL_GPL(spk_synth_flush);
 157
 158int spk_synth_is_alive_nop(struct spk_synth *synth)
 159{
 160        synth->alive = 1;
 161        return 1;
 162}
 163EXPORT_SYMBOL_GPL(spk_synth_is_alive_nop);
 164
 165int spk_synth_is_alive_restart(struct spk_synth *synth)
 166{
 167        if (synth->alive)
 168                return 1;
 169        if (!synth->alive && wait_for_xmitr() > 0) {
 170                /* restart */
 171                synth->alive = 1;
 172                synth_printf("%s", synth->init);
 173                return 2; /* reenabled */
 174        }
 175        pr_warn("%s: can't restart synth\n", synth->long_name);
 176        return 0;
 177}
 178EXPORT_SYMBOL_GPL(spk_synth_is_alive_restart);
 179
 180static void thread_wake_up(u_long data)
 181{
 182        wake_up_interruptible_all(&speakup_event);
 183}
 184
 185static DEFINE_TIMER(thread_timer, thread_wake_up, 0, 0);
 186
 187void synth_start(void)
 188{
 189        struct var_t *trigger_time;
 190
 191        if (!synth->alive) {
 192                synth_buffer_clear();
 193                return;
 194        }
 195        trigger_time = get_var(TRIGGER);
 196        if (!timer_pending(&thread_timer))
 197                mod_timer(&thread_timer, jiffies +
 198                        msecs_to_jiffies(trigger_time->u.n.value));
 199}
 200
 201void do_flush(void)
 202{
 203        speakup_info.flushing = 1;
 204        synth_buffer_clear();
 205        if (synth->alive) {
 206                if (pitch_shift) {
 207                        synth_printf("%s", pitch_buff);
 208                        pitch_shift = 0;
 209                }
 210        }
 211        wake_up_interruptible_all(&speakup_event);
 212        wake_up_process(speakup_task);
 213}
 214
 215void synth_write(const char *buf, size_t count)
 216{
 217        while (count--)
 218                synth_buffer_add(*buf++);
 219        synth_start();
 220}
 221
 222void synth_printf(const char *fmt, ...)
 223{
 224        va_list args;
 225        unsigned char buf[160], *p;
 226        int r;
 227
 228        va_start(args, fmt);
 229        r = vsnprintf(buf, sizeof(buf), fmt, args);
 230        va_end(args);
 231        if (r > sizeof(buf) - 1)
 232                r = sizeof(buf) - 1;
 233
 234        p = buf;
 235        while (r--)
 236                synth_buffer_add(*p++);
 237        synth_start();
 238}
 239EXPORT_SYMBOL_GPL(synth_printf);
 240
 241static int index_count;
 242static int sentence_count;
 243
 244void reset_index_count(int sc)
 245{
 246        static int first = 1;
 247        if (first)
 248                first = 0;
 249        else
 250                synth->get_index();
 251        index_count = 0;
 252        sentence_count = sc;
 253}
 254
 255int synth_supports_indexing(void)
 256{
 257        if (synth->get_index != NULL)
 258                return 1;
 259        return 0;
 260}
 261
 262void synth_insert_next_index(int sent_num)
 263{
 264        int out;
 265        if (synth->alive) {
 266                if (sent_num == 0) {
 267                        synth->indexing.currindex++;
 268                        index_count++;
 269                        if (synth->indexing.currindex >
 270                                        synth->indexing.highindex)
 271                                synth->indexing.currindex =
 272                                        synth->indexing.lowindex;
 273                }
 274
 275                out = synth->indexing.currindex * 10 + sent_num;
 276                synth_printf(synth->indexing.command, out, out);
 277        }
 278}
 279
 280void get_index_count(int *linecount, int *sentcount)
 281{
 282        int ind = synth->get_index();
 283        if (ind) {
 284                sentence_count = ind % 10;
 285
 286                if ((ind / 10) <= synth->indexing.currindex)
 287                        index_count = synth->indexing.currindex-(ind/10);
 288                else
 289                        index_count = synth->indexing.currindex
 290                                -synth->indexing.lowindex
 291                                + synth->indexing.highindex-(ind/10)+1;
 292
 293        }
 294        *sentcount = sentence_count;
 295        *linecount = index_count;
 296}
 297
 298static struct resource synth_res;
 299
 300int synth_request_region(unsigned long start, unsigned long n)
 301{
 302        struct resource *parent = &ioport_resource;
 303        memset(&synth_res, 0, sizeof(synth_res));
 304        synth_res.name = synth->name;
 305        synth_res.start = start;
 306        synth_res.end = start + n - 1;
 307        synth_res.flags = IORESOURCE_BUSY;
 308        return request_resource(parent, &synth_res);
 309}
 310EXPORT_SYMBOL_GPL(synth_request_region);
 311
 312int synth_release_region(unsigned long start, unsigned long n)
 313{
 314        return release_resource(&synth_res);
 315}
 316EXPORT_SYMBOL_GPL(synth_release_region);
 317
 318struct var_t synth_time_vars[] = {
 319        { DELAY, .u.n = {NULL, 100, 100, 2000, 0, 0, NULL } },
 320        { TRIGGER, .u.n = {NULL, 20, 10, 2000, 0, 0, NULL } },
 321        { JIFFY, .u.n = {NULL, 50, 20, 200, 0, 0, NULL } },
 322        { FULL, .u.n = {NULL, 400, 200, 60000, 0, 0, NULL } },
 323        V_LAST_VAR
 324};
 325
 326/* called by: speakup_init() */
 327int synth_init(char *synth_name)
 328{
 329        int i;
 330        int ret = 0;
 331        struct spk_synth *synth = NULL;
 332
 333        if (synth_name == NULL)
 334                return 0;
 335
 336        if (strcmp(synth_name, "none") == 0) {
 337                mutex_lock(&spk_mutex);
 338                synth_release();
 339                mutex_unlock(&spk_mutex);
 340                return 0;
 341        }
 342
 343        mutex_lock(&spk_mutex);
 344        /* First, check if we already have it loaded. */
 345        for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++)
 346                if (strcmp(synths[i]->name, synth_name) == 0)
 347                        synth = synths[i];
 348
 349        /* If we got one, initialize it now. */
 350        if (synth)
 351                ret = do_synth_init(synth);
 352        else
 353                ret = -ENODEV;
 354        mutex_unlock(&spk_mutex);
 355
 356        return ret;
 357}
 358
 359/* called by: synth_add() */
 360static int do_synth_init(struct spk_synth *in_synth)
 361{
 362        struct var_t *var;
 363
 364        synth_release();
 365        if (in_synth->checkval != SYNTH_CHECK)
 366                return -EINVAL;
 367        synth = in_synth;
 368        synth->alive = 0;
 369        pr_warn("synth probe\n");
 370        if (synth->probe(synth) < 0) {
 371                pr_warn("%s: device probe failed\n", in_synth->name);
 372                synth = NULL;
 373                return -ENODEV;
 374        }
 375        synth_time_vars[0].u.n.value =
 376                synth_time_vars[0].u.n.default_val = synth->delay;
 377        synth_time_vars[1].u.n.value =
 378                synth_time_vars[1].u.n.default_val = synth->trigger;
 379        synth_time_vars[2].u.n.value =
 380                synth_time_vars[2].u.n.default_val = synth->jiffies;
 381        synth_time_vars[3].u.n.value =
 382                synth_time_vars[3].u.n.default_val = synth->full;
 383        synth_printf("%s", synth->init);
 384        for (var = synth->vars;
 385                (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
 386                speakup_register_var(var);
 387        if (!quiet_boot)
 388                synth_printf("%s found\n", synth->long_name);
 389        if (synth->attributes.name
 390        && sysfs_create_group(speakup_kobj, &(synth->attributes)) < 0)
 391                return -ENOMEM;
 392        synth_flags = synth->flags;
 393        wake_up_interruptible_all(&speakup_event);
 394        if (speakup_task)
 395                wake_up_process(speakup_task);
 396        return 0;
 397}
 398
 399void synth_release(void)
 400{
 401        struct var_t *var;
 402        unsigned long flags;
 403
 404        if (synth == NULL)
 405                return;
 406        spk_lock(flags);
 407        pr_info("releasing synth %s\n", synth->name);
 408        synth->alive = 0;
 409        del_timer(&thread_timer);
 410        spk_unlock(flags);
 411        if (synth->attributes.name)
 412                sysfs_remove_group(speakup_kobj, &(synth->attributes));
 413        for (var = synth->vars; var->var_id != MAXVARS; var++)
 414                speakup_unregister_var(var->var_id);
 415        stop_serial_interrupt();
 416        synth->release();
 417        synth = NULL;
 418}
 419
 420/* called by: all_driver_init() */
 421int synth_add(struct spk_synth *in_synth)
 422{
 423        int i;
 424        int status = 0;
 425        mutex_lock(&spk_mutex);
 426        for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++)
 427                /* synth_remove() is responsible for rotating the array down */
 428                if (in_synth == synths[i]) {
 429                        mutex_unlock(&spk_mutex);
 430                        return 0;
 431                }
 432        if (i == MAXSYNTHS) {
 433                pr_warn("Error: attempting to add a synth past end of array\n");
 434                mutex_unlock(&spk_mutex);
 435                return -1;
 436        }
 437        synths[i++] = in_synth;
 438        synths[i] = NULL;
 439        if (in_synth->startup)
 440                status = do_synth_init(in_synth);
 441        mutex_unlock(&spk_mutex);
 442        return status;
 443}
 444EXPORT_SYMBOL_GPL(synth_add);
 445
 446void synth_remove(struct spk_synth *in_synth)
 447{
 448        int i;
 449        mutex_lock(&spk_mutex);
 450        if (synth == in_synth)
 451                synth_release();
 452        for (i = 0; synths[i] != NULL; i++) {
 453                if (in_synth == synths[i])
 454                        break;
 455        }
 456        for ( ; synths[i] != NULL; i++) /* compress table */
 457                synths[i] = synths[i+1];
 458        module_status = 0;
 459        mutex_unlock(&spk_mutex);
 460}
 461EXPORT_SYMBOL_GPL(synth_remove);
 462
 463short punc_masks[] = { 0, SOME, MOST, PUNC, PUNC|B_SYM };
 464