2  * dtlk.c - DoubleTalk PC driver for Linux
 
   4  * Original author: Chris Pallotta <chris@allmedia.com>
 
   5  * Current maintainer: Jim Van Zandt <jrv@vanzandt.mv.com>
 
   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.
 
  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
 
  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
 
  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.
 
  32    The DoubleTalk PC generates no interrupts.
 
  34    These characteristics are mapped into the Unix stream I/O model as
 
  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.
 
  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.
 
  46    Status information is available using the DTLK_INTERROGATE ioctl.
 
  50 #include <linux/module.h>
 
  53 #include <linux/types.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 <asm/io.h>             /* for inb_p, outb_p, inb, outb, etc. */
 
  60 #include <asm/uaccess.h>        /* for get_user, etc. */
 
  61 #include <linux/wait.h>         /* for wait_queue */
 
  62 #include <linux/init.h>         /* for __init, module_{init,exit} */
 
  63 #include <linux/poll.h>         /* for POLLIN, etc. */
 
  64 #include <linux/dtlk.h>         /* local header file for DoubleTalk values */
 
  67 #define TRACE_TEXT(str) printk(str);
 
  68 #define TRACE_RET printk(")")
 
  70 #define TRACE_TEXT(str) ((void) 0)
 
  71 #define TRACE_RET ((void) 0)
 
  74 static void dtlk_timer_tick(unsigned long data);
 
  76 static int dtlk_major;
 
  77 static int dtlk_port_lpc;
 
  78 static int dtlk_port_tts;
 
  80 static int dtlk_has_indexing;
 
  81 static unsigned int dtlk_portlist[] =
 
  82 {0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0};
 
  83 static wait_queue_head_t dtlk_process_list;
 
  84 static DEFINE_TIMER(dtlk_timer, dtlk_timer_tick, 0, 0);
 
  86 /* prototypes for file_operations struct */
 
  87 static ssize_t dtlk_read(struct file *, char __user *,
 
  88                          size_t nbytes, loff_t * ppos);
 
  89 static ssize_t dtlk_write(struct file *, const char __user *,
 
  90                           size_t nbytes, loff_t * ppos);
 
  91 static unsigned int dtlk_poll(struct file *, poll_table *);
 
  92 static int dtlk_open(struct inode *, struct file *);
 
  93 static int dtlk_release(struct inode *, struct file *);
 
  94 static int dtlk_ioctl(struct inode *inode, struct file *file,
 
  95                       unsigned int cmd, unsigned long arg);
 
  97 static const struct file_operations dtlk_fops =
 
 105         .release        = dtlk_release,
 
 108 /* local prototypes */
 
 109 static int dtlk_dev_probe(void);
 
 110 static struct dtlk_settings *dtlk_interrogate(void);
 
 111 static int dtlk_readable(void);
 
 112 static char dtlk_read_lpc(void);
 
 113 static char dtlk_read_tts(void);
 
 114 static int dtlk_writeable(void);
 
 115 static char dtlk_write_bytes(const char *buf, int n);
 
 116 static char dtlk_write_tts(char);
 
 118    static void dtlk_handle_error(char, char, unsigned int);
 
 121 static ssize_t dtlk_read(struct file *file, char __user *buf,
 
 122                          size_t count, loff_t * ppos)
 
 124         unsigned int minor = iminor(file->f_path.dentry->d_inode);
 
 128         TRACE_TEXT("(dtlk_read");
 
 129         /*  printk("DoubleTalk PC - dtlk_read()\n"); */
 
 131         if (minor != DTLK_MINOR || !dtlk_has_indexing)
 
 134         for (retries = 0; retries < loops_per_jiffy; retries++) {
 
 135                 while (i < count && dtlk_readable()) {
 
 136                         ch = dtlk_read_lpc();
 
 137                         /*        printk("dtlk_read() reads 0x%02x\n", ch); */
 
 138                         if (put_user(ch, buf++))
 
 144                 if (file->f_flags & O_NONBLOCK)
 
 146                 msleep_interruptible(100);
 
 148         if (retries == loops_per_jiffy)
 
 149                 printk(KERN_ERR "dtlk_read times out\n");
 
 154 static ssize_t dtlk_write(struct file *file, const char __user *buf,
 
 155                           size_t count, loff_t * ppos)
 
 157         int i = 0, retries = 0, ch;
 
 159         TRACE_TEXT("(dtlk_write");
 
 164                 for (i = 0; i < count; i++) {
 
 165                         if (get_user(ch, buf + i))
 
 167                         if (' ' <= ch && ch <= '~')
 
 170                                 printk("\\%03o", ch);
 
 176         if (iminor(file->f_path.dentry->d_inode) != DTLK_MINOR)
 
 180                 while (i < count && !get_user(ch, buf) &&
 
 181                        (ch == DTLK_CLEAR || dtlk_writeable())) {
 
 186                                 /* We yield our time until scheduled
 
 187                                    again.  This reduces the transfer
 
 188                                    rate to 500 bytes/sec, but that's
 
 189                                    still enough to keep up with the
 
 190                                    speech synthesizer. */
 
 191                                 msleep_interruptible(1);
 
 193                                 /* the RDY bit goes zero 2-3 usec
 
 194                                    after writing, and goes 1 again
 
 195                                    180-190 usec later.  Here, we wait
 
 196                                    up to 250 usec for the RDY bit to
 
 199                                      retries < loops_per_jiffy / (4000/HZ);
 
 201                                         if (inb_p(dtlk_port_tts) &
 
 209                 if (file->f_flags & O_NONBLOCK)
 
 212                 msleep_interruptible(1);
 
 214                 if (++retries > 10 * HZ) { /* wait no more than 10 sec
 
 216                         printk("dtlk: write timeout.  "
 
 217                                "inb_p(dtlk_port_tts) = 0x%02x\n",
 
 218                                inb_p(dtlk_port_tts));
 
 227 static unsigned int dtlk_poll(struct file *file, poll_table * wait)
 
 230         unsigned long expires;
 
 232         TRACE_TEXT(" dtlk_poll");
 
 236            printk("<%ld>", jiffies-j);
 
 239         poll_wait(file, &dtlk_process_list, wait);
 
 241         if (dtlk_has_indexing && dtlk_readable()) {
 
 242                 del_timer(&dtlk_timer);
 
 243                 mask = POLLIN | POLLRDNORM;
 
 245         if (dtlk_writeable()) {
 
 246                 del_timer(&dtlk_timer);
 
 247                 mask |= POLLOUT | POLLWRNORM;
 
 249         /* there are no exception conditions */
 
 251         /* There won't be any interrupts, so we set a timer instead. */
 
 252         expires = jiffies + 3*HZ / 100;
 
 253         mod_timer(&dtlk_timer, expires);
 
 258 static void dtlk_timer_tick(unsigned long data)
 
 260         TRACE_TEXT(" dtlk_timer_tick");
 
 261         wake_up_interruptible(&dtlk_process_list);
 
 264 static int dtlk_ioctl(struct inode *inode,
 
 269         char __user *argp = (char __user *)arg;
 
 270         struct dtlk_settings *sp;
 
 272         TRACE_TEXT(" dtlk_ioctl");
 
 276         case DTLK_INTERROGATE:
 
 277                 sp = dtlk_interrogate();
 
 278                 if (copy_to_user(argp, sp, sizeof(struct dtlk_settings)))
 
 283                 portval = inb_p(dtlk_port_tts);
 
 284                 return put_user(portval, argp);
 
 291 static int dtlk_open(struct inode *inode, struct file *file)
 
 293         TRACE_TEXT("(dtlk_open");
 
 295         nonseekable_open(inode, file);
 
 296         switch (iminor(inode)) {
 
 300                 return nonseekable_open(inode, file);
 
 307 static int dtlk_release(struct inode *inode, struct file *file)
 
 309         TRACE_TEXT("(dtlk_release");
 
 311         switch (iminor(inode)) {
 
 320         del_timer_sync(&dtlk_timer);
 
 325 static int __init dtlk_init(void)
 
 332         dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops);
 
 333         if (dtlk_major < 0) {
 
 334                 printk(KERN_ERR "DoubleTalk PC - cannot register device\n");
 
 337         err = dtlk_dev_probe();
 
 339                 unregister_chrdev(dtlk_major, "dtlk");
 
 342         printk(", MAJOR %d\n", dtlk_major);
 
 344         init_waitqueue_head(&dtlk_process_list);
 
 349 static void __exit dtlk_cleanup (void)
 
 351         dtlk_write_bytes("goodbye", 8);
 
 352         msleep_interruptible(500);              /* nap 0.50 sec but
 
 357         dtlk_write_tts(DTLK_CLEAR);
 
 358         unregister_chrdev(dtlk_major, "dtlk");
 
 359         release_region(dtlk_port_lpc, DTLK_IO_EXTENT);
 
 362 module_init(dtlk_init);
 
 363 module_exit(dtlk_cleanup);
 
 365 /* ------------------------------------------------------------------------ */
 
 367 static int dtlk_readable(void)
 
 370         printk(" dtlk_readable=%u@%u", inb_p(dtlk_port_lpc) != 0x7f, jiffies);
 
 372         return inb_p(dtlk_port_lpc) != 0x7f;
 
 375 static int dtlk_writeable(void)
 
 377         /* TRACE_TEXT(" dtlk_writeable"); */
 
 379         printk(" dtlk_writeable=%u", (inb_p(dtlk_port_tts) & TTS_WRITABLE)!=0);
 
 381         return inb_p(dtlk_port_tts) & TTS_WRITABLE;
 
 384 static int __init dtlk_dev_probe(void)
 
 386         unsigned int testval = 0;
 
 388         struct dtlk_settings *sp;
 
 390         if (dtlk_port_lpc | dtlk_port_tts)
 
 393         for (i = 0; dtlk_portlist[i]; i++) {
 
 395                 printk("DoubleTalk PC - Port %03x = %04x\n",
 
 396                        dtlk_portlist[i], (testval = inw_p(dtlk_portlist[i])));
 
 399                 if (!request_region(dtlk_portlist[i], DTLK_IO_EXTENT, 
 
 402                 testval = inw_p(dtlk_portlist[i]);
 
 403                 if ((testval &= 0xfbff) == 0x107f) {
 
 404                         dtlk_port_lpc = dtlk_portlist[i];
 
 405                         dtlk_port_tts = dtlk_port_lpc + 1;
 
 407                         sp = dtlk_interrogate();
 
 408                         printk("DoubleTalk PC at %03x-%03x, "
 
 409                                "ROM version %s, serial number %u",
 
 410                                dtlk_portlist[i], dtlk_portlist[i] +
 
 412                                sp->rom_version, sp->serial_number);
 
 414                         /* put LPC port into known state, so
 
 415                            dtlk_readable() gives valid result */
 
 416                         outb_p(0xff, dtlk_port_lpc); 
 
 418                         /* INIT string and index marker */
 
 419                         dtlk_write_bytes("\036\1@\0\0012I\r", 8);
 
 420                         /* posting an index takes 18 msec.  Here, we
 
 421                            wait up to 100 msec to see whether it
 
 423                         msleep_interruptible(100);
 
 424                         dtlk_has_indexing = dtlk_readable();
 
 426                         printk(", indexing %d\n", dtlk_has_indexing);
 
 430 /* This macro records ten samples read from the LPC port, for later display */
 
 432 for (i = 0; i < 10; i++)                        \
 
 434     buffer[b++] = inb_p(dtlk_port_lpc);         \
 
 435     __delay(loops_per_jiffy/(1000000/HZ));             \
 
 441                                 outb_p(0xff, dtlk_port_lpc);
 
 444                                 dtlk_write_bytes("\0012I\r", 4);
 
 446                                 __delay(50 * loops_per_jiffy / (1000/HZ));
 
 447                                 outb_p(0xff, dtlk_port_lpc);
 
 452                                 for (j = 0; j < b; j++)
 
 453                                         printk(" %02x", buffer[j]);
 
 460 /* This macro records ten samples read from the TTS port, for later display */
 
 462 for (i = 0; i < 10; i++)                        \
 
 464     buffer[b++] = inb_p(dtlk_port_tts);         \
 
 465     __delay(loops_per_jiffy/(1000000/HZ));  /* 1 us */ \
 
 470                                 mdelay(10);     /* 10 ms */
 
 472                                 outb_p(0x03, dtlk_port_tts);
 
 478                                 for (j = 0; j < b; j++)
 
 479                                         printk(" %02x", buffer[j]);
 
 482 #endif                          /* OUTSCOPE */
 
 484                         dtlk_write_bytes("Double Talk found", 18);
 
 488                 release_region(dtlk_portlist[i], DTLK_IO_EXTENT);
 
 491         printk(KERN_INFO "DoubleTalk PC - not found\n");
 
 496    static void dtlk_handle_error(char op, char rc, unsigned int minor)
 
 498    printk(KERN_INFO"\nDoubleTalk PC - MINOR: %d, OPCODE: %d, ERROR: %d\n", 
 
 504 /* interrogate the DoubleTalk PC and return its settings */
 
 505 static struct dtlk_settings *dtlk_interrogate(void)
 
 508         static char buf[sizeof(struct dtlk_settings) + 1];
 
 510         static struct dtlk_settings status;
 
 511         TRACE_TEXT("(dtlk_interrogate");
 
 512         dtlk_write_bytes("\030\001?", 3);
 
 513         for (total = 0, i = 0; i < 50; i++) {
 
 514                 buf[total] = dtlk_read_tts();
 
 515                 if (total > 2 && buf[total] == 0x7f)
 
 517                 if (total < sizeof(struct dtlk_settings))
 
 521            if (i==50) printk("interrogate() read overrun\n");
 
 522            for (i=0; i<sizeof(buf); i++)
 
 523            printk(" %02x", buf[i]);
 
 527         status.serial_number = t[0] + t[1] * 256; /* serial number is
 
 533                 status.rom_version[i] = *t;
 
 534                 if (i < sizeof(status.rom_version) - 1)
 
 538         status.rom_version[i] = 0;
 
 542         status.punc_level = *t++;
 
 543         status.formant_freq = *t++;
 
 546         status.volume = *t++;
 
 548         status.expression = *t++;
 
 549         status.ext_dict_loaded = *t++;
 
 550         status.ext_dict_status = *t++;
 
 551         status.free_ram = *t++;
 
 552         status.articulation = *t++;
 
 553         status.reverb = *t++;
 
 555         status.has_indexing = dtlk_has_indexing;
 
 560 static char dtlk_read_tts(void)
 
 562         int portval, retries = 0;
 
 564         TRACE_TEXT("(dtlk_read_tts");
 
 566         /* verify DT is ready, read char, wait for ACK */
 
 568                 portval = inb_p(dtlk_port_tts);
 
 569         } while ((portval & TTS_READABLE) == 0 &&
 
 570                  retries++ < DTLK_MAX_RETRIES);
 
 571         if (retries == DTLK_MAX_RETRIES)
 
 572                 printk(KERN_ERR "dtlk_read_tts() timeout\n");
 
 574         ch = inb_p(dtlk_port_tts);      /* input from TTS port */
 
 576         outb_p(ch, dtlk_port_tts);
 
 580                 portval = inb_p(dtlk_port_tts);
 
 581         } while ((portval & TTS_READABLE) != 0 &&
 
 582                  retries++ < DTLK_MAX_RETRIES);
 
 583         if (retries == DTLK_MAX_RETRIES)
 
 584                 printk(KERN_ERR "dtlk_read_tts() timeout\n");
 
 590 static char dtlk_read_lpc(void)
 
 594         TRACE_TEXT("(dtlk_read_lpc");
 
 596         /* no need to test -- this is only called when the port is readable */
 
 598         ch = inb_p(dtlk_port_lpc);      /* input from LPC port */
 
 600         outb_p(0xff, dtlk_port_lpc);
 
 602         /* acknowledging a read takes 3-4
 
 603            usec.  Here, we wait up to 20 usec
 
 604            for the acknowledgement */
 
 605         retries = (loops_per_jiffy * 20) / (1000000/HZ);
 
 606         while (inb_p(dtlk_port_lpc) != 0x7f && --retries > 0);
 
 608                 printk(KERN_ERR "dtlk_read_lpc() timeout\n");
 
 614 /* write n bytes to tts port */
 
 615 static char dtlk_write_bytes(const char *buf, int n)
 
 618         /*  printk("dtlk_write_bytes(\"%-*s\", %d)\n", n, buf, n); */
 
 619         TRACE_TEXT("(dtlk_write_bytes");
 
 621                 val = dtlk_write_tts(*buf++);
 
 626 static char dtlk_write_tts(char ch)
 
 630         printk("  dtlk_write_tts(");
 
 631         if (' ' <= ch && ch <= '~')
 
 634                 printk("0x%02x", ch);
 
 636         if (ch != DTLK_CLEAR)   /* no flow control for CLEAR command */
 
 637                 while ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0 &&
 
 638                        retries++ < DTLK_MAX_RETRIES)    /* DT ready? */
 
 640         if (retries == DTLK_MAX_RETRIES)
 
 641                 printk(KERN_ERR "dtlk_write_tts() timeout\n");
 
 643         outb_p(ch, dtlk_port_tts);      /* output to TTS port */
 
 644         /* the RDY bit goes zero 2-3 usec after writing, and goes
 
 645            1 again 180-190 usec later.  Here, we wait up to 10
 
 646            usec for the RDY bit to go zero. */
 
 647         for (retries = 0; retries < loops_per_jiffy / (100000/HZ); retries++)
 
 648                 if ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0)
 
 657 MODULE_LICENSE("GPL");