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