linux/drivers/staging/speakup/speakup_keypc.c
<<
>>
Prefs
   1/*
   2 * written by David Borowski
   3 *
   4 * Copyright (C) 2003 David Borowski.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * specificly written as a driver for the speakup screenreview
  17 * package it's not a general device driver.
  18 * This driver is for the Keynote Gold internal synthesizer.
  19 */
  20#include <linux/jiffies.h>
  21#include <linux/sched.h>
  22#include <linux/timer.h>
  23#include <linux/kthread.h>
  24#include <linux/serial_reg.h>
  25
  26#include "spk_priv.h"
  27#include "speakup.h"
  28
  29#define DRV_VERSION "2.10"
  30#define SYNTH_IO_EXTENT 0x04
  31#define SWAIT udelay(70)
  32#define PROCSPEECH 0x1f
  33#define SYNTH_CLEAR 0x03
  34
  35static int synth_probe(struct spk_synth *synth);
  36static void keynote_release(void);
  37static const char *synth_immediate(struct spk_synth *synth, const char *buf);
  38static void do_catch_up(struct spk_synth *synth);
  39static void synth_flush(struct spk_synth *synth);
  40
  41static int synth_port;
  42static int port_forced;
  43static unsigned int synth_portlist[] = { 0x2a8, 0 };
  44
  45static struct var_t vars[] = {
  46        { CAPS_START, .u.s = {"[f130]" } },
  47        { CAPS_STOP, .u.s = {"[f90]" } },
  48        { RATE, .u.n = {"\04%c ", 8, 0, 10, 81, -8, NULL } },
  49        { PITCH, .u.n = {"[f%d]", 5, 0, 9, 40, 10, NULL } },
  50        { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
  51        V_LAST_VAR
  52};
  53
  54/*
  55 * These attributes will appear in /sys/accessibility/speakup/keypc.
  56 */
  57static struct kobj_attribute caps_start_attribute =
  58        __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
  59static struct kobj_attribute caps_stop_attribute =
  60        __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
  61static struct kobj_attribute pitch_attribute =
  62        __ATTR(pitch, 0644, spk_var_show, spk_var_store);
  63static struct kobj_attribute rate_attribute =
  64        __ATTR(rate, 0644, spk_var_show, spk_var_store);
  65
  66static struct kobj_attribute delay_time_attribute =
  67        __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
  68static struct kobj_attribute direct_attribute =
  69        __ATTR(direct, 0644, spk_var_show, spk_var_store);
  70static struct kobj_attribute full_time_attribute =
  71        __ATTR(full_time, 0644, spk_var_show, spk_var_store);
  72static struct kobj_attribute jiffy_delta_attribute =
  73        __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
  74static struct kobj_attribute trigger_time_attribute =
  75        __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
  76
  77/*
  78 * Create a group of attributes so that we can create and destroy them all
  79 * at once.
  80 */
  81static struct attribute *synth_attrs[] = {
  82        &caps_start_attribute.attr,
  83        &caps_stop_attribute.attr,
  84        &pitch_attribute.attr,
  85        &rate_attribute.attr,
  86        &delay_time_attribute.attr,
  87        &direct_attribute.attr,
  88        &full_time_attribute.attr,
  89        &jiffy_delta_attribute.attr,
  90        &trigger_time_attribute.attr,
  91        NULL,   /* need to NULL terminate the list of attributes */
  92};
  93
  94static struct spk_synth synth_keypc = {
  95        .name = "keypc",
  96        .version = DRV_VERSION,
  97        .long_name = "Keynote PC",
  98        .init = "[t][n7,1][n8,0]",
  99        .procspeech = PROCSPEECH,
 100        .clear = SYNTH_CLEAR,
 101        .delay = 500,
 102        .trigger = 50,
 103        .jiffies = 50,
 104        .full = 1000,
 105        .startup = SYNTH_START,
 106        .checkval = SYNTH_CHECK,
 107        .vars = vars,
 108        .io_ops = &spk_serial_io_ops,
 109        .probe = synth_probe,
 110        .release = keynote_release,
 111        .synth_immediate = synth_immediate,
 112        .catch_up = do_catch_up,
 113        .flush = synth_flush,
 114        .is_alive = spk_synth_is_alive_nop,
 115        .synth_adjust = NULL,
 116        .read_buff_add = NULL,
 117        .get_index = NULL,
 118        .indexing = {
 119                .command = NULL,
 120                .lowindex = 0,
 121                .highindex = 0,
 122                .currindex = 0,
 123        },
 124        .attributes = {
 125                .attrs = synth_attrs,
 126                .name = "keypc",
 127        },
 128};
 129
 130static inline bool synth_writable(void)
 131{
 132        return (inb_p(synth_port + UART_RX) & 0x10) != 0;
 133}
 134
 135static inline bool synth_full(void)
 136{
 137        return (inb_p(synth_port + UART_RX) & 0x80) == 0;
 138}
 139
 140static char *oops(void)
 141{
 142        int s1, s2, s3, s4;
 143
 144        s1 = inb_p(synth_port);
 145        s2 = inb_p(synth_port + 1);
 146        s3 = inb_p(synth_port + 2);
 147        s4 = inb_p(synth_port + 3);
 148        pr_warn("synth timeout %d %d %d %d\n", s1, s2, s3, s4);
 149        return NULL;
 150}
 151
 152static const char *synth_immediate(struct spk_synth *synth, const char *buf)
 153{
 154        u_char ch;
 155        int timeout;
 156
 157        while ((ch = *buf)) {
 158                if (ch == '\n')
 159                        ch = PROCSPEECH;
 160                if (synth_full())
 161                        return buf;
 162                timeout = 1000;
 163                while (synth_writable())
 164                        if (--timeout <= 0)
 165                                return oops();
 166                outb_p(ch, synth_port);
 167                udelay(70);
 168                buf++;
 169        }
 170        return NULL;
 171}
 172
 173static void do_catch_up(struct spk_synth *synth)
 174{
 175        u_char ch;
 176        int timeout;
 177        unsigned long flags;
 178        unsigned long jiff_max;
 179        struct var_t *jiffy_delta;
 180        struct var_t *delay_time;
 181        struct var_t *full_time;
 182        int delay_time_val;
 183        int full_time_val;
 184        int jiffy_delta_val;
 185
 186        jiffy_delta = spk_get_var(JIFFY);
 187        delay_time = spk_get_var(DELAY);
 188        full_time = spk_get_var(FULL);
 189spin_lock_irqsave(&speakup_info.spinlock, flags);
 190        jiffy_delta_val = jiffy_delta->u.n.value;
 191        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 192
 193        jiff_max = jiffies + jiffy_delta_val;
 194        while (!kthread_should_stop()) {
 195                spin_lock_irqsave(&speakup_info.spinlock, flags);
 196                if (speakup_info.flushing) {
 197                        speakup_info.flushing = 0;
 198                        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 199                        synth->flush(synth);
 200                        continue;
 201                }
 202                synth_buffer_skip_nonlatin1();
 203                if (synth_buffer_empty()) {
 204                        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 205                        break;
 206                }
 207                set_current_state(TASK_INTERRUPTIBLE);
 208                full_time_val = full_time->u.n.value;
 209                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 210                if (synth_full()) {
 211                        schedule_timeout(msecs_to_jiffies(full_time_val));
 212                        continue;
 213                }
 214                set_current_state(TASK_RUNNING);
 215                timeout = 1000;
 216                while (synth_writable())
 217                        if (--timeout <= 0)
 218                                break;
 219                if (timeout <= 0) {
 220                        oops();
 221                        break;
 222                }
 223                spin_lock_irqsave(&speakup_info.spinlock, flags);
 224                ch = synth_buffer_getc();
 225                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 226                if (ch == '\n')
 227                        ch = PROCSPEECH;
 228                outb_p(ch, synth_port);
 229                SWAIT;
 230                if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
 231                        timeout = 1000;
 232                        while (synth_writable())
 233                                if (--timeout <= 0)
 234                                        break;
 235                        if (timeout <= 0) {
 236                                oops();
 237                                break;
 238                        }
 239                        outb_p(PROCSPEECH, synth_port);
 240                        spin_lock_irqsave(&speakup_info.spinlock, flags);
 241                        jiffy_delta_val = jiffy_delta->u.n.value;
 242                        delay_time_val = delay_time->u.n.value;
 243                        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 244                        schedule_timeout(msecs_to_jiffies(delay_time_val));
 245                        jiff_max = jiffies+jiffy_delta_val;
 246                }
 247        }
 248        timeout = 1000;
 249        while (synth_writable())
 250                if (--timeout <= 0)
 251                        break;
 252        if (timeout <= 0)
 253                oops();
 254        else
 255                outb_p(PROCSPEECH, synth_port);
 256}
 257
 258static void synth_flush(struct spk_synth *synth)
 259{
 260        outb_p(SYNTH_CLEAR, synth_port);
 261}
 262
 263static int synth_probe(struct spk_synth *synth)
 264{
 265        unsigned int port_val = 0;
 266        int i = 0;
 267
 268        pr_info("Probing for %s.\n", synth->long_name);
 269        if (port_forced) {
 270                synth_port = port_forced;
 271                pr_info("probe forced to %x by kernel command line\n",
 272                                synth_port);
 273                if (synth_request_region(synth_port-1, SYNTH_IO_EXTENT)) {
 274                        pr_warn("sorry, port already reserved\n");
 275                        return -EBUSY;
 276                }
 277                port_val = inb(synth_port);
 278        } else {
 279                for (i = 0; synth_portlist[i]; i++) {
 280                        if (synth_request_region(synth_portlist[i],
 281                                                SYNTH_IO_EXTENT)) {
 282                                pr_warn
 283                                    ("request_region: failed with 0x%x, %d\n",
 284                                     synth_portlist[i], SYNTH_IO_EXTENT);
 285                                continue;
 286                        }
 287                        port_val = inb(synth_portlist[i]);
 288                        if (port_val == 0x80) {
 289                                synth_port = synth_portlist[i];
 290                                break;
 291                        }
 292                }
 293        }
 294        if (port_val != 0x80) {
 295                pr_info("%s: not found\n", synth->long_name);
 296                synth_release_region(synth_port, SYNTH_IO_EXTENT);
 297                synth_port = 0;
 298                return -ENODEV;
 299        }
 300        pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name,
 301                synth_port, synth_port+SYNTH_IO_EXTENT-1,
 302                synth->version);
 303        synth->alive = 1;
 304        return 0;
 305}
 306
 307static void keynote_release(void)
 308{
 309        spk_stop_serial_interrupt();
 310        if (synth_port)
 311                synth_release_region(synth_port, SYNTH_IO_EXTENT);
 312        synth_port = 0;
 313}
 314
 315module_param_hw_named(port, port_forced, int, ioport, 0444);
 316module_param_named(start, synth_keypc.startup, short, 0444);
 317
 318MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
 319MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
 320
 321module_spk_synth(synth_keypc);
 322
 323MODULE_AUTHOR("David Borowski");
 324MODULE_DESCRIPTION("Speakup support for Keynote Gold PC synthesizers");
 325MODULE_LICENSE("GPL");
 326MODULE_VERSION(DRV_VERSION);
 327
 328