OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [dtlk.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.