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 <linux/smp_lock.h>     /* cycle_kernel_lock() */
 
  60 #include <asm/io.h>             /* for inb_p, outb_p, inb, outb, etc. */
 
  61 #include <asm/uaccess.h>        /* for get_user, etc. */
 
  62 #include <linux/wait.h>         /* for wait_queue */
 
  63 #include <linux/init.h>         /* for __init, module_{init,exit} */
 
  64 #include <linux/poll.h>         /* for POLLIN, etc. */
 
  65 #include <linux/dtlk.h>         /* local header file for DoubleTalk values */
 
  68 #define TRACE_TEXT(str) printk(str);
 
  69 #define TRACE_RET printk(")")
 
  71 #define TRACE_TEXT(str) ((void) 0)
 
  72 #define TRACE_RET ((void) 0)
 
  75 static void dtlk_timer_tick(unsigned long data);
 
  77 static int dtlk_major;
 
  78 static int dtlk_port_lpc;
 
  79 static int dtlk_port_tts;
 
  81 static int dtlk_has_indexing;
 
  82 static unsigned int dtlk_portlist[] =
 
  83 {0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0};
 
  84 static wait_queue_head_t dtlk_process_list;
 
  85 static DEFINE_TIMER(dtlk_timer, dtlk_timer_tick, 0, 0);
 
  87 /* prototypes for file_operations struct */
 
  88 static ssize_t dtlk_read(struct file *, char __user *,
 
  89                          size_t nbytes, loff_t * ppos);
 
  90 static ssize_t dtlk_write(struct file *, const char __user *,
 
  91                           size_t nbytes, loff_t * ppos);
 
  92 static unsigned int dtlk_poll(struct file *, poll_table *);
 
  93 static int dtlk_open(struct inode *, struct file *);
 
  94 static int dtlk_release(struct inode *, struct file *);
 
  95 static int dtlk_ioctl(struct inode *inode, struct file *file,
 
  96                       unsigned int cmd, unsigned long arg);
 
  98 static const struct file_operations dtlk_fops =
 
 100         .owner          = THIS_MODULE,
 
 106         .release        = dtlk_release,
 
 109 /* local prototypes */
 
 110 static int dtlk_dev_probe(void);
 
 111 static struct dtlk_settings *dtlk_interrogate(void);
 
 112 static int dtlk_readable(void);
 
 113 static char dtlk_read_lpc(void);
 
 114 static char dtlk_read_tts(void);
 
 115 static int dtlk_writeable(void);
 
 116 static char dtlk_write_bytes(const char *buf, int n);
 
 117 static char dtlk_write_tts(char);
 
 119    static void dtlk_handle_error(char, char, unsigned int);
 
 122 static ssize_t dtlk_read(struct file *file, char __user *buf,
 
 123                          size_t count, loff_t * ppos)
 
 125         unsigned int minor = iminor(file->f_path.dentry->d_inode);
 
 129         TRACE_TEXT("(dtlk_read");
 
 130         /*  printk("DoubleTalk PC - dtlk_read()\n"); */
 
 132         if (minor != DTLK_MINOR || !dtlk_has_indexing)
 
 135         for (retries = 0; retries < loops_per_jiffy; retries++) {
 
 136                 while (i < count && dtlk_readable()) {
 
 137                         ch = dtlk_read_lpc();
 
 138                         /*        printk("dtlk_read() reads 0x%02x\n", ch); */
 
 139                         if (put_user(ch, buf++))
 
 145                 if (file->f_flags & O_NONBLOCK)
 
 147                 msleep_interruptible(100);
 
 149         if (retries == loops_per_jiffy)
 
 150                 printk(KERN_ERR "dtlk_read times out\n");
 
 155 static ssize_t dtlk_write(struct file *file, const char __user *buf,
 
 156                           size_t count, loff_t * ppos)
 
 158         int i = 0, retries = 0, ch;
 
 160         TRACE_TEXT("(dtlk_write");
 
 165                 for (i = 0; i < count; i++) {
 
 166                         if (get_user(ch, buf + i))
 
 168                         if (' ' <= ch && ch <= '~')
 
 171                                 printk("\\%03o", ch);
 
 177         if (iminor(file->f_path.dentry->d_inode) != DTLK_MINOR)
 
 181                 while (i < count && !get_user(ch, buf) &&
 
 182                        (ch == DTLK_CLEAR || dtlk_writeable())) {
 
 187                                 /* We yield our time until scheduled
 
 188                                    again.  This reduces the transfer
 
 189                                    rate to 500 bytes/sec, but that's
 
 190                                    still enough to keep up with the
 
 191                                    speech synthesizer. */
 
 192                                 msleep_interruptible(1);
 
 194                                 /* the RDY bit goes zero 2-3 usec
 
 195                                    after writing, and goes 1 again
 
 196                                    180-190 usec later.  Here, we wait
 
 197                                    up to 250 usec for the RDY bit to
 
 200                                      retries < loops_per_jiffy / (4000/HZ);
 
 202                                         if (inb_p(dtlk_port_tts) &
 
 210                 if (file->f_flags & O_NONBLOCK)
 
 213                 msleep_interruptible(1);
 
 215                 if (++retries > 10 * HZ) { /* wait no more than 10 sec
 
 217                         printk("dtlk: write timeout.  "
 
 218                                "inb_p(dtlk_port_tts) = 0x%02x\n",
 
 219                                inb_p(dtlk_port_tts));
 
 228 static unsigned int dtlk_poll(struct file *file, poll_table * wait)
 
 231         unsigned long expires;
 
 233         TRACE_TEXT(" dtlk_poll");
 
 237            printk("<%ld>", jiffies-j);
 
 240         poll_wait(file, &dtlk_process_list, wait);
 
 242         if (dtlk_has_indexing && dtlk_readable()) {
 
 243                 del_timer(&dtlk_timer);
 
 244                 mask = POLLIN | POLLRDNORM;
 
 246         if (dtlk_writeable()) {
 
 247                 del_timer(&dtlk_timer);
 
 248                 mask |= POLLOUT | POLLWRNORM;
 
 250         /* there are no exception conditions */
 
 252         /* There won't be any interrupts, so we set a timer instead. */
 
 253         expires = jiffies + 3*HZ / 100;
 
 254         mod_timer(&dtlk_timer, expires);
 
 259 static void dtlk_timer_tick(unsigned long data)
 
 261         TRACE_TEXT(" dtlk_timer_tick");
 
 262         wake_up_interruptible(&dtlk_process_list);
 
 265 static int dtlk_ioctl(struct inode *inode,
 
 270         char __user *argp = (char __user *)arg;
 
 271         struct dtlk_settings *sp;
 
 273         TRACE_TEXT(" dtlk_ioctl");
 
 277         case DTLK_INTERROGATE:
 
 278                 sp = dtlk_interrogate();
 
 279                 if (copy_to_user(argp, sp, sizeof(struct dtlk_settings)))
 
 284                 portval = inb_p(dtlk_port_tts);
 
 285                 return put_user(portval, argp);
 
 292 /* Note that nobody ever sets dtlk_busy... */
 
 293 static int dtlk_open(struct inode *inode, struct file *file)
 
 295         TRACE_TEXT("(dtlk_open");
 
 298         nonseekable_open(inode, file);
 
 299         switch (iminor(inode)) {
 
 303                 return nonseekable_open(inode, file);
 
 310 static int dtlk_release(struct inode *inode, struct file *file)
 
 312         TRACE_TEXT("(dtlk_release");
 
 314         switch (iminor(inode)) {
 
 323         del_timer_sync(&dtlk_timer);
 
 328 static int __init dtlk_init(void)
 
 335         dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops);
 
 336         if (dtlk_major < 0) {
 
 337                 printk(KERN_ERR "DoubleTalk PC - cannot register device\n");
 
 340         err = dtlk_dev_probe();
 
 342                 unregister_chrdev(dtlk_major, "dtlk");
 
 345         printk(", MAJOR %d\n", dtlk_major);
 
 347         init_waitqueue_head(&dtlk_process_list);
 
 352 static void __exit dtlk_cleanup (void)
 
 354         dtlk_write_bytes("goodbye", 8);
 
 355         msleep_interruptible(500);              /* nap 0.50 sec but
 
 360         dtlk_write_tts(DTLK_CLEAR);
 
 361         unregister_chrdev(dtlk_major, "dtlk");
 
 362         release_region(dtlk_port_lpc, DTLK_IO_EXTENT);
 
 365 module_init(dtlk_init);
 
 366 module_exit(dtlk_cleanup);
 
 368 /* ------------------------------------------------------------------------ */
 
 370 static int dtlk_readable(void)
 
 373         printk(" dtlk_readable=%u@%u", inb_p(dtlk_port_lpc) != 0x7f, jiffies);
 
 375         return inb_p(dtlk_port_lpc) != 0x7f;
 
 378 static int dtlk_writeable(void)
 
 380         /* TRACE_TEXT(" dtlk_writeable"); */
 
 382         printk(" dtlk_writeable=%u", (inb_p(dtlk_port_tts) & TTS_WRITABLE)!=0);
 
 384         return inb_p(dtlk_port_tts) & TTS_WRITABLE;
 
 387 static int __init dtlk_dev_probe(void)
 
 389         unsigned int testval = 0;
 
 391         struct dtlk_settings *sp;
 
 393         if (dtlk_port_lpc | dtlk_port_tts)
 
 396         for (i = 0; dtlk_portlist[i]; i++) {
 
 398                 printk("DoubleTalk PC - Port %03x = %04x\n",
 
 399                        dtlk_portlist[i], (testval = inw_p(dtlk_portlist[i])));
 
 402                 if (!request_region(dtlk_portlist[i], DTLK_IO_EXTENT, 
 
 405                 testval = inw_p(dtlk_portlist[i]);
 
 406                 if ((testval &= 0xfbff) == 0x107f) {
 
 407                         dtlk_port_lpc = dtlk_portlist[i];
 
 408                         dtlk_port_tts = dtlk_port_lpc + 1;
 
 410                         sp = dtlk_interrogate();
 
 411                         printk("DoubleTalk PC at %03x-%03x, "
 
 412                                "ROM version %s, serial number %u",
 
 413                                dtlk_portlist[i], dtlk_portlist[i] +
 
 415                                sp->rom_version, sp->serial_number);
 
 417                         /* put LPC port into known state, so
 
 418                            dtlk_readable() gives valid result */
 
 419                         outb_p(0xff, dtlk_port_lpc); 
 
 421                         /* INIT string and index marker */
 
 422                         dtlk_write_bytes("\036\1@\0\0012I\r", 8);
 
 423                         /* posting an index takes 18 msec.  Here, we
 
 424                            wait up to 100 msec to see whether it
 
 426                         msleep_interruptible(100);
 
 427                         dtlk_has_indexing = dtlk_readable();
 
 429                         printk(", indexing %d\n", dtlk_has_indexing);
 
 433 /* This macro records ten samples read from the LPC port, for later display */
 
 435 for (i = 0; i < 10; i++)                        \
 
 437     buffer[b++] = inb_p(dtlk_port_lpc);         \
 
 438     __delay(loops_per_jiffy/(1000000/HZ));             \
 
 444                                 outb_p(0xff, dtlk_port_lpc);
 
 447                                 dtlk_write_bytes("\0012I\r", 4);
 
 449                                 __delay(50 * loops_per_jiffy / (1000/HZ));
 
 450                                 outb_p(0xff, dtlk_port_lpc);
 
 455                                 for (j = 0; j < b; j++)
 
 456                                         printk(" %02x", buffer[j]);
 
 463 /* This macro records ten samples read from the TTS port, for later display */
 
 465 for (i = 0; i < 10; i++)                        \
 
 467     buffer[b++] = inb_p(dtlk_port_tts);         \
 
 468     __delay(loops_per_jiffy/(1000000/HZ));  /* 1 us */ \
 
 473                                 mdelay(10);     /* 10 ms */
 
 475                                 outb_p(0x03, dtlk_port_tts);
 
 481                                 for (j = 0; j < b; j++)
 
 482                                         printk(" %02x", buffer[j]);
 
 485 #endif                          /* OUTSCOPE */
 
 487                         dtlk_write_bytes("Double Talk found", 18);
 
 491                 release_region(dtlk_portlist[i], DTLK_IO_EXTENT);
 
 494         printk(KERN_INFO "DoubleTalk PC - not found\n");
 
 499    static void dtlk_handle_error(char op, char rc, unsigned int minor)
 
 501    printk(KERN_INFO"\nDoubleTalk PC - MINOR: %d, OPCODE: %d, ERROR: %d\n", 
 
 507 /* interrogate the DoubleTalk PC and return its settings */
 
 508 static struct dtlk_settings *dtlk_interrogate(void)
 
 511         static char buf[sizeof(struct dtlk_settings) + 1];
 
 513         static struct dtlk_settings status;
 
 514         TRACE_TEXT("(dtlk_interrogate");
 
 515         dtlk_write_bytes("\030\001?", 3);
 
 516         for (total = 0, i = 0; i < 50; i++) {
 
 517                 buf[total] = dtlk_read_tts();
 
 518                 if (total > 2 && buf[total] == 0x7f)
 
 520                 if (total < sizeof(struct dtlk_settings))
 
 524            if (i==50) printk("interrogate() read overrun\n");
 
 525            for (i=0; i<sizeof(buf); i++)
 
 526            printk(" %02x", buf[i]);
 
 530         status.serial_number = t[0] + t[1] * 256; /* serial number is
 
 536                 status.rom_version[i] = *t;
 
 537                 if (i < sizeof(status.rom_version) - 1)
 
 541         status.rom_version[i] = 0;
 
 545         status.punc_level = *t++;
 
 546         status.formant_freq = *t++;
 
 549         status.volume = *t++;
 
 551         status.expression = *t++;
 
 552         status.ext_dict_loaded = *t++;
 
 553         status.ext_dict_status = *t++;
 
 554         status.free_ram = *t++;
 
 555         status.articulation = *t++;
 
 556         status.reverb = *t++;
 
 558         status.has_indexing = dtlk_has_indexing;
 
 563 static char dtlk_read_tts(void)
 
 565         int portval, retries = 0;
 
 567         TRACE_TEXT("(dtlk_read_tts");
 
 569         /* verify DT is ready, read char, wait for ACK */
 
 571                 portval = inb_p(dtlk_port_tts);
 
 572         } while ((portval & TTS_READABLE) == 0 &&
 
 573                  retries++ < DTLK_MAX_RETRIES);
 
 574         if (retries == DTLK_MAX_RETRIES)
 
 575                 printk(KERN_ERR "dtlk_read_tts() timeout\n");
 
 577         ch = inb_p(dtlk_port_tts);      /* input from TTS port */
 
 579         outb_p(ch, dtlk_port_tts);
 
 583                 portval = inb_p(dtlk_port_tts);
 
 584         } while ((portval & TTS_READABLE) != 0 &&
 
 585                  retries++ < DTLK_MAX_RETRIES);
 
 586         if (retries == DTLK_MAX_RETRIES)
 
 587                 printk(KERN_ERR "dtlk_read_tts() timeout\n");
 
 593 static char dtlk_read_lpc(void)
 
 597         TRACE_TEXT("(dtlk_read_lpc");
 
 599         /* no need to test -- this is only called when the port is readable */
 
 601         ch = inb_p(dtlk_port_lpc);      /* input from LPC port */
 
 603         outb_p(0xff, dtlk_port_lpc);
 
 605         /* acknowledging a read takes 3-4
 
 606            usec.  Here, we wait up to 20 usec
 
 607            for the acknowledgement */
 
 608         retries = (loops_per_jiffy * 20) / (1000000/HZ);
 
 609         while (inb_p(dtlk_port_lpc) != 0x7f && --retries > 0);
 
 611                 printk(KERN_ERR "dtlk_read_lpc() timeout\n");
 
 617 /* write n bytes to tts port */
 
 618 static char dtlk_write_bytes(const char *buf, int n)
 
 621         /*  printk("dtlk_write_bytes(\"%-*s\", %d)\n", n, buf, n); */
 
 622         TRACE_TEXT("(dtlk_write_bytes");
 
 624                 val = dtlk_write_tts(*buf++);
 
 629 static char dtlk_write_tts(char ch)
 
 633         printk("  dtlk_write_tts(");
 
 634         if (' ' <= ch && ch <= '~')
 
 637                 printk("0x%02x", ch);
 
 639         if (ch != DTLK_CLEAR)   /* no flow control for CLEAR command */
 
 640                 while ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0 &&
 
 641                        retries++ < DTLK_MAX_RETRIES)    /* DT ready? */
 
 643         if (retries == DTLK_MAX_RETRIES)
 
 644                 printk(KERN_ERR "dtlk_write_tts() timeout\n");
 
 646         outb_p(ch, dtlk_port_tts);      /* output to TTS port */
 
 647         /* the RDY bit goes zero 2-3 usec after writing, and goes
 
 648            1 again 180-190 usec later.  Here, we wait up to 10
 
 649            usec for the RDY bit to go zero. */
 
 650         for (retries = 0; retries < loops_per_jiffy / (100000/HZ); retries++)
 
 651                 if ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0)
 
 660 MODULE_LICENSE("GPL");