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 = 62d901aaa723a7ea4601b0984534dde70adc81a38cRusty Russell __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store); 63c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct kobj_attribute caps_stop_attribute = 64d901aaa723a7ea4601b0984534dde70adc81a38cRusty Russell __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store); 65c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct kobj_attribute pitch_attribute = 66d901aaa723a7ea4601b0984534dde70adc81a38cRusty Russell __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store); 67c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct kobj_attribute rate_attribute = 68d901aaa723a7ea4601b0984534dde70adc81a38cRusty Russell __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store); 69c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 70c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct kobj_attribute delay_time_attribute = 7122c9bcad859d5c969289b3b37084a96c621f8f2cRusty Russell __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store); 72c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct kobj_attribute direct_attribute = 73d901aaa723a7ea4601b0984534dde70adc81a38cRusty Russell __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store); 74c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct kobj_attribute full_time_attribute = 7522c9bcad859d5c969289b3b37084a96c621f8f2cRusty Russell __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store); 76c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct kobj_attribute jiffy_delta_attribute = 7722c9bcad859d5c969289b3b37084a96c621f8f2cRusty Russell __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store); 78c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct kobj_attribute trigger_time_attribute = 7922c9bcad859d5c969289b3b37084a96c621f8f2cRusty Russell __ATTR(trigger_time, S_IWUSR|S_IRUGO, 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; 1468e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan 147c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs s1 = inb_p(synth_port); 148c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs s2 = inb_p(synth_port+1); 149c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs s3 = inb_p(synth_port+2); 150c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs s4 = inb_p(synth_port+3); 151c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs pr_warn("synth timeout %d %d %d %d\n", s1, s2, s3, s4); 152c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs return NULL; 153c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs} 154c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 155c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic const char *synth_immediate(struct spk_synth *synth, const char *buf) 156c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{ 157c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs u_char ch; 158c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs int timeout; 1598e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan 160c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs while ((ch = *buf)) { 161c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (ch == '\n') 162c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs ch = PROCSPEECH; 163c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (synth_full()) 164c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs return buf; 165c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs timeout = 1000; 166c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs while (synth_writable()) 167c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (--timeout <= 0) 168c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs return oops(); 169c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs outb_p(ch, synth_port); 170c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs udelay(70); 171c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs buf++; 172c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 1730a0bd35518a9c14b73b93dce1c3aa18d496879d7Sachin Kamat return NULL; 174c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs} 175c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 176c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_catch_up(struct spk_synth *synth) 177c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{ 178c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs u_char ch; 179c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs int timeout; 180c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs unsigned long flags; 181c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs unsigned long jiff_max; 182c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs struct var_t *jiffy_delta; 183c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs struct var_t *delay_time; 184c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs struct var_t *full_time; 185c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs int delay_time_val; 186c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs int full_time_val; 187c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs int jiffy_delta_val; 188c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 189ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault jiffy_delta = spk_get_var(JIFFY); 190ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault delay_time = spk_get_var(DELAY); 191ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault full_time = spk_get_var(FULL); 192e6f1838373f14c7b062c092e42d0ba8dac175472William Hubbsspin_lock_irqsave(&speakup_info.spinlock, flags); 193c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs jiffy_delta_val = jiffy_delta->u.n.value; 194e6f1838373f14c7b062c092e42d0ba8dac175472William Hubbs spin_unlock_irqrestore(&speakup_info.spinlock, flags); 195c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 196c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs jiff_max = jiffies + jiffy_delta_val; 197c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs while (!kthread_should_stop()) { 198e6f1838373f14c7b062c092e42d0ba8dac175472William Hubbs spin_lock_irqsave(&speakup_info.spinlock, flags); 199c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (speakup_info.flushing) { 200c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs speakup_info.flushing = 0; 201e6f1838373f14c7b062c092e42d0ba8dac175472William Hubbs spin_unlock_irqrestore(&speakup_info.spinlock, flags); 202c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth->flush(synth); 203c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs continue; 204c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 205c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (synth_buffer_empty()) { 206e6f1838373f14c7b062c092e42d0ba8dac175472William Hubbs spin_unlock_irqrestore(&speakup_info.spinlock, flags); 207c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs break; 208c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 209c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs set_current_state(TASK_INTERRUPTIBLE); 210c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs full_time_val = full_time->u.n.value; 211e6f1838373f14c7b062c092e42d0ba8dac175472William Hubbs spin_unlock_irqrestore(&speakup_info.spinlock, flags); 212c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (synth_full()) { 213c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs schedule_timeout(msecs_to_jiffies(full_time_val)); 214c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs continue; 215c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 216c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs set_current_state(TASK_RUNNING); 217c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs timeout = 1000; 218c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs while (synth_writable()) 219c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (--timeout <= 0) 220c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs break; 221c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (timeout <= 0) { 222c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs oops(); 223c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs break; 224c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 225e6f1838373f14c7b062c092e42d0ba8dac175472William Hubbs spin_lock_irqsave(&speakup_info.spinlock, flags); 226c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs ch = synth_buffer_getc(); 227e6f1838373f14c7b062c092e42d0ba8dac175472William Hubbs spin_unlock_irqrestore(&speakup_info.spinlock, flags); 228c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (ch == '\n') 229c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs ch = PROCSPEECH; 230c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs outb_p(ch, synth_port); 231c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs SWAIT; 232c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if ((jiffies >= jiff_max) && (ch == SPACE)) { 233c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs timeout = 1000; 234c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs while (synth_writable()) 235c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (--timeout <= 0) 236c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs break; 237c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (timeout <= 0) { 238c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs oops(); 239c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs break; 240c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 241c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs outb_p(PROCSPEECH, synth_port); 242e6f1838373f14c7b062c092e42d0ba8dac175472William Hubbs spin_lock_irqsave(&speakup_info.spinlock, flags); 243c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs jiffy_delta_val = jiffy_delta->u.n.value; 244c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs delay_time_val = delay_time->u.n.value; 245e6f1838373f14c7b062c092e42d0ba8dac175472William Hubbs spin_unlock_irqrestore(&speakup_info.spinlock, flags); 246c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs schedule_timeout(msecs_to_jiffies(delay_time_val)); 247c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs jiff_max = jiffies+jiffy_delta_val; 248c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 249c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 250c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs timeout = 1000; 251c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs while (synth_writable()) 252c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (--timeout <= 0) 253c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs break; 254c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (timeout <= 0) 255c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs oops(); 256c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs else 257c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs outb_p(PROCSPEECH, synth_port); 258c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs} 259c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 260c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void synth_flush(struct spk_synth *synth) 261c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{ 262c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs outb_p(SYNTH_CLEAR, synth_port); 263c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs} 264c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 265c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int synth_probe(struct spk_synth *synth) 266c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{ 267c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs unsigned int port_val = 0; 268c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs int i = 0; 2698e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan 270c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs pr_info("Probing for %s.\n", synth->long_name); 271c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (port_forced) { 272c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth_port = port_forced; 273c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs pr_info("probe forced to %x by kernel command line\n", 274c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth_port); 275c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (synth_request_region(synth_port-1, SYNTH_IO_EXTENT)) { 276c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs pr_warn("sorry, port already reserved\n"); 277c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs return -EBUSY; 278c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 279c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs port_val = inb(synth_port); 280c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } else { 281c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs for (i = 0; synth_portlist[i]; i++) { 282c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (synth_request_region(synth_portlist[i], 283c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs SYNTH_IO_EXTENT)) { 28475d6282d8b2d58b4722e63225f3951e1c9b0ebf8Christopher Brannon pr_warn 28575d6282d8b2d58b4722e63225f3951e1c9b0ebf8Christopher Brannon ("request_region: failed with 0x%x, %d\n", 28675d6282d8b2d58b4722e63225f3951e1c9b0ebf8Christopher Brannon synth_portlist[i], SYNTH_IO_EXTENT); 287c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs continue; 288c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 289c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs port_val = inb(synth_portlist[i]); 290c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (port_val == 0x80) { 291c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth_port = synth_portlist[i]; 292c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs break; 293c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 294c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 295c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 296c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (port_val != 0x80) { 297c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs pr_info("%s: not found\n", synth->long_name); 298c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth_release_region(synth_port, SYNTH_IO_EXTENT); 299c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth_port = 0; 300c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs return -ENODEV; 301c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs } 302c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name, 303c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth_port, synth_port+SYNTH_IO_EXTENT-1, 304c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth->version); 305c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth->alive = 1; 306c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs return 0; 307c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs} 308c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 309c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void keynote_release(void) 310c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{ 311c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs if (synth_port) 312c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth_release_region(synth_port, SYNTH_IO_EXTENT); 313c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth_port = 0; 314c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs} 315c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 316c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_param_named(port, port_forced, int, S_IRUGO); 317c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_param_named(start, synth_keypc.startup, short, S_IRUGO); 318c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 319c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing)."); 320c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); 321c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 322c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int __init keypc_init(void) 323c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{ 324c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs return synth_add(&synth_keypc); 325c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs} 326c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 327c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void __exit keypc_exit(void) 328c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{ 329c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs synth_remove(&synth_keypc); 330c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs} 331c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 332c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_init(keypc_init); 333c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_exit(keypc_exit); 334c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_AUTHOR("David Borowski"); 335c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_DESCRIPTION("Speakup support for Keynote Gold PC synthesizers"); 336c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_LICENSE("GPL"); 337c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_VERSION(DRV_VERSION); 338c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs 339