~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/char/dtlk.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.