headers: remove sched.h from poll.h
[safe/jmp/linux-2.6] / drivers / char / dtlk.c
1 /*                                              -*- linux-c -*-
2  * dtlk.c - DoubleTalk PC driver for Linux
3  *
4  * Original author: Chris Pallotta <chris@allmedia.com>
5  * Current maintainer: Jim Van Zandt <jrv@vanzandt.mv.com>
6  * 
7  * 2000-03-18 Jim Van Zandt: Fix polling.
8  *  Eliminate dtlk_timer_active flag and separate dtlk_stop_timer
9  *  function.  Don't restart timer in dtlk_timer_tick.  Restart timer
10  *  in dtlk_poll after every poll.  dtlk_poll returns mask (duh).
11  *  Eliminate unused function dtlk_write_byte.  Misc. code cleanups.
12  */
13
14 /* This driver is for the DoubleTalk PC, a speech synthesizer
15    manufactured by RC Systems (http://www.rcsys.com/).  It was written
16    based on documentation in their User's Manual file and Developer's
17    Tools disk.
18
19    The DoubleTalk PC contains four voice synthesizers: text-to-speech
20    (TTS), linear predictive coding (LPC), PCM/ADPCM, and CVSD.  It
21    also has a tone generator.  Output data for LPC are written to the
22    LPC port, and output data for the other modes are written to the
23    TTS port.
24
25    Two kinds of data can be read from the DoubleTalk: status
26    information (in response to the "\001?" interrogation command) is
27    read from the TTS port, and index markers (which mark the progress
28    of the speech) are read from the LPC port.  Not all models of the
29    DoubleTalk PC implement index markers.  Both the TTS and LPC ports
30    can also display status flags.
31
32    The DoubleTalk PC generates no interrupts.
33
34    These characteristics are mapped into the Unix stream I/O model as
35    follows:
36
37    "write" sends bytes to the TTS port.  It is the responsibility of
38    the user program to switch modes among TTS, PCM/ADPCM, and CVSD.
39    This driver was written for use with the text-to-speech
40    synthesizer.  If LPC output is needed some day, other minor device
41    numbers can be used to select among output modes.
42
43    "read" gets index markers from the LPC port.  If the device does
44    not implement index markers, the read will fail with error EINVAL.
45
46    Status information is available using the DTLK_INTERROGATE ioctl.
47
48  */
49
50 #include <linux/module.h>
51
52 #define KERNEL
53 #include <linux/types.h>
54 #include <linux/fs.h>
55 #include <linux/mm.h>
56 #include <linux/errno.h>        /* for -EBUSY */
57 #include <linux/ioport.h>       /* for request_region */
58 #include <linux/delay.h>        /* for loops_per_jiffy */
59 #include <linux/sched.h>
60 #include <linux/smp_lock.h>     /* cycle_kernel_lock() */
61 #include <asm/io.h>             /* for inb_p, outb_p, inb, outb, etc. */
62 #include <asm/uaccess.h>        /* for get_user, etc. */
63 #include <linux/wait.h>         /* for wait_queue */
64 #include <linux/init.h>         /* for __init, module_{init,exit} */
65 #include <linux/poll.h>         /* for POLLIN, etc. */
66 #include <linux/dtlk.h>         /* local header file for DoubleTalk values */
67
68 #ifdef TRACING
69 #define TRACE_TEXT(str) printk(str);
70 #define TRACE_RET printk(")")
71 #else                           /* !TRACING */
72 #define TRACE_TEXT(str) ((void) 0)
73 #define TRACE_RET ((void) 0)
74 #endif                          /* TRACING */
75
76 static void dtlk_timer_tick(unsigned long data);
77
78 static int dtlk_major;
79 static int dtlk_port_lpc;
80 static int dtlk_port_tts;
81 static int dtlk_busy;
82 static int dtlk_has_indexing;
83 static unsigned int dtlk_portlist[] =
84 {0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0};
85 static wait_queue_head_t dtlk_process_list;
86 static DEFINE_TIMER(dtlk_timer, dtlk_timer_tick, 0, 0);
87
88 /* prototypes for file_operations struct */
89 static ssize_t dtlk_read(struct file *, char __user *,
90                          size_t nbytes, loff_t * ppos);
91 static ssize_t dtlk_write(struct file *, const char __user *,
92                           size_t nbytes, loff_t * ppos);
93 static unsigned int dtlk_poll(struct file *, poll_table *);
94 static int dtlk_open(struct inode *, struct file *);
95 static int dtlk_release(struct inode *, struct file *);
96 static int dtlk_ioctl(struct inode *inode, struct file *file,
97                       unsigned int cmd, unsigned long arg);
98
99 static const struct file_operations dtlk_fops =
100 {
101         .owner          = THIS_MODULE,
102         .read           = dtlk_read,
103         .write          = dtlk_write,
104         .poll           = dtlk_poll,
105         .ioctl          = dtlk_ioctl,
106         .open           = dtlk_open,
107         .release        = dtlk_release,
108 };
109
110 /* local prototypes */
111 static int dtlk_dev_probe(void);
112 static struct dtlk_settings *dtlk_interrogate(void);
113 static int dtlk_readable(void);
114 static char dtlk_read_lpc(void);
115 static char dtlk_read_tts(void);
116 static int dtlk_writeable(void);
117 static char dtlk_write_bytes(const char *buf, int n);
118 static char dtlk_write_tts(char);
119 /*
120    static void dtlk_handle_error(char, char, unsigned int);
121  */
122
123 static ssize_t dtlk_read(struct file *file, char __user *buf,
124                          size_t count, loff_t * ppos)
125 {
126         unsigned int minor = iminor(file->f_path.dentry->d_inode);
127         char ch;
128         int i = 0, retries;
129
130         TRACE_TEXT("(dtlk_read");
131         /*  printk("DoubleTalk PC - dtlk_read()\n"); */
132
133         if (minor != DTLK_MINOR || !dtlk_has_indexing)
134                 return -EINVAL;
135
136         for (retries = 0; retries < loops_per_jiffy; retries++) {
137                 while (i < count && dtlk_readable()) {
138                         ch = dtlk_read_lpc();
139                         /*        printk("dtlk_read() reads 0x%02x\n", ch); */
140                         if (put_user(ch, buf++))
141                                 return -EFAULT;
142                         i++;
143                 }
144                 if (i)
145                         return i;
146                 if (file->f_flags & O_NONBLOCK)
147                         break;
148                 msleep_interruptible(100);
149         }
150         if (retries == loops_per_jiffy)
151                 printk(KERN_ERR "dtlk_read times out\n");
152         TRACE_RET;
153         return -EAGAIN;
154 }
155
156 static ssize_t dtlk_write(struct file *file, const char __user *buf,
157                           size_t count, loff_t * ppos)
158 {
159         int i = 0, retries = 0, ch;
160
161         TRACE_TEXT("(dtlk_write");
162 #ifdef TRACING
163         printk(" \"");
164         {
165                 int i, ch;
166                 for (i = 0; i < count; i++) {
167                         if (get_user(ch, buf + i))
168                                 return -EFAULT;
169                         if (' ' <= ch && ch <= '~')
170                                 printk("%c", ch);
171                         else
172                                 printk("\\%03o", ch);
173                 }
174                 printk("\"");
175         }
176 #endif
177
178         if (iminor(file->f_path.dentry->d_inode) != DTLK_MINOR)
179                 return -EINVAL;
180
181         while (1) {
182                 while (i < count && !get_user(ch, buf) &&
183                        (ch == DTLK_CLEAR || dtlk_writeable())) {
184                         dtlk_write_tts(ch);
185                         buf++;
186                         i++;
187                         if (i % 5 == 0)
188                                 /* We yield our time until scheduled
189                                    again.  This reduces the transfer
190                                    rate to 500 bytes/sec, but that's
191                                    still enough to keep up with the
192                                    speech synthesizer. */
193                                 msleep_interruptible(1);
194                         else {
195                                 /* the RDY bit goes zero 2-3 usec
196                                    after writing, and goes 1 again
197                                    180-190 usec later.  Here, we wait
198                                    up to 250 usec for the RDY bit to
199                                    go nonzero. */
200                                 for (retries = 0;
201                                      retries < loops_per_jiffy / (4000/HZ);
202                                      retries++)
203                                         if (inb_p(dtlk_port_tts) &
204                                             TTS_WRITABLE)
205                                                 break;
206                         }
207                         retries = 0;
208                 }
209                 if (i == count)
210                         return i;
211                 if (file->f_flags & O_NONBLOCK)
212                         break;
213
214                 msleep_interruptible(1);
215
216                 if (++retries > 10 * HZ) { /* wait no more than 10 sec
217                                               from last write */
218                         printk("dtlk: write timeout.  "
219                                "inb_p(dtlk_port_tts) = 0x%02x\n",
220                                inb_p(dtlk_port_tts));
221                         TRACE_RET;
222                         return -EBUSY;
223                 }
224         }
225         TRACE_RET;
226         return -EAGAIN;
227 }
228
229 static unsigned int dtlk_poll(struct file *file, poll_table * wait)
230 {
231         int mask = 0;
232         unsigned long expires;
233
234         TRACE_TEXT(" dtlk_poll");
235         /*
236            static long int j;
237            printk(".");
238            printk("<%ld>", jiffies-j);
239            j=jiffies;
240          */
241         poll_wait(file, &dtlk_process_list, wait);
242
243         if (dtlk_has_indexing && dtlk_readable()) {
244                 del_timer(&dtlk_timer);
245                 mask = POLLIN | POLLRDNORM;
246         }
247         if (dtlk_writeable()) {
248                 del_timer(&dtlk_timer);
249                 mask |= POLLOUT | POLLWRNORM;
250         }
251         /* there are no exception conditions */
252
253         /* There won't be any interrupts, so we set a timer instead. */
254         expires = jiffies + 3*HZ / 100;
255         mod_timer(&dtlk_timer, expires);
256
257         return mask;
258 }
259
260 static void dtlk_timer_tick(unsigned long data)
261 {
262         TRACE_TEXT(" dtlk_timer_tick");
263         wake_up_interruptible(&dtlk_process_list);
264 }
265
266 static int dtlk_ioctl(struct inode *inode,
267                       struct file *file,
268                       unsigned int cmd,
269                       unsigned long arg)
270 {
271         char __user *argp = (char __user *)arg;
272         struct dtlk_settings *sp;
273         char portval;
274         TRACE_TEXT(" dtlk_ioctl");
275
276         switch (cmd) {
277
278         case DTLK_INTERROGATE:
279                 sp = dtlk_interrogate();
280                 if (copy_to_user(argp, sp, sizeof(struct dtlk_settings)))
281                         return -EINVAL;
282                 return 0;
283
284         case DTLK_STATUS:
285                 portval = inb_p(dtlk_port_tts);
286                 return put_user(portval, argp);
287
288         default:
289                 return -EINVAL;
290         }
291 }
292
293 /* Note that nobody ever sets dtlk_busy... */
294 static int dtlk_open(struct inode *inode, struct file *file)
295 {
296         TRACE_TEXT("(dtlk_open");
297
298         cycle_kernel_lock();
299         nonseekable_open(inode, file);
300         switch (iminor(inode)) {
301         case DTLK_MINOR:
302                 if (dtlk_busy)
303                         return -EBUSY;
304                 return nonseekable_open(inode, file);
305
306         default:
307                 return -ENXIO;
308         }
309 }
310
311 static int dtlk_release(struct inode *inode, struct file *file)
312 {
313         TRACE_TEXT("(dtlk_release");
314
315         switch (iminor(inode)) {
316         case DTLK_MINOR:
317                 break;
318
319         default:
320                 break;
321         }
322         TRACE_RET;
323         
324         del_timer_sync(&dtlk_timer);
325
326         return 0;
327 }
328
329 static int __init dtlk_init(void)
330 {
331         int err;
332
333         dtlk_port_lpc = 0;
334         dtlk_port_tts = 0;
335         dtlk_busy = 0;
336         dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops);
337         if (dtlk_major < 0) {
338                 printk(KERN_ERR "DoubleTalk PC - cannot register device\n");
339                 return dtlk_major;
340         }
341         err = dtlk_dev_probe();
342         if (err) {
343                 unregister_chrdev(dtlk_major, "dtlk");
344                 return err;
345         }
346         printk(", MAJOR %d\n", dtlk_major);
347
348         init_waitqueue_head(&dtlk_process_list);
349
350         return 0;
351 }
352
353 static void __exit dtlk_cleanup (void)
354 {
355         dtlk_write_bytes("goodbye", 8);
356         msleep_interruptible(500);              /* nap 0.50 sec but
357                                                    could be awakened
358                                                    earlier by
359                                                    signals... */
360
361         dtlk_write_tts(DTLK_CLEAR);
362         unregister_chrdev(dtlk_major, "dtlk");
363         release_region(dtlk_port_lpc, DTLK_IO_EXTENT);
364 }
365
366 module_init(dtlk_init);
367 module_exit(dtlk_cleanup);
368
369 /* ------------------------------------------------------------------------ */
370
371 static int dtlk_readable(void)
372 {
373 #ifdef TRACING
374         printk(" dtlk_readable=%u@%u", inb_p(dtlk_port_lpc) != 0x7f, jiffies);
375 #endif
376         return inb_p(dtlk_port_lpc) != 0x7f;
377 }
378
379 static int dtlk_writeable(void)
380 {
381         /* TRACE_TEXT(" dtlk_writeable"); */
382 #ifdef TRACINGMORE
383         printk(" dtlk_writeable=%u", (inb_p(dtlk_port_tts) & TTS_WRITABLE)!=0);
384 #endif
385         return inb_p(dtlk_port_tts) & TTS_WRITABLE;
386 }
387
388 static int __init dtlk_dev_probe(void)
389 {
390         unsigned int testval = 0;
391         int i = 0;
392         struct dtlk_settings *sp;
393
394         if (dtlk_port_lpc | dtlk_port_tts)
395                 return -EBUSY;
396
397         for (i = 0; dtlk_portlist[i]; i++) {
398 #if 0
399                 printk("DoubleTalk PC - Port %03x = %04x\n",
400                        dtlk_portlist[i], (testval = inw_p(dtlk_portlist[i])));
401 #endif
402
403                 if (!request_region(dtlk_portlist[i], DTLK_IO_EXTENT, 
404                                "dtlk"))
405                         continue;
406                 testval = inw_p(dtlk_portlist[i]);
407                 if ((testval &= 0xfbff) == 0x107f) {
408                         dtlk_port_lpc = dtlk_portlist[i];
409                         dtlk_port_tts = dtlk_port_lpc + 1;
410
411                         sp = dtlk_interrogate();
412                         printk("DoubleTalk PC at %03x-%03x, "
413                                "ROM version %s, serial number %u",
414                                dtlk_portlist[i], dtlk_portlist[i] +
415                                DTLK_IO_EXTENT - 1,
416                                sp->rom_version, sp->serial_number);
417
418                         /* put LPC port into known state, so
419                            dtlk_readable() gives valid result */
420                         outb_p(0xff, dtlk_port_lpc); 
421
422                         /* INIT string and index marker */
423                         dtlk_write_bytes("\036\1@\0\0012I\r", 8);
424                         /* posting an index takes 18 msec.  Here, we
425                            wait up to 100 msec to see whether it
426                            appears. */
427                         msleep_interruptible(100);
428                         dtlk_has_indexing = dtlk_readable();
429 #ifdef TRACING
430                         printk(", indexing %d\n", dtlk_has_indexing);
431 #endif
432 #ifdef INSCOPE
433                         {
434 /* This macro records ten samples read from the LPC port, for later display */
435 #define LOOK                                    \
436 for (i = 0; i < 10; i++)                        \
437   {                                             \
438     buffer[b++] = inb_p(dtlk_port_lpc);         \
439     __delay(loops_per_jiffy/(1000000/HZ));             \
440   }
441                                 char buffer[1000];
442                                 int b = 0, i, j;
443
444                                 LOOK
445                                 outb_p(0xff, dtlk_port_lpc);
446                                 buffer[b++] = 0;
447                                 LOOK
448                                 dtlk_write_bytes("\0012I\r", 4);
449                                 buffer[b++] = 0;
450                                 __delay(50 * loops_per_jiffy / (1000/HZ));
451                                 outb_p(0xff, dtlk_port_lpc);
452                                 buffer[b++] = 0;
453                                 LOOK
454
455                                 printk("\n");
456                                 for (j = 0; j < b; j++)
457                                         printk(" %02x", buffer[j]);
458                                 printk("\n");
459                         }
460 #endif                          /* INSCOPE */
461
462 #ifdef OUTSCOPE
463                         {
464 /* This macro records ten samples read from the TTS port, for later display */
465 #define LOOK                                    \
466 for (i = 0; i < 10; i++)                        \
467   {                                             \
468     buffer[b++] = inb_p(dtlk_port_tts);         \
469     __delay(loops_per_jiffy/(1000000/HZ));  /* 1 us */ \
470   }
471                                 char buffer[1000];
472                                 int b = 0, i, j;
473
474                                 mdelay(10);     /* 10 ms */
475                                 LOOK
476                                 outb_p(0x03, dtlk_port_tts);
477                                 buffer[b++] = 0;
478                                 LOOK
479                                 LOOK
480
481                                 printk("\n");
482                                 for (j = 0; j < b; j++)
483                                         printk(" %02x", buffer[j]);
484                                 printk("\n");
485                         }
486 #endif                          /* OUTSCOPE */
487
488                         dtlk_write_bytes("Double Talk found", 18);
489
490                         return 0;
491                 }
492                 release_region(dtlk_portlist[i], DTLK_IO_EXTENT);
493         }
494
495         printk(KERN_INFO "DoubleTalk PC - not found\n");
496         return -ENODEV;
497 }
498
499 /*
500    static void dtlk_handle_error(char op, char rc, unsigned int minor)
501    {
502    printk(KERN_INFO"\nDoubleTalk PC - MINOR: %d, OPCODE: %d, ERROR: %d\n", 
503    minor, op, rc);
504    return;
505    }
506  */
507
508 /* interrogate the DoubleTalk PC and return its settings */
509 static struct dtlk_settings *dtlk_interrogate(void)
510 {
511         unsigned char *t;
512         static char buf[sizeof(struct dtlk_settings) + 1];
513         int total, i;
514         static struct dtlk_settings status;
515         TRACE_TEXT("(dtlk_interrogate");
516         dtlk_write_bytes("\030\001?", 3);
517         for (total = 0, i = 0; i < 50; i++) {
518                 buf[total] = dtlk_read_tts();
519                 if (total > 2 && buf[total] == 0x7f)
520                         break;
521                 if (total < sizeof(struct dtlk_settings))
522                         total++;
523         }
524         /*
525            if (i==50) printk("interrogate() read overrun\n");
526            for (i=0; i<sizeof(buf); i++)
527            printk(" %02x", buf[i]);
528            printk("\n");
529          */
530         t = buf;
531         status.serial_number = t[0] + t[1] * 256; /* serial number is
532                                                      little endian */
533         t += 2;
534
535         i = 0;
536         while (*t != '\r') {
537                 status.rom_version[i] = *t;
538                 if (i < sizeof(status.rom_version) - 1)
539                         i++;
540                 t++;
541         }
542         status.rom_version[i] = 0;
543         t++;
544
545         status.mode = *t++;
546         status.punc_level = *t++;
547         status.formant_freq = *t++;
548         status.pitch = *t++;
549         status.speed = *t++;
550         status.volume = *t++;
551         status.tone = *t++;
552         status.expression = *t++;
553         status.ext_dict_loaded = *t++;
554         status.ext_dict_status = *t++;
555         status.free_ram = *t++;
556         status.articulation = *t++;
557         status.reverb = *t++;
558         status.eob = *t++;
559         status.has_indexing = dtlk_has_indexing;
560         TRACE_RET;
561         return &status;
562 }
563
564 static char dtlk_read_tts(void)
565 {
566         int portval, retries = 0;
567         char ch;
568         TRACE_TEXT("(dtlk_read_tts");
569
570         /* verify DT is ready, read char, wait for ACK */
571         do {
572                 portval = inb_p(dtlk_port_tts);
573         } while ((portval & TTS_READABLE) == 0 &&
574                  retries++ < DTLK_MAX_RETRIES);
575         if (retries > DTLK_MAX_RETRIES)
576                 printk(KERN_ERR "dtlk_read_tts() timeout\n");
577
578         ch = inb_p(dtlk_port_tts);      /* input from TTS port */
579         ch &= 0x7f;
580         outb_p(ch, dtlk_port_tts);
581
582         retries = 0;
583         do {
584                 portval = inb_p(dtlk_port_tts);
585         } while ((portval & TTS_READABLE) != 0 &&
586                  retries++ < DTLK_MAX_RETRIES);
587         if (retries > DTLK_MAX_RETRIES)
588                 printk(KERN_ERR "dtlk_read_tts() timeout\n");
589
590         TRACE_RET;
591         return ch;
592 }
593
594 static char dtlk_read_lpc(void)
595 {
596         int retries = 0;
597         char ch;
598         TRACE_TEXT("(dtlk_read_lpc");
599
600         /* no need to test -- this is only called when the port is readable */
601
602         ch = inb_p(dtlk_port_lpc);      /* input from LPC port */
603
604         outb_p(0xff, dtlk_port_lpc);
605
606         /* acknowledging a read takes 3-4
607            usec.  Here, we wait up to 20 usec
608            for the acknowledgement */
609         retries = (loops_per_jiffy * 20) / (1000000/HZ);
610         while (inb_p(dtlk_port_lpc) != 0x7f && --retries > 0);
611         if (retries == 0)
612                 printk(KERN_ERR "dtlk_read_lpc() timeout\n");
613
614         TRACE_RET;
615         return ch;
616 }
617
618 /* write n bytes to tts port */
619 static char dtlk_write_bytes(const char *buf, int n)
620 {
621         char val = 0;
622         /*  printk("dtlk_write_bytes(\"%-*s\", %d)\n", n, buf, n); */
623         TRACE_TEXT("(dtlk_write_bytes");
624         while (n-- > 0)
625                 val = dtlk_write_tts(*buf++);
626         TRACE_RET;
627         return val;
628 }
629
630 static char dtlk_write_tts(char ch)
631 {
632         int retries = 0;
633 #ifdef TRACINGMORE
634         printk("  dtlk_write_tts(");
635         if (' ' <= ch && ch <= '~')
636                 printk("'%c'", ch);
637         else
638                 printk("0x%02x", ch);
639 #endif
640         if (ch != DTLK_CLEAR)   /* no flow control for CLEAR command */
641                 while ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0 &&
642                        retries++ < DTLK_MAX_RETRIES)    /* DT ready? */
643                         ;
644         if (retries > DTLK_MAX_RETRIES)
645                 printk(KERN_ERR "dtlk_write_tts() timeout\n");
646
647         outb_p(ch, dtlk_port_tts);      /* output to TTS port */
648         /* the RDY bit goes zero 2-3 usec after writing, and goes
649            1 again 180-190 usec later.  Here, we wait up to 10
650            usec for the RDY bit to go zero. */
651         for (retries = 0; retries < loops_per_jiffy / (100000/HZ); retries++)
652                 if ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0)
653                         break;
654
655 #ifdef TRACINGMORE
656         printk(")\n");
657 #endif
658         return 0;
659 }
660
661 MODULE_LICENSE("GPL");