0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/jiffies.h>
0015 #include <linux/sched.h>
0016 #include <linux/timer.h>
0017 #include <linux/kthread.h>
0018
0019 #include "spk_priv.h"
0020 #include "serialio.h"
0021 #include "speakup.h"
0022 #include "speakup_acnt.h" /* local header file for Accent values */
0023
0024 #define DRV_VERSION "2.10"
0025 #define PROCSPEECH '\r'
0026
0027 static int synth_probe(struct spk_synth *synth);
0028 static void accent_release(struct spk_synth *synth);
0029 static const char *synth_immediate(struct spk_synth *synth, const char *buf);
0030 static void do_catch_up(struct spk_synth *synth);
0031 static void synth_flush(struct spk_synth *synth);
0032
0033 static int synth_port_control;
0034 static int port_forced;
0035 static unsigned int synth_portlist[] = { 0x2a8, 0 };
0036
0037 static struct var_t vars[] = {
0038 { CAPS_START, .u.s = {"\033P8" } },
0039 { CAPS_STOP, .u.s = {"\033P5" } },
0040 { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" } },
0041 { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL } },
0042 { VOL, .u.n = {"\033A%d", 5, 0, 9, 0, 0, NULL } },
0043 { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL } },
0044 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
0045 V_LAST_VAR
0046 };
0047
0048
0049
0050
0051 static struct kobj_attribute caps_start_attribute =
0052 __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
0053 static struct kobj_attribute caps_stop_attribute =
0054 __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
0055 static struct kobj_attribute pitch_attribute =
0056 __ATTR(pitch, 0644, spk_var_show, spk_var_store);
0057 static struct kobj_attribute rate_attribute =
0058 __ATTR(rate, 0644, spk_var_show, spk_var_store);
0059 static struct kobj_attribute tone_attribute =
0060 __ATTR(tone, 0644, spk_var_show, spk_var_store);
0061 static struct kobj_attribute vol_attribute =
0062 __ATTR(vol, 0644, spk_var_show, spk_var_store);
0063
0064 static struct kobj_attribute delay_time_attribute =
0065 __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
0066 static struct kobj_attribute direct_attribute =
0067 __ATTR(direct, 0644, spk_var_show, spk_var_store);
0068 static struct kobj_attribute full_time_attribute =
0069 __ATTR(full_time, 0644, spk_var_show, spk_var_store);
0070 static struct kobj_attribute jiffy_delta_attribute =
0071 __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
0072 static struct kobj_attribute trigger_time_attribute =
0073 __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
0074
0075
0076
0077
0078
0079 static struct attribute *synth_attrs[] = {
0080 &caps_start_attribute.attr,
0081 &caps_stop_attribute.attr,
0082 &pitch_attribute.attr,
0083 &rate_attribute.attr,
0084 &tone_attribute.attr,
0085 &vol_attribute.attr,
0086 &delay_time_attribute.attr,
0087 &direct_attribute.attr,
0088 &full_time_attribute.attr,
0089 &jiffy_delta_attribute.attr,
0090 &trigger_time_attribute.attr,
0091 NULL,
0092 };
0093
0094 static struct spk_synth synth_acntpc = {
0095 .name = "acntpc",
0096 .version = DRV_VERSION,
0097 .long_name = "Accent PC",
0098 .init = "\033=X \033Oi\033T2\033=M\033N1\n",
0099 .procspeech = PROCSPEECH,
0100 .clear = SYNTH_CLEAR,
0101 .delay = 500,
0102 .trigger = 50,
0103 .jiffies = 50,
0104 .full = 1000,
0105 .startup = SYNTH_START,
0106 .checkval = SYNTH_CHECK,
0107 .vars = vars,
0108 .io_ops = &spk_serial_io_ops,
0109 .probe = synth_probe,
0110 .release = accent_release,
0111 .synth_immediate = synth_immediate,
0112 .catch_up = do_catch_up,
0113 .flush = synth_flush,
0114 .is_alive = spk_synth_is_alive_nop,
0115 .synth_adjust = NULL,
0116 .read_buff_add = NULL,
0117 .get_index = NULL,
0118 .indexing = {
0119 .command = NULL,
0120 .lowindex = 0,
0121 .highindex = 0,
0122 .currindex = 0,
0123 },
0124 .attributes = {
0125 .attrs = synth_attrs,
0126 .name = "acntpc",
0127 },
0128 };
0129
0130 static inline bool synth_writable(void)
0131 {
0132 return inb_p(synth_port_control) & SYNTH_WRITABLE;
0133 }
0134
0135 static inline bool synth_full(void)
0136 {
0137 return inb_p(speakup_info.port_tts + UART_RX) == 'F';
0138 }
0139
0140 static const char *synth_immediate(struct spk_synth *synth, const char *buf)
0141 {
0142 u_char ch;
0143
0144 while ((ch = *buf)) {
0145 int timeout = SPK_XMITR_TIMEOUT;
0146
0147 if (ch == '\n')
0148 ch = PROCSPEECH;
0149 if (synth_full())
0150 return buf;
0151 while (synth_writable()) {
0152 if (!--timeout)
0153 return buf;
0154 udelay(1);
0155 }
0156 outb_p(ch, speakup_info.port_tts);
0157 buf++;
0158 }
0159 return NULL;
0160 }
0161
0162 static void do_catch_up(struct spk_synth *synth)
0163 {
0164 u_char ch;
0165 unsigned long flags;
0166 unsigned long jiff_max;
0167 int timeout;
0168 int delay_time_val;
0169 int jiffy_delta_val;
0170 int full_time_val;
0171 struct var_t *delay_time;
0172 struct var_t *full_time;
0173 struct var_t *jiffy_delta;
0174
0175 jiffy_delta = spk_get_var(JIFFY);
0176 delay_time = spk_get_var(DELAY);
0177 full_time = spk_get_var(FULL);
0178
0179 spin_lock_irqsave(&speakup_info.spinlock, flags);
0180 jiffy_delta_val = jiffy_delta->u.n.value;
0181 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0182
0183 jiff_max = jiffies + jiffy_delta_val;
0184 while (!kthread_should_stop()) {
0185 spin_lock_irqsave(&speakup_info.spinlock, flags);
0186 if (speakup_info.flushing) {
0187 speakup_info.flushing = 0;
0188 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0189 synth->flush(synth);
0190 continue;
0191 }
0192 synth_buffer_skip_nonlatin1();
0193 if (synth_buffer_empty()) {
0194 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0195 break;
0196 }
0197 set_current_state(TASK_INTERRUPTIBLE);
0198 full_time_val = full_time->u.n.value;
0199 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0200 if (synth_full()) {
0201 schedule_timeout(msecs_to_jiffies(full_time_val));
0202 continue;
0203 }
0204 set_current_state(TASK_RUNNING);
0205 timeout = SPK_XMITR_TIMEOUT;
0206 while (synth_writable()) {
0207 if (!--timeout)
0208 break;
0209 udelay(1);
0210 }
0211 spin_lock_irqsave(&speakup_info.spinlock, flags);
0212 ch = synth_buffer_getc();
0213 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0214 if (ch == '\n')
0215 ch = PROCSPEECH;
0216 outb_p(ch, speakup_info.port_tts);
0217 if (time_after_eq(jiffies, jiff_max) && ch == SPACE) {
0218 timeout = SPK_XMITR_TIMEOUT;
0219 while (synth_writable()) {
0220 if (!--timeout)
0221 break;
0222 udelay(1);
0223 }
0224 outb_p(PROCSPEECH, speakup_info.port_tts);
0225 spin_lock_irqsave(&speakup_info.spinlock, flags);
0226 jiffy_delta_val = jiffy_delta->u.n.value;
0227 delay_time_val = delay_time->u.n.value;
0228 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0229 schedule_timeout(msecs_to_jiffies(delay_time_val));
0230 jiff_max = jiffies + jiffy_delta_val;
0231 }
0232 }
0233 timeout = SPK_XMITR_TIMEOUT;
0234 while (synth_writable()) {
0235 if (!--timeout)
0236 break;
0237 udelay(1);
0238 }
0239 outb_p(PROCSPEECH, speakup_info.port_tts);
0240 }
0241
0242 static void synth_flush(struct spk_synth *synth)
0243 {
0244 outb_p(SYNTH_CLEAR, speakup_info.port_tts);
0245 }
0246
0247 static int synth_probe(struct spk_synth *synth)
0248 {
0249 unsigned int port_val = 0;
0250 int i;
0251
0252 pr_info("Probing for %s.\n", synth->long_name);
0253 if (port_forced) {
0254 speakup_info.port_tts = port_forced;
0255 pr_info("probe forced to %x by kernel command line\n",
0256 speakup_info.port_tts);
0257 if (synth_request_region(speakup_info.port_tts - 1,
0258 SYNTH_IO_EXTENT)) {
0259 pr_warn("sorry, port already reserved\n");
0260 return -EBUSY;
0261 }
0262 port_val = inw(speakup_info.port_tts - 1);
0263 synth_port_control = speakup_info.port_tts - 1;
0264 } else {
0265 for (i = 0; synth_portlist[i]; i++) {
0266 if (synth_request_region(synth_portlist[i],
0267 SYNTH_IO_EXTENT)) {
0268 pr_warn
0269 ("request_region: failed with 0x%x, %d\n",
0270 synth_portlist[i], SYNTH_IO_EXTENT);
0271 continue;
0272 }
0273 port_val = inw(synth_portlist[i]) & 0xfffc;
0274 if (port_val == 0x53fc) {
0275
0276 synth_port_control = synth_portlist[i];
0277 speakup_info.port_tts = synth_port_control + 1;
0278 break;
0279 }
0280 }
0281 }
0282 port_val &= 0xfffc;
0283 if (port_val != 0x53fc) {
0284
0285 pr_info("%s: not found\n", synth->long_name);
0286 synth_release_region(synth_port_control, SYNTH_IO_EXTENT);
0287 synth_port_control = 0;
0288 return -ENODEV;
0289 }
0290 pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name,
0291 synth_port_control, synth_port_control + SYNTH_IO_EXTENT - 1,
0292 synth->version);
0293 synth->alive = 1;
0294 return 0;
0295 }
0296
0297 static void accent_release(struct spk_synth *synth)
0298 {
0299 spk_stop_serial_interrupt();
0300 if (speakup_info.port_tts)
0301 synth_release_region(speakup_info.port_tts - 1,
0302 SYNTH_IO_EXTENT);
0303 speakup_info.port_tts = 0;
0304 }
0305
0306 module_param_hw_named(port, port_forced, int, ioport, 0444);
0307 module_param_named(start, synth_acntpc.startup, short, 0444);
0308
0309 MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
0310 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
0311
0312 module_spk_synth(synth_acntpc);
0313
0314 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
0315 MODULE_AUTHOR("David Borowski");
0316 MODULE_DESCRIPTION("Speakup support for Accent PC synthesizer");
0317 MODULE_LICENSE("GPL");
0318 MODULE_VERSION(DRV_VERSION);
0319