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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * Rocketport device driver for Linux
3
 *
4
 * Written by Theodore Ts'o, 1995, 1996, 1997.
5
 *
6
 * Copyright (C) 1995, 1996, 1997 by Comtrol, Inc.
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License as
10
 * published by the Free Software Foundation; either version 2 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
 */
22
 
23
/*
24
 * Minor number schema:
25
 *
26
 * +-------------------------------+
27
 * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
28
 * +---+-------+-------+-----------+
29
 * | C | Board |  AIOP | Port #    |
30
 * +---+-------+-------+-----------+
31
 *
32
 * C=0 implements normal POSIX tty.
33
 * C=1 is reserved for the callout device.
34
 *
35
 * Normally, the user won't have to worry about the AIOP; as far as
36
 * the user is concerned, the lower 5 bits of the minor number address
37
 * the ports on a particular board (from 0 up to 32).
38
 */
39
 
40
/* Kernel includes */
41
 
42
#include <linux/config.h>
43
#include <linux/version.h>
44
 
45
#ifdef CONFIG_PCI
46
#define ENABLE_PCI
47
#endif
48
 
49
#include <linux/module.h>
50
#include <linux/errno.h>
51
#include <linux/major.h>
52
#include <linux/kernel.h>
53
#include <linux/signal.h>
54
#include <linux/slab.h>
55
#include <linux/mm.h>
56
 
57
#include <linux/sched.h>
58
#include <linux/timer.h>
59
#include <linux/interrupt.h>
60
#include <linux/tty.h>
61
#include <linux/tty_flip.h>
62
#include <linux/string.h>
63
#include <linux/fcntl.h>
64
#include <linux/ptrace.h>
65
#include <linux/ioport.h>
66
#ifdef ENABLE_PCI
67
#include <linux/pci.h>
68
#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
69
#include <linux/bios32.h>
70
#endif
71
#endif
72
#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
73
#include <linux/init.h>
74
#endif
75
 
76
#include "rocket_int.h"
77
#ifdef LOCAL_ROCKET_H
78
#include "rocket.h"
79
#include "version.h"
80
#else
81
#include <linux/rocket.h>
82
#define ROCKET_VERSION "1.14c"
83
#define ROCKET_DATE "24-Aug-98"
84
#endif /* LOCAL_ROCKET_H */
85
 
86
#define ROCKET_PARANOIA_CHECK
87
#define ROCKET_SOFT_FLOW
88
 
89
#undef ROCKET_DEBUG_OPEN
90
#undef ROCKET_DEBUG_INTR
91
#undef ROCKET_DEBUG_WRITE
92
#undef ROCKET_DEBUG_FLOW
93
#undef ROCKET_DEBUG_THROTTLE
94
#undef ROCKET_DEBUG_WAIT_UNTIL_SENT
95
#undef ROCKET_DEBUG_RECEIVE
96
#undef ROCKET_DEBUG_HANGUP
97
 
98
 
99
/*   CAUTION!!!!!  The TIME_STAT Function relies on the Pentium 64 bit
100
 *    register.  For various reasons related to 1.2.13, the test for this
101
 *    register is omitted from this driver.  If you are going to enable
102
 *    this option, make sure you are running a Pentium CPU and that a
103
 *    cat of /proc/cpuinfo shows ability TS Counters as Yes.  Warning part
104
 *    done, don't cry to me if you enable this options and things won't
105
 *    work.  If it gives you any problems, then disable the option.  The code
106
 *    in this function is pretty straight forward, if it breaks on your
107
 *    CPU, there is probably something funny about your CPU.
108
 */
109
 
110
#undef TIME_STAT        /* For performing timing statistics on driver. */
111
                        /* Produces printks, one every TIME_COUNTER loops, eats */
112
                        /* some of your CPU time.  Good for testing or */
113
                        /* other checking, otherwise, leave it undefed */
114
                        /* Doug Ledford */
115
#define TIME_STAT_CPU 100      /* This needs to be set to your processor speed */
116
                               /* For example, 100Mhz CPU, set this to 100 */
117
#define TIME_COUNTER 180000    /* This is how many iterations to run before */
118
                              /* performing the printk statements.   */
119
                              /* 6000 = 1 minute, 360000 = 1 hour, etc. */
120
                              /* Since time_stat is long long, this */
121
                              /* Can be really high if you want :)  */
122
#undef TIME_STAT_VERBOSE   /* Undef this if you want a terse log message. */
123
 
124
#define _INLINE_ inline
125
 
126
static struct r_port *rp_table[MAX_RP_PORTS];
127
static struct tty_struct *rocket_table[MAX_RP_PORTS];
128
static unsigned int xmit_flags[NUM_BOARDS];
129
static struct termios *rocket_termios[MAX_RP_PORTS];
130
static struct termios *rocket_termios_locked[MAX_RP_PORTS];
131
static void rp_wait_until_sent(struct tty_struct *tty, int timeout);
132
static void rp_flush_buffer(struct tty_struct *tty);
133
 
134
static struct tty_driver rocket_driver, callout_driver;
135
static int rocket_refcount;
136
 
137
static int rp_num_ports_open;
138
 
139
static struct timer_list rocket_timer;
140
 
141
unsigned long board1;
142
unsigned long board2;
143
unsigned long board3;
144
unsigned long board4;
145
unsigned long controller;
146
unsigned long support_low_speed;
147
int rp_baud_base = 460800;
148
static unsigned long rcktpt_io_addr[NUM_BOARDS];
149
static int max_board;
150
#ifdef TIME_STAT
151
static unsigned long long time_stat;
152
static unsigned long time_stat_short;
153
static unsigned long time_stat_long;
154
static unsigned long time_counter;
155
#endif
156
 
157
#if ((LINUX_VERSION_CODE > 0x020111) && defined(MODULE))
158
MODULE_AUTHOR("Theodore Ts'o");
159
MODULE_DESCRIPTION("Comtrol Rocketport driver");
160
MODULE_LICENSE("GPL");
161
MODULE_PARM(board1,     "i");
162
MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1");
163
MODULE_PARM(board2,     "i");
164
MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2");
165
MODULE_PARM(board3,     "i");
166
MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3");
167
MODULE_PARM(board4,     "i");
168
MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4");
169
MODULE_PARM(controller, "i");
170
MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
171
MODULE_PARM(support_low_speed, "i");
172
MODULE_PARM_DESC(support_low_speed, "0 means support 50 baud, 1 means support 460400 baud");
173
#endif
174
 
175
#if (LINUX_VERSION_CODE < 131336)
176
int copy_from_user(void *to, const void *from_user, unsigned long len)
177
{
178
        int     error;
179
 
180
        error = verify_area(VERIFY_READ, from_user, len);
181
        if (error)
182
                return len;
183
        memcpy_fromfs(to, from_user, len);
184
        return 0;
185
}
186
 
187
int copy_to_user(void *to_user, const void *from, unsigned long len)
188
{
189
        int     error;
190
 
191
        error = verify_area(VERIFY_WRITE, to_user, len);
192
        if (error)
193
                return len;
194
        memcpy_tofs(to_user, from, len);
195
        return 0;
196
}
197
 
198
static inline int signal_pending(struct task_struct *p)
199
{
200
        return (p->signal & ~p->blocked) != 0;
201
}
202
 
203
#else
204
#include <asm/uaccess.h>
205
#endif
206
 
207
/*
208
 * tmp_buf is used as a temporary buffer by rp_write.  We need to
209
 * lock it in case the memcpy_fromfs blocks while swapping in a page,
210
 * and some other program tries to do a serial write at the same time.
211
 * Since the lock will only come under contention when the system is
212
 * swapping and available memory is low, it makes sense to share one
213
 * buffer across all the serial ports, since it significantly saves
214
 * memory if large numbers of serial ports are open.
215
 */
216
static unsigned char *tmp_buf = 0;
217
static DECLARE_MUTEX(tmp_buf_sem);
218
 
219
static void rp_start(struct tty_struct *tty);
220
 
221
static inline int rocket_paranoia_check(struct r_port *info,
222
                                        kdev_t device, const char *routine)
223
{
224
#ifdef ROCKET_PARANOIA_CHECK
225
        static const char *badmagic =
226
                "Warning: bad magic number for rocketport struct (%d, %d) in %s\n";
227
        if (!info)
228
                return 1;
229
        if (info->magic != RPORT_MAGIC) {
230
                printk(badmagic, MAJOR(device), MINOR(device), routine);
231
                return 1;
232
        }
233
#endif
234
        return 0;
235
}
236
 
237
/*
238
 * Here begins the interrupt/polling routine for the Rocketport!
239
 */
240
static _INLINE_ void rp_do_receive(struct r_port *info, struct tty_struct *tty,
241
                                   CHANNEL_t *cp, unsigned int ChanStatus)
242
{
243
        unsigned int CharNStat;
244
        int ToRecv, wRecv, space, count;
245
        unsigned char   *cbuf;
246
        char            *fbuf;
247
 
248
        ToRecv= sGetRxCnt(cp);
249
        space = 2*TTY_FLIPBUF_SIZE;
250
        cbuf = tty->flip.char_buf;
251
        fbuf = tty->flip.flag_buf;
252
        count = 0;
253
#ifdef ROCKET_DEBUG_INTR
254
        printk("rp_do_receive(%d, %d)...", ToRecv, space);
255
#endif
256
        if (ToRecv == 0 || (space <= 0))
257
                return;
258
 
259
        /*
260
         * determine how many we can actually read in.  If we can't
261
         * read any in then we have a software overrun condition.
262
         */
263
        if (ToRecv > space)
264
                ToRecv = space;
265
 
266
        /*
267
         * if status indicates there are errored characters in the
268
         * FIFO, then enter status mode (a word in FIFO holds
269
         * character and status).
270
         */
271
        if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
272
                if (!(ChanStatus & STATMODE)) {
273
#ifdef ROCKET_DEBUG_RECEIVE
274
                        printk("Entering STATMODE...");
275
#endif
276
                        ChanStatus |= STATMODE;
277
                        sEnRxStatusMode(cp);
278
                }
279
        }
280
 
281
        /*
282
         * if we previously entered status mode, then read down the
283
         * FIFO one word at a time, pulling apart the character and
284
         * the status.  Update error counters depending on status
285
         */
286
        if (ChanStatus & STATMODE) {
287
#ifdef ROCKET_DEBUG_RECEIVE
288
                printk("Ignore %x, read %x...", info->ignore_status_mask,
289
                       info->read_status_mask);
290
#endif
291
                while (ToRecv) {
292
                        CharNStat= sInW(sGetTxRxDataIO(cp));
293
 
294
#ifdef ROCKET_DEBUG_RECEIVE
295
                        printk("%x...", CharNStat);
296
#endif
297
 
298
                        if (CharNStat & STMBREAKH)
299
                                CharNStat &= ~(STMFRAMEH | STMPARITYH);
300
                        if (CharNStat & info->ignore_status_mask) {
301
                                ToRecv--;
302
                                continue;
303
                        }
304
                        CharNStat &= info->read_status_mask;
305
                        if (CharNStat & STMBREAKH) {
306
                                *fbuf++ = TTY_BREAK;
307
#if 0
308
                                if (info->flags & ROCKET_SAK)
309
                                        do_SAK(tty);
310
#endif
311
                        } else if (CharNStat & STMPARITYH)
312
                                *fbuf++ = TTY_PARITY;
313
                        else if (CharNStat & STMFRAMEH)
314
                                *fbuf++ = TTY_FRAME;
315
                        else if (CharNStat & STMRCVROVRH)
316
                                *fbuf++ =TTY_OVERRUN;
317
                        else
318
                                *fbuf++ = 0;
319
                        *cbuf++ = CharNStat & 0xff;
320
                        count++;
321
                        ToRecv--;
322
                }
323
 
324
                /*
325
                 * after we've emptied the FIFO in status mode, turn
326
                 * status mode back off
327
                 */
328
                if (sGetRxCnt(cp) == 0) {
329
#ifdef ROCKET_DEBUG_RECEIVE
330
                        printk("Status mode off.\n");
331
#endif
332
                        sDisRxStatusMode(cp);
333
                }
334
        } else {
335
                /*
336
                 * we aren't in status mode, so read down the FIFO two
337
                 * characters at time by doing repeated word IO
338
                 * transfer.
339
                 */
340
                wRecv= ToRecv >> 1;
341
                if (wRecv)
342
                        sInStrW(sGetTxRxDataIO(cp), cbuf,
343
                                wRecv);
344
                if (ToRecv & 1)
345
                        cbuf[ToRecv-1] = sInB(sGetTxRxDataIO(cp));
346
                memset(fbuf, 0, ToRecv);
347
                cbuf += ToRecv;
348
                fbuf += ToRecv;
349
                count += ToRecv;
350
        }
351
        tty->ldisc.receive_buf(tty, tty->flip.char_buf,
352
                               tty->flip.flag_buf, count);
353
}
354
 
355
/*
356
 * This routine is called when a transmit interrupt is found.  It's
357
 * responsible for pushing data found in the transmit buffer out to
358
 * the serial card.
359
 */
360
static _INLINE_ void rp_do_transmit(struct r_port *info)
361
{
362
        int     c;
363
        CHANNEL_t *cp = &info->channel;
364
        struct tty_struct *tty;
365
 
366
#ifdef ROCKET_DEBUG_INTR
367
        printk("rp_do_transmit ");
368
#endif
369
        if (!info)
370
                return;
371
        if (!info->tty) {
372
                printk("rp: WARNING rp_do_transmit called with info->tty==NULL\n");
373
                xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
374
                return;
375
        }
376
        tty = info->tty;
377
        info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
378
        while (1) {
379
                if (tty->stopped || tty->hw_stopped)
380
                        break;
381
                c = MIN(info->xmit_fifo_room,
382
                        MIN(info->xmit_cnt,
383
                            XMIT_BUF_SIZE - info->xmit_tail));
384
                if (c <= 0 || info->xmit_fifo_room <= 0)
385
                        break;
386
                sOutStrW(sGetTxRxDataIO(cp),
387
                         info->xmit_buf + info->xmit_tail, c/2);
388
                if (c & 1)
389
                        sOutB(sGetTxRxDataIO(cp),
390
                              info->xmit_buf[info->xmit_tail + c -
391
                                             1]);
392
                info->xmit_tail += c;
393
                info->xmit_tail &= XMIT_BUF_SIZE-1;
394
                info->xmit_cnt -= c;
395
                info->xmit_fifo_room -= c;
396
#ifdef ROCKET_DEBUG_INTR
397
                printk("tx %d chars...", c);
398
#endif
399
        }
400
        if (info->xmit_cnt == 0)
401
                xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
402
        if (info->xmit_cnt < WAKEUP_CHARS) {
403
                if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
404
                    tty->ldisc.write_wakeup)
405
                        (tty->ldisc.write_wakeup)(tty);
406
                wake_up_interruptible(&tty->write_wait);
407
        }
408
#ifdef ROCKET_DEBUG_INTR
409
        printk("(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head,
410
               info->xmit_tail, info->xmit_fifo_room);
411
#endif
412
}
413
 
414
/*
415
 * This function is called for each port which has signalled an
416
 * interrupt.  It checks what interrupts are pending and services
417
 * them.
418
 */
419
static _INLINE_ void rp_handle_port(struct r_port *info)
420
{
421
        CHANNEL_t *cp;
422
        struct tty_struct *tty;
423
        unsigned int IntMask, ChanStatus;
424
 
425
        if (!info)
426
                return;
427
        if ( (info->flags & ROCKET_INITIALIZED) == 0 ) {
428
                printk("rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n");
429
                return;
430
        }
431
        if (!info->tty) {
432
                printk("rp: WARNING: rp_handle_port called with info->tty==NULL\n");
433
                return;
434
        }
435
        cp = &info->channel;
436
        tty = info->tty;
437
 
438
        IntMask = sGetChanIntID(cp) & info->intmask;
439
#ifdef ROCKET_DEBUG_INTR
440
        printk("rp_interrupt %02x...", IntMask);
441
#endif
442
        ChanStatus= sGetChanStatus(cp);
443
        if (IntMask & RXF_TRIG) {       /* Rx FIFO trigger level */
444
                rp_do_receive(info, tty, cp, ChanStatus);
445
        }
446
#if 0
447
        if (IntMask & SRC_INT) {        /* Special receive condition */
448
        }
449
#endif
450
        if (IntMask & DELTA_CD) {       /* CD change  */
451
#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || \
452
     defined(ROCKET_DEBUG_HANGUP))
453
                printk("ttyR%d CD now %s...", info->line,
454
                       (ChanStatus & CD_ACT) ? "on" : "off");
455
#endif
456
                if (!(ChanStatus & CD_ACT) &&
457
                    info->cd_status &&
458
                    !((info->flags & ROCKET_CALLOUT_ACTIVE) &&
459
                      (info->flags & ROCKET_CALLOUT_NOHUP))) {
460
#ifdef ROCKET_DEBUG_HANGUP
461
                        printk("CD drop, calling hangup.\n");
462
#endif
463
                        tty_hangup(tty);
464
                }
465
                info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
466
                wake_up_interruptible(&info->open_wait);
467
        }
468
#ifdef ROCKET_DEBUG_INTR
469
        if (IntMask & DELTA_CTS) {      /* CTS change */
470
                printk("CTS change...\n");
471
        }
472
        if (IntMask & DELTA_DSR) {      /* DSR change */
473
                printk("DSR change...\n");
474
        }
475
#endif
476
}
477
 
478
/*
479
 * The top level polling routine.
480
 */
481
static void rp_do_poll(unsigned long dummy)
482
{
483
        CONTROLLER_t *ctlp;
484
        int ctrl, aiop, ch, line;
485
        unsigned int xmitmask;
486
        unsigned char CtlMask, AiopMask;
487
 
488
#ifdef TIME_STAT
489
        unsigned long loop_time;
490
        unsigned long long time_stat_tmp=0, time_stat_tmp2=0;
491
 
492
        rdtscll(time_stat_tmp);
493
#endif /* TIME_STAT */
494
 
495
        for (ctrl=0; ctrl < max_board; ctrl++) {
496
                if (rcktpt_io_addr[ctrl] <= 0)
497
                        continue;
498
                ctlp= sCtlNumToCtlPtr(ctrl);
499
 
500
#ifdef ENABLE_PCI
501
                if(ctlp->BusType == isPCI)
502
                        CtlMask= sPCIGetControllerIntStatus(ctlp);
503
                else
504
#endif
505
                        CtlMask= sGetControllerIntStatus(ctlp);
506
                for (aiop=0; CtlMask; CtlMask >>= 1, aiop++) {
507
                        if (CtlMask & 1) {
508
                                AiopMask= sGetAiopIntStatus(ctlp, aiop);
509
                                for (ch=0; AiopMask; AiopMask >>= 1, ch++) {
510
                                        if (AiopMask & 1) {
511
                                                line = (ctrl << 5) |
512
                                                        (aiop << 3) | ch;
513
                                                rp_handle_port(rp_table[line]);
514
                                        }
515
                                }
516
                        }
517
                }
518
                xmitmask = xmit_flags[ctrl];
519
                for (line = ctrl << 5; xmitmask; xmitmask >>= 1, line++) {
520
                        if (xmitmask & 1)
521
                                rp_do_transmit(rp_table[line]);
522
                }
523
        }
524
 
525
        /*
526
         * Reset the timer so we get called at the next clock tick.
527
         */
528
        if (rp_num_ports_open) {
529
                mod_timer(&rocket_timer, jiffies + 1);
530
        }
531
#ifdef TIME_STAT
532
        rdtscll(time_stat_tmp2);
533
        time_stat_tmp2 -= time_stat_tmp;
534
        time_stat += time_stat_tmp2;
535
        if (time_counter == 0)
536
                time_stat_short = time_stat_long = time_stat_tmp2;
537
        else {
538
                if ( time_stat_tmp2 < time_stat_short )
539
                        time_stat_short = time_stat_tmp2;
540
                else if ( time_stat_tmp2 > time_stat_long )
541
                        time_stat_long = time_stat_tmp2;
542
        }
543
        if ( ++time_counter == TIME_COUNTER ) {
544
                loop_time = (unsigned long) ( ((unsigned long)(time_stat >> 32) * ( (unsigned long)(0xffffffff)/(TIME_STAT_CPU * TIME_COUNTER) ) ) + ((unsigned long)time_stat/(TIME_STAT_CPU*TIME_COUNTER)));
545
#ifdef TIME_STAT_VERBOSE
546
                printk("rp_do_poll: Interrupt Timings\n");
547
                printk("     %5ld iterations; %ld us min,\n",
548
                       (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU));
549
                printk("     %5ld us max, %ld us average per iteration.\n",
550
                       (time_stat_long/TIME_STAT_CPU), loop_time);
551
                printk("We want to use < 5,000 us for an iteration.\n");
552
#else /* TIME_STAT_VERBOSE */
553
                printk("rp: %ld loops: %ld min, %ld max, %ld us/loop.\n",
554
                       (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU),
555
                       (time_stat_long/TIME_STAT_CPU), loop_time);
556
#endif /* TIME_STAT_VERBOSE */
557
                time_counter = time_stat = 0;
558
                time_stat_short = time_stat_long = 0;
559
        }
560
#endif /* TIME_STAT */
561
}
562
/*
563
 * Here ends the interrupt/polling routine.
564
 */
565
 
566
 
567
/*
568
 * This function initializes the r_port structure, as well as enabling
569
 * the port on the RocketPort board.
570
 */
571
static void init_r_port(int board, int aiop, int chan)
572
{
573
        struct r_port *info;
574
        int line;
575
        CONTROLLER_T *ctlp;
576
        CHANNEL_t       *cp;
577
 
578
        line = (board << 5) | (aiop << 3) | chan;
579
 
580
        ctlp= sCtlNumToCtlPtr(board);
581
 
582
        info = kmalloc(sizeof(struct r_port), GFP_KERNEL);
583
        if (!info) {
584
                printk("Couldn't allocate info struct for line #%d\n", line);
585
                return;
586
        }
587
        memset(info, 0, sizeof(struct r_port));
588
 
589
        info->magic = RPORT_MAGIC;
590
        info->line = line;
591
        info->ctlp = ctlp;
592
        info->board = board;
593
        info->aiop = aiop;
594
        info->chan = chan;
595
        info->closing_wait = 3000;
596
        info->close_delay = 50;
597
        info->callout_termios =callout_driver.init_termios;
598
        info->normal_termios = rocket_driver.init_termios;
599
        init_waitqueue_head(&info->open_wait);
600
        init_waitqueue_head(&info->close_wait);
601
 
602
        info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD |
603
                DELTA_CTS | DELTA_DSR;
604
        if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
605
                printk("Rocketport sInitChan(%d, %d, %d) failed!\n",
606
                       board, aiop, chan);
607
                kfree(info);
608
                return;
609
        }
610
        cp = &info->channel;
611
        rp_table[line] = info;
612
}
613
 
614
#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
615
static int baud_table[] = {
616
        0, 50, 75, 110, 134, 150, 200, 300,
617
        600, 1200, 1800, 2400, 4800, 9600, 19200,
618
        38400, 57600, 115200, 230400, 460800, 0 };
619
#endif
620
 
621
/*
622
 * This routine configures a rocketport port so according to its
623
 * termio settings.
624
 */
625
static void configure_r_port(struct r_port *info)
626
{
627
        unsigned cflag;
628
        unsigned long   flags;
629
        int     bits, baud;
630
#if (LINUX_VERSION_CODE < 131393) /* Linux 2.1.65 */
631
        int i;
632
#endif
633
        CHANNEL_t       *cp;
634
 
635
        if (!info->tty || !info->tty->termios)
636
                return;
637
        cp = &info->channel;
638
        cflag = info->tty->termios->c_cflag;
639
 
640
        /* Byte size and parity */
641
        if ((cflag & CSIZE) == CS8) {
642
                sSetData8(cp);
643
                bits = 10;
644
        } else {
645
                sSetData7(cp);
646
                bits = 9;
647
        }
648
        if (cflag & CSTOPB) {
649
                sSetStop2(cp);
650
                bits++;
651
        } else {
652
                sSetStop1(cp);
653
        }
654
 
655
        if (cflag & PARENB) {
656
                sEnParity(cp);
657
                bits++;
658
                if (cflag & PARODD) {
659
                        sSetOddParity(cp);
660
                } else {
661
                        sSetEvenParity(cp);
662
                }
663
        } else {
664
                sDisParity(cp);
665
        }
666
 
667
        /* baud rate */
668
#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
669
        i = cflag & CBAUD;
670
        if (i & CBAUDEX) {
671
                i &= ~CBAUDEX;
672
                if (i < 1 || i > 4)
673
                        info->tty->termios->c_cflag &= ~CBAUDEX;
674
                else
675
                        i += 15;
676
        }
677
        if (i == 15) {
678
                if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
679
                        i += 1;
680
                if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
681
                        i += 2;
682
                if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
683
                        i += 3;
684
                if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
685
                        i += 4;
686
        }
687
        baud = baud_table[i] ? baud_table[i] : 9600;
688
#else
689
        baud = tty_get_baud_rate(info->tty);
690
        if (!baud)
691
                baud = 9600;
692
#endif
693
        info->cps = baud / bits;
694
        sSetBaud(cp, (rp_baud_base/baud) - 1);
695
 
696
        if (cflag & CRTSCTS) {
697
                info->intmask |= DELTA_CTS;
698
                sEnCTSFlowCtl(cp);
699
        } else {
700
                info->intmask &= ~DELTA_CTS;
701
                sDisCTSFlowCtl(cp);
702
        }
703
        sSetRTS(&info->channel);
704
        if (cflag & CLOCAL)
705
                info->intmask &= ~DELTA_CD;
706
        else {
707
                save_flags(flags); cli();
708
                if (sGetChanStatus(cp) & CD_ACT)
709
                        info->cd_status = 1;
710
                else
711
                        info->cd_status = 0;
712
                info->intmask |= DELTA_CD;
713
                restore_flags(flags);
714
        }
715
 
716
        /*
717
         * Handle software flow control in the board
718
         */
719
#ifdef ROCKET_SOFT_FLOW
720
        if (I_IXON(info->tty)) {
721
                sEnTxSoftFlowCtl(cp);
722
                if (I_IXANY(info->tty)) {
723
                        sEnIXANY(cp);
724
                } else {
725
                        sDisIXANY(cp);
726
                }
727
                sSetTxXONChar(cp, START_CHAR(info->tty));
728
                sSetTxXOFFChar(cp, STOP_CHAR(info->tty));
729
        } else {
730
                sDisTxSoftFlowCtl(cp);
731
                sDisIXANY(cp);
732
                sClrTxXOFF(cp);
733
        }
734
#endif
735
 
736
        /*
737
         * Set up ignore/read mask words
738
         */
739
        info->read_status_mask = STMRCVROVRH | 0xFF;
740
        if (I_INPCK(info->tty))
741
                info->read_status_mask |= STMFRAMEH | STMPARITYH;
742
        if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
743
                info->read_status_mask |= STMBREAKH;
744
 
745
        /*
746
         * Characters to ignore
747
         */
748
        info->ignore_status_mask = 0;
749
        if (I_IGNPAR(info->tty))
750
                info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
751
        if (I_IGNBRK(info->tty)) {
752
                info->ignore_status_mask |= STMBREAKH;
753
                /*
754
                 * If we're ignoring parity and break indicators,
755
                 * ignore overruns too.  (For real raw support).
756
                 */
757
                if (I_IGNPAR(info->tty))
758
                        info->ignore_status_mask |= STMRCVROVRH;
759
        }
760
}
761
 
762
static int block_til_ready(struct tty_struct *tty, struct file * filp,
763
                           struct r_port *info)
764
{
765
        DECLARE_WAITQUEUE(wait, current);
766
        int             retval;
767
        int             do_clocal = 0, extra_count = 0;
768
        unsigned long   flags;
769
 
770
        /*
771
         * If the device is in the middle of being closed, then block
772
         * until it's done, and then try again.
773
         */
774
        if (tty_hung_up_p(filp))
775
                return ((info->flags & ROCKET_HUP_NOTIFY) ?
776
                        -EAGAIN : -ERESTARTSYS);
777
        if (info->flags & ROCKET_CLOSING) {
778
                interruptible_sleep_on(&info->close_wait);
779
                return ((info->flags & ROCKET_HUP_NOTIFY) ?
780
                        -EAGAIN : -ERESTARTSYS);
781
        }
782
 
783
        /*
784
         * If this is a callout device, then just make sure the normal
785
         * device isn't being used.
786
         */
787
        if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
788
                if (info->flags & ROCKET_NORMAL_ACTIVE)
789
                        return -EBUSY;
790
                if ((info->flags & ROCKET_CALLOUT_ACTIVE) &&
791
                    (info->flags & ROCKET_SESSION_LOCKOUT) &&
792
                    (info->session != current->session))
793
                    return -EBUSY;
794
                if ((info->flags & ROCKET_CALLOUT_ACTIVE) &&
795
                    (info->flags & ROCKET_PGRP_LOCKOUT) &&
796
                    (info->pgrp != current->pgrp))
797
                    return -EBUSY;
798
                info->flags |= ROCKET_CALLOUT_ACTIVE;
799
                return 0;
800
        }
801
 
802
        /*
803
         * If non-blocking mode is set, or the port is not enabled,
804
         * then make the check up front and then exit.
805
         */
806
        if ((filp->f_flags & O_NONBLOCK) ||
807
            (tty->flags & (1 << TTY_IO_ERROR))) {
808
                if (info->flags & ROCKET_CALLOUT_ACTIVE)
809
                        return -EBUSY;
810
                info->flags |= ROCKET_NORMAL_ACTIVE;
811
                return 0;
812
        }
813
 
814
        if (info->flags & ROCKET_CALLOUT_ACTIVE) {
815
                if (info->normal_termios.c_cflag & CLOCAL)
816
                        do_clocal = 1;
817
        } else {
818
                if (tty->termios->c_cflag & CLOCAL)
819
                        do_clocal = 1;
820
        }
821
 
822
        /*
823
         * Block waiting for the carrier detect and the line to become
824
         * free (i.e., not in use by the callout).  While we are in
825
         * this loop, info->count is dropped by one, so that
826
         * rp_close() knows when to free things.  We restore it upon
827
         * exit, either normal or abnormal.
828
         */
829
        retval = 0;
830
        add_wait_queue(&info->open_wait, &wait);
831
#ifdef ROCKET_DEBUG_OPEN
832
        printk("block_til_ready before block: ttyR%d, count = %d\n",
833
               info->line, info->count);
834
#endif
835
        save_flags(flags); cli();
836
        if (!tty_hung_up_p(filp)) {
837
                extra_count = 1;
838
                info->count--;
839
        }
840
        restore_flags(flags);
841
        info->blocked_open++;
842
        while (1) {
843
                if (!(info->flags & ROCKET_CALLOUT_ACTIVE) &&
844
                    (tty->termios->c_cflag & CBAUD)) {
845
                        sSetDTR(&info->channel);
846
                        sSetRTS(&info->channel);
847
                }
848
                set_current_state(TASK_INTERRUPTIBLE);
849
                if (tty_hung_up_p(filp) ||
850
                    !(info->flags & ROCKET_INITIALIZED)) {
851
                        if (info->flags & ROCKET_HUP_NOTIFY)
852
                                retval = -EAGAIN;
853
                        else
854
                                retval = -ERESTARTSYS;
855
                        break;
856
                }
857
                if (!(info->flags & ROCKET_CALLOUT_ACTIVE) &&
858
                    !(info->flags & ROCKET_CLOSING) &&
859
                    (do_clocal || (sGetChanStatusLo(&info->channel) &
860
                                   CD_ACT)))
861
                        break;
862
                if (signal_pending(current)) {
863
                        retval = -ERESTARTSYS;
864
                        break;
865
                }
866
#ifdef ROCKET_DEBUG_OPEN
867
                printk("block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n",
868
                       info->line, info->count, info->flags);
869
#endif
870
                schedule();
871
        }
872
        current->state = TASK_RUNNING;
873
        remove_wait_queue(&info->open_wait, &wait);
874
        cli();
875
        if (extra_count)
876
                info->count++;
877
        restore_flags(flags);
878
        info->blocked_open--;
879
#ifdef ROCKET_DEBUG_OPEN
880
        printk("block_til_ready after blocking: ttyR%d, count = %d\n",
881
               info->line, info->count);
882
#endif
883
        if (retval)
884
                return retval;
885
        info->flags |= ROCKET_NORMAL_ACTIVE;
886
        return 0;
887
}
888
 
889
/*
890
 * This routine is called whenever a rocketport board is opened.
891
 */
892
static int rp_open(struct tty_struct *tty, struct file * filp)
893
{
894
        struct r_port *info;
895
        int     line, retval;
896
        CHANNEL_t       *cp;
897
        unsigned long page;
898
 
899
        line = MINOR(tty->device) - tty->driver.minor_start;
900
        if ((line < 0) || (line >= MAX_RP_PORTS))
901
                return -ENODEV;
902
        if (!tmp_buf) {
903
                page = get_free_page(GFP_KERNEL);
904
                if (!page)
905
                        return -ENOMEM;
906
                if (tmp_buf)
907
                        free_page(page);
908
                else
909
                        tmp_buf = (unsigned char *) page;
910
        }
911
        page = get_free_page(GFP_KERNEL);
912
        if (!page)
913
                return -ENOMEM;
914
 
915
        tty->driver_data = info = rp_table[line];
916
 
917
        if (info->flags & ROCKET_CLOSING) {
918
                interruptible_sleep_on(&info->close_wait);
919
                free_page(page);
920
                return ((info->flags & ROCKET_HUP_NOTIFY) ?
921
                        -EAGAIN : -ERESTARTSYS);
922
        }
923
 
924
        /*
925
         * We must not sleep from here until the port is marked fully
926
         * in use.
927
         */
928
        if (rp_table[line] == NULL) {
929
                tty->flags = (1 << TTY_IO_ERROR);
930
                free_page(page);
931
                return 0;
932
        }
933
        if (!info) {
934
                printk("rp_open: rp_table[%d] is NULL!\n", line);
935
                free_page(page);
936
                return -EIO;
937
        }
938
        if (info->xmit_buf)
939
                free_page(page);
940
        else
941
                info->xmit_buf = (unsigned char *) page;
942
        info->tty = tty;
943
 
944
        if (info->flags & ROCKET_CLOSING) {
945
                interruptible_sleep_on(&info->close_wait);
946
                return ((info->flags & ROCKET_HUP_NOTIFY) ?
947
                        -EAGAIN : -ERESTARTSYS);
948
        }
949
 
950
        if (info->count++ == 0) {
951
#ifdef MODULE
952
                MOD_INC_USE_COUNT;
953
#endif
954
                rp_num_ports_open++;
955
#ifdef ROCKET_DEBUG_OPEN
956
                printk("rocket mod++ = %d...", rp_num_ports_open);
957
#endif
958
        }
959
#ifdef ROCKET_DEBUG_OPEN
960
        printk("rp_open ttyR%d, count=%d\n", info->line, info->count);
961
#endif
962
        /*
963
         * Info->count is now 1; so it's safe to sleep now.
964
         */
965
        info->session = current->session;
966
        info->pgrp = current->pgrp;
967
 
968
        cp = &info->channel;
969
        sSetRxTrigger(cp, TRIG_1);
970
        if (sGetChanStatus(cp) & CD_ACT)
971
                info->cd_status = 1;
972
        else
973
                info->cd_status = 0;
974
        sDisRxStatusMode(cp);
975
        sFlushRxFIFO(cp);
976
        sFlushTxFIFO(cp);
977
 
978
        sEnInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
979
        sSetRxTrigger(cp, TRIG_1);
980
 
981
        sGetChanStatus(cp);
982
        sDisRxStatusMode(cp);
983
        sClrTxXOFF(cp);
984
 
985
        sDisCTSFlowCtl(cp);
986
        sDisTxSoftFlowCtl(cp);
987
 
988
        sEnRxFIFO(cp);
989
        sEnTransmit(cp);
990
 
991
        info->flags |= ROCKET_INITIALIZED;
992
 
993
#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
994
        /*
995
         * Set up the tty->alt_speed kludge
996
         */
997
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
998
                info->tty->alt_speed = 57600;
999
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
1000
                info->tty->alt_speed = 115200;
1001
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
1002
                info->tty->alt_speed = 230400;
1003
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
1004
                info->tty->alt_speed = 460800;
1005
#endif
1006
 
1007
        configure_r_port(info);
1008
        if (tty->termios->c_cflag & CBAUD) {
1009
                sSetDTR(cp);
1010
                sSetRTS(cp);
1011
        }
1012
 
1013
        mod_timer(&rocket_timer, jiffies + 1);
1014
 
1015
        retval = block_til_ready(tty, filp, info);
1016
        if (retval) {
1017
#ifdef ROCKET_DEBUG_OPEN
1018
                printk("rp_open returning after block_til_ready with %d\n",
1019
                       retval);
1020
#endif
1021
                return retval;
1022
        }
1023
 
1024
        if ((info->count == 1) && (info->flags & ROCKET_SPLIT_TERMIOS)) {
1025
                if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
1026
                        *tty->termios = info->normal_termios;
1027
                else
1028
                        *tty->termios = info->callout_termios;
1029
                configure_r_port(info);
1030
        }
1031
 
1032
        return 0;
1033
}
1034
 
1035
static void rp_close(struct tty_struct *tty, struct file * filp)
1036
{
1037
        struct r_port * info = (struct r_port *)tty->driver_data;
1038
        unsigned long flags;
1039
        int timeout;
1040
        CHANNEL_t       *cp;
1041
 
1042
        if (rocket_paranoia_check(info, tty->device, "rp_close"))
1043
                return;
1044
 
1045
#ifdef ROCKET_DEBUG_OPEN
1046
        printk("rp_close ttyR%d, count = %d\n", info->line, info->count);
1047
#endif
1048
 
1049
        save_flags(flags); cli();
1050
 
1051
        if (tty_hung_up_p(filp)) {
1052
                restore_flags(flags);
1053
                return;
1054
        }
1055
        if ((tty->count == 1) && (info->count != 1)) {
1056
                /*
1057
                 * Uh, oh.  tty->count is 1, which means that the tty
1058
                 * structure will be freed.  Info->count should always
1059
                 * be one in these conditions.  If it's greater than
1060
                 * one, we've got real problems, since it means the
1061
                 * serial port won't be shutdown.
1062
                 */
1063
                printk("rp_close: bad serial port count; tty->count is 1, "
1064
                       "info->count is %d\n", info->count);
1065
                info->count = 1;
1066
        }
1067
        if (--info->count < 0) {
1068
                printk("rp_close: bad serial port count for ttyR%d: %d\n",
1069
                       info->line, info->count);
1070
                info->count = 0;
1071
        }
1072
        if (info->count) {
1073
                restore_flags(flags);
1074
                return;
1075
        }
1076
        info->flags |= ROCKET_CLOSING;
1077
        /*
1078
         * Save the termios structure, since this port may have
1079
         * separate termios for callout and dialin.
1080
         */
1081
        if (info->flags & ROCKET_NORMAL_ACTIVE)
1082
                info->normal_termios = *tty->termios;
1083
        if (info->flags & ROCKET_CALLOUT_ACTIVE)
1084
                info->callout_termios = *tty->termios;
1085
 
1086
        cp = &info->channel;
1087
 
1088
        /*
1089
         * Notify the line discpline to only process XON/XOFF characters
1090
         */
1091
        tty->closing = 1;
1092
 
1093
        /*
1094
         * If transmission was throttled by the application request,
1095
         * just flush the xmit buffer.
1096
         */
1097
#if (LINUX_VERSION_CODE >= 131343)
1098
        if (tty->flow_stopped)
1099
                rp_flush_buffer(tty);
1100
#endif
1101
 
1102
        /*
1103
         * Wait for the transmit buffer to clear
1104
         */
1105
        if (info->closing_wait != ROCKET_CLOSING_WAIT_NONE)
1106
                tty_wait_until_sent(tty, info->closing_wait);
1107
        /*
1108
         * Before we drop DTR, make sure the UART transmitter
1109
         * has completely drained; this is especially
1110
         * important if there is a transmit FIFO!
1111
         */
1112
        timeout = (sGetTxCnt(cp)+1) * HZ / info->cps;
1113
        if (timeout == 0)
1114
                timeout = 1;
1115
        rp_wait_until_sent(tty, timeout);
1116
 
1117
        xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
1118
        sDisTransmit(cp);
1119
        sDisInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
1120
        sDisCTSFlowCtl(cp);
1121
        sDisTxSoftFlowCtl(cp);
1122
        sClrTxXOFF(cp);
1123
        sFlushRxFIFO(cp);
1124
        sFlushTxFIFO(cp);
1125
        sClrRTS(cp);
1126
        if (C_HUPCL(tty)) {
1127
                sClrDTR(cp);
1128
        }
1129
        if (tty->driver.flush_buffer)
1130
                tty->driver.flush_buffer(tty);
1131
        if (tty->ldisc.flush_buffer)
1132
                tty->ldisc.flush_buffer(tty);
1133
 
1134
        xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
1135
        if (info->blocked_open) {
1136
                if (info->close_delay) {
1137
                        current->state = TASK_INTERRUPTIBLE;
1138
                        schedule_timeout(info->close_delay);
1139
                }
1140
                wake_up_interruptible(&info->open_wait);
1141
        } else {
1142
                if (info->xmit_buf) {
1143
                        free_page((unsigned long) info->xmit_buf);
1144
                        info->xmit_buf = 0;
1145
                }
1146
        }
1147
        info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING |
1148
                         ROCKET_CALLOUT_ACTIVE | ROCKET_NORMAL_ACTIVE);
1149
        tty->closing = 0;
1150
        wake_up_interruptible(&info->close_wait);
1151
 
1152
#ifdef MODULE
1153
        MOD_DEC_USE_COUNT;
1154
#endif
1155
        rp_num_ports_open--;
1156
#ifdef ROCKET_DEBUG_OPEN
1157
        printk("rocket mod-- = %d...", rp_num_ports_open);
1158
#endif
1159
        restore_flags(flags);
1160
 
1161
#ifdef ROCKET_DEBUG_OPEN
1162
        printk("rp_close ttyR%d complete shutdown\n", info->line);
1163
#endif
1164
 
1165
}
1166
 
1167
static void rp_set_termios(struct tty_struct *tty, struct termios *old_termios)
1168
{
1169
        struct r_port * info = (struct r_port *)tty->driver_data;
1170
        CHANNEL_t *cp;
1171
        unsigned cflag;
1172
 
1173
 
1174
        if (rocket_paranoia_check(info, tty->device, "rp_set_termios"))
1175
                return;
1176
 
1177
        cflag = tty->termios->c_cflag;
1178
 
1179
        if (cflag == old_termios->c_cflag)
1180
                return;
1181
 
1182
        /*
1183
         * This driver doesn't support CS5 or CS6
1184
         */
1185
        if (((cflag & CSIZE) == CS5) ||
1186
            ((cflag & CSIZE) == CS6))
1187
                tty->termios->c_cflag = ((cflag & ~CSIZE) |
1188
                                         (old_termios->c_cflag & CSIZE));
1189
 
1190
        configure_r_port(info);
1191
 
1192
        cp = &info->channel;
1193
 
1194
        /* Handle transition to B0 status */
1195
        if ((old_termios->c_cflag & CBAUD) &&
1196
            !(tty->termios->c_cflag & CBAUD)) {
1197
                sClrDTR(cp);
1198
                sClrRTS(cp);
1199
        }
1200
 
1201
        /* Handle transition away from B0 status */
1202
        if (!(old_termios->c_cflag & CBAUD) &&
1203
            (tty->termios->c_cflag & CBAUD)) {
1204
                if (!tty->hw_stopped ||
1205
                    !(tty->termios->c_cflag & CRTSCTS)) {
1206
                        sSetRTS(cp);
1207
                }
1208
                sSetDTR(cp);
1209
        }
1210
 
1211
        if ((old_termios->c_cflag & CRTSCTS) &&
1212
            !(tty->termios->c_cflag & CRTSCTS)) {
1213
                tty->hw_stopped = 0;
1214
                rp_start(tty);
1215
        }
1216
}
1217
 
1218
/*
1219
 * Here are the routines used by rp_ioctl
1220
 */
1221
#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
1222
static void send_break( struct r_port * info, int duration)
1223
{
1224
        current->state = TASK_INTERRUPTIBLE;
1225
        cli();
1226
        sSendBreak(&info->channel);
1227
        schedule_timeout(duration);
1228
        sClrBreak(&info->channel);
1229
        sti();
1230
}
1231
#else
1232
static void rp_break(struct tty_struct *tty, int break_state)
1233
{
1234
        struct r_port * info = (struct r_port *)tty->driver_data;
1235
        unsigned long flags;
1236
 
1237
        if (rocket_paranoia_check(info, tty->device, "rp_break"))
1238
                return;
1239
 
1240
        save_flags(flags); cli();
1241
        if (break_state == -1) {
1242
                sSendBreak(&info->channel);
1243
        } else {
1244
                sClrBreak(&info->channel);
1245
        }
1246
        restore_flags(flags);
1247
}
1248
#endif
1249
 
1250
static int get_modem_info(struct r_port * info, unsigned int *value)
1251
{
1252
        unsigned int control, result, ChanStatus;
1253
 
1254
        ChanStatus = sGetChanStatusLo(&info->channel);
1255
 
1256
        control = info->channel.TxControl[3];
1257
        result =  ((control & SET_RTS) ? TIOCM_RTS : 0)
1258
                | ((control & SET_DTR) ? TIOCM_DTR : 0)
1259
                | ((ChanStatus  & CD_ACT) ? TIOCM_CAR : 0)
1260
                        /* TIOCM_RNG not supported */
1261
                | ((ChanStatus  & DSR_ACT) ? TIOCM_DSR : 0)
1262
                | ((ChanStatus  & CTS_ACT) ? TIOCM_CTS : 0);
1263
 
1264
        if (copy_to_user(value, &result, sizeof(int)))
1265
                return -EFAULT;
1266
        return 0;
1267
}
1268
 
1269
static int set_modem_info(struct r_port * info, unsigned int cmd,
1270
                          unsigned int *value)
1271
{
1272
        unsigned int arg;
1273
 
1274
        if (copy_from_user(&arg, value, sizeof(int)))
1275
                return -EFAULT;
1276
 
1277
        switch (cmd) {
1278
        case TIOCMBIS:
1279
                if (arg & TIOCM_RTS)
1280
                        info->channel.TxControl[3] |= SET_RTS;
1281
                if (arg & TIOCM_DTR)
1282
                        info->channel.TxControl[3] |= SET_DTR;
1283
                break;
1284
        case TIOCMBIC:
1285
                if (arg & TIOCM_RTS)
1286
                        info->channel.TxControl[3] &= ~SET_RTS;
1287
                if (arg & TIOCM_DTR)
1288
                        info->channel.TxControl[3] &= ~SET_DTR;
1289
                break;
1290
        case TIOCMSET:
1291
                info->channel.TxControl[3] =
1292
                        ((info->channel.TxControl[3] & ~(SET_RTS | SET_DTR))
1293
                         | ((arg & TIOCM_RTS) ? SET_RTS : 0)
1294
                         | ((arg & TIOCM_DTR) ? SET_DTR : 0));
1295
                break;
1296
        default:
1297
                return -EINVAL;
1298
        }
1299
 
1300
        sOutDW(info->channel.IndexAddr,
1301
               *(DWord_t *) &(info->channel.TxControl[0]));
1302
 
1303
        return 0;
1304
}
1305
 
1306
static int get_config(struct r_port * info, struct rocket_config * retinfo)
1307
{
1308
        struct rocket_config tmp;
1309
 
1310
        if (!retinfo)
1311
                return -EFAULT;
1312
        memset(&tmp, 0, sizeof(tmp));
1313
        tmp.line = info->line;
1314
        tmp.flags = info->flags;
1315
        tmp.close_delay = info->close_delay;
1316
        tmp.closing_wait = info->closing_wait;
1317
        tmp.port = rcktpt_io_addr[(info->line >> 5) & 3];
1318
 
1319
        if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
1320
                return -EFAULT;
1321
        return 0;
1322
}
1323
 
1324
static int set_config(struct r_port * info, struct rocket_config * new_info)
1325
{
1326
        struct rocket_config new_serial;
1327
 
1328
        if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
1329
                return -EFAULT;
1330
 
1331
#ifdef CAP_SYS_ADMIN
1332
        if (!capable(CAP_SYS_ADMIN))
1333
#else
1334
        if (!suser())
1335
#endif
1336
        {
1337
                if ((new_serial.flags & ~ROCKET_USR_MASK) !=
1338
                    (info->flags & ~ROCKET_USR_MASK))
1339
                        return -EPERM;
1340
                info->flags = ((info->flags & ~ROCKET_USR_MASK) |
1341
                               (new_serial.flags & ROCKET_USR_MASK));
1342
                configure_r_port(info);
1343
                return 0;
1344
        }
1345
 
1346
        info->flags = ((info->flags & ~ROCKET_FLAGS) |
1347
                        (new_serial.flags & ROCKET_FLAGS));
1348
        info->close_delay = new_serial.close_delay;
1349
        info->closing_wait = new_serial.closing_wait;
1350
 
1351
#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
1352
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
1353
                info->tty->alt_speed = 57600;
1354
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
1355
                info->tty->alt_speed = 115200;
1356
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
1357
                info->tty->alt_speed = 230400;
1358
        if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
1359
                info->tty->alt_speed = 460800;
1360
#endif
1361
 
1362
        configure_r_port(info);
1363
        return 0;
1364
}
1365
 
1366
static int get_ports(struct r_port * info, struct rocket_ports * retports)
1367
{
1368
        struct rocket_ports tmp;
1369
        int     board, port, index;
1370
 
1371
        if (!retports)
1372
                return -EFAULT;
1373
        memset(&tmp, 0, sizeof(tmp));
1374
        tmp.tty_major = rocket_driver.major;
1375
        tmp.callout_major = callout_driver.major;
1376
        for (board = 0; board < 4; board++) {
1377
                index = board << 5;
1378
                for (port = 0; port < 32; port++, index++) {
1379
                        if (rp_table[index])
1380
                                tmp.port_bitmap[board] |= 1 << port;
1381
                }
1382
        }
1383
        if (copy_to_user(retports,&tmp,sizeof(*retports)))
1384
                return -EFAULT;
1385
        return 0;
1386
}
1387
 
1388
static int rp_ioctl(struct tty_struct *tty, struct file * file,
1389
                    unsigned int cmd, unsigned long arg)
1390
{
1391
        struct r_port * info = (struct r_port *)tty->driver_data;
1392
#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
1393
        int retval, tmp;
1394
#endif
1395
 
1396
        if (cmd != RCKP_GET_PORTS &&
1397
            rocket_paranoia_check(info, tty->device, "rp_ioctl"))
1398
                return -ENODEV;
1399
 
1400
        switch (cmd) {
1401
#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
1402
                case TCSBRK:    /* SVID version: non-zero arg --> no break */
1403
                        retval = tty_check_change(tty);
1404
                        if (retval)
1405
                                return retval;
1406
                        tty_wait_until_sent(tty, 0);
1407
                        if (signal_pending(current))
1408
                                return -EINTR;
1409
                        if (!arg) {
1410
                                send_break(info, HZ/4); /* 1/4 second */
1411
                                if (signal_pending(current))
1412
                                        return -EINTR;
1413
                        }
1414
                        return 0;
1415
                case TCSBRKP:   /* support for POSIX tcsendbreak() */
1416
                        retval = tty_check_change(tty);
1417
                        if (retval)
1418
                                return retval;
1419
                        tty_wait_until_sent(tty, 0);
1420
                        if (signal_pending(current))
1421
                                return -EINTR;
1422
                        send_break(info, arg ? arg*(HZ/10) : HZ/4);
1423
                        if (signal_pending(current))
1424
                                return -EINTR;
1425
                        return 0;
1426
                case TIOCGSOFTCAR:
1427
                        tmp = C_CLOCAL(tty) ? 1 : 0;
1428
                        if (copy_to_user((void *)arg, &tmp, sizeof(int)))
1429
                                return -EFAULT;
1430
                        return 0;
1431
                case TIOCSSOFTCAR:
1432
                        if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
1433
                                return -EFAULT;
1434
 
1435
                        tty->termios->c_cflag =
1436
                                ((tty->termios->c_cflag & ~CLOCAL) |
1437
                                 (tmp ? CLOCAL : 0));
1438
                        return 0;
1439
#endif
1440
                case TIOCMGET:
1441
                        return get_modem_info(info, (unsigned int *) arg);
1442
                case TIOCMBIS:
1443
                case TIOCMBIC:
1444
                case TIOCMSET:
1445
                        return set_modem_info(info, cmd, (unsigned int *) arg);
1446
                case RCKP_GET_STRUCT:
1447
                        if (copy_to_user((void *) arg, info,
1448
                                         sizeof(struct r_port)))
1449
                                return -EFAULT;
1450
                        return 0;
1451
 
1452
                case RCKP_GET_CONFIG:
1453
                        return get_config(info, (struct rocket_config *) arg);
1454
                case RCKP_SET_CONFIG:
1455
                        return set_config(info, (struct rocket_config *) arg);
1456
 
1457
                case RCKP_GET_PORTS:
1458
                        return get_ports(info, (struct rocket_ports *) arg);
1459
                default:
1460
                        return -ENOIOCTLCMD;
1461
                }
1462
        return 0;
1463
}
1464
 
1465
#if (defined(ROCKET_DEBUG_FLOW) || defined(ROCKET_DEBUG_THROTTLE))
1466
static char *rp_tty_name(struct tty_struct *tty, char *buf)
1467
{
1468
        if (tty)
1469
                sprintf(buf, "%s%d", tty->driver.name,
1470
                        MINOR(tty->device) - tty->driver.minor_start +
1471
                        tty->driver.name_base);
1472
        else
1473
                strcpy(buf, "NULL tty");
1474
        return buf;
1475
}
1476
#endif
1477
 
1478
static void rp_send_xchar(struct tty_struct *tty, char ch)
1479
{
1480
        struct r_port *info = (struct r_port *)tty->driver_data;
1481
        CHANNEL_t *cp;
1482
 
1483
        if (rocket_paranoia_check(info, tty->device, "rp_send_xchar"))
1484
                return;
1485
 
1486
        cp = &info->channel;
1487
        if (sGetTxCnt(cp))
1488
                sWriteTxPrioByte(cp, ch);
1489
        else
1490
                sWriteTxByte(sGetTxRxDataIO(cp), ch);
1491
}
1492
 
1493
static void rp_throttle(struct tty_struct * tty)
1494
{
1495
        struct r_port *info = (struct r_port *)tty->driver_data;
1496
        CHANNEL_t *cp;
1497
#ifdef ROCKET_DEBUG_THROTTLE
1498
        char    buf[64];
1499
 
1500
        printk("throttle %s: %d....\n", rp_tty_name(tty, buf),
1501
               tty->ldisc.chars_in_buffer(tty));
1502
#endif
1503
 
1504
        if (rocket_paranoia_check(info, tty->device, "rp_throttle"))
1505
                return;
1506
 
1507
        cp = &info->channel;
1508
        if (I_IXOFF(tty))
1509
                rp_send_xchar(tty, STOP_CHAR(tty));
1510
 
1511
        sClrRTS(&info->channel);
1512
}
1513
 
1514
static void rp_unthrottle(struct tty_struct * tty)
1515
{
1516
        struct r_port *info = (struct r_port *)tty->driver_data;
1517
        CHANNEL_t *cp;
1518
#ifdef ROCKET_DEBUG_THROTTLE
1519
        char    buf[64];
1520
 
1521
        printk("unthrottle %s: %d....\n", rp_tty_name(tty, buf),
1522
               tty->ldisc.chars_in_buffer(tty));
1523
#endif
1524
 
1525
        if (rocket_paranoia_check(info, tty->device, "rp_throttle"))
1526
                return;
1527
 
1528
        cp = &info->channel;
1529
        if (I_IXOFF(tty))
1530
                rp_send_xchar(tty, START_CHAR(tty));
1531
 
1532
        sSetRTS(&info->channel);
1533
}
1534
 
1535
/*
1536
 * ------------------------------------------------------------
1537
 * rp_stop() and rp_start()
1538
 *
1539
 * This routines are called before setting or resetting tty->stopped.
1540
 * They enable or disable transmitter interrupts, as necessary.
1541
 * ------------------------------------------------------------
1542
 */
1543
static void rp_stop(struct tty_struct *tty)
1544
{
1545
        struct r_port * info = (struct r_port *)tty->driver_data;
1546
#ifdef ROCKET_DEBUG_FLOW
1547
        char    buf[64];
1548
 
1549
        printk("stop %s: %d %d....\n", rp_tty_name(tty, buf),
1550
               info->xmit_cnt, info->xmit_fifo_room);
1551
#endif
1552
 
1553
        if (rocket_paranoia_check(info, tty->device, "rp_stop"))
1554
                return;
1555
 
1556
        if (sGetTxCnt(&info->channel))
1557
                sDisTransmit(&info->channel);
1558
}
1559
 
1560
static void rp_start(struct tty_struct *tty)
1561
{
1562
        struct r_port * info = (struct r_port *)tty->driver_data;
1563
#ifdef ROCKET_DEBUG_FLOW
1564
        char    buf[64];
1565
 
1566
        printk("start %s: %d %d....\n", rp_tty_name(tty, buf),
1567
               info->xmit_cnt, info->xmit_fifo_room);
1568
#endif
1569
 
1570
        if (rocket_paranoia_check(info, tty->device, "rp_stop"))
1571
                return;
1572
 
1573
        sEnTransmit(&info->channel);
1574
        xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f));
1575
}
1576
 
1577
/*
1578
 * rp_wait_until_sent() --- wait until the transmitter is empty
1579
 */
1580
static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
1581
{
1582
        struct r_port *info = (struct r_port *)tty->driver_data;
1583
        CHANNEL_t *cp;
1584
        unsigned long orig_jiffies;
1585
        int check_time, exit_time;
1586
        int txcnt;
1587
 
1588
        if (rocket_paranoia_check(info, tty->device, "rp_wait_until_sent"))
1589
                return;
1590
 
1591
        cp = &info->channel;
1592
 
1593
        orig_jiffies = jiffies;
1594
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1595
        printk("In RP_wait_until_sent(%d) (jiff=%lu)...", timeout, jiffies);
1596
        printk("cps=%d...", info->cps);
1597
#endif
1598
        while (1) {
1599
                txcnt = sGetTxCnt(cp);
1600
                if (!txcnt) {
1601
                        if (sGetChanStatusLo(cp) & TXSHRMT)
1602
                                break;
1603
                        check_time = (HZ / info->cps) / 5;
1604
                } else
1605
                        check_time = HZ * txcnt / info->cps;
1606
                if (timeout) {
1607
                        exit_time = orig_jiffies + timeout - jiffies;
1608
                        if (exit_time <= 0)
1609
                                break;
1610
                        if (exit_time < check_time)
1611
                                check_time = exit_time;
1612
                }
1613
                if (check_time == 0)
1614
                        check_time = 1;
1615
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1616
                printk("txcnt = %d (jiff=%lu,check=%d)...", txcnt,
1617
                       jiffies, check_time);
1618
#endif
1619
                current->state = TASK_INTERRUPTIBLE;
1620
                schedule_timeout(check_time);
1621
                if (signal_pending(current))
1622
                        break;
1623
        }
1624
        current->state = TASK_RUNNING;
1625
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1626
        printk("txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
1627
#endif
1628
}
1629
 
1630
/*
1631
 * rp_hangup() --- called by tty_hangup() when a hangup is signaled.
1632
 */
1633
static void rp_hangup(struct tty_struct *tty)
1634
{
1635
        CHANNEL_t       *cp;
1636
        struct r_port * info = (struct r_port *)tty->driver_data;
1637
 
1638
        if (rocket_paranoia_check(info, tty->device, "rp_hangup"))
1639
                return;
1640
 
1641
#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
1642
        printk("rp_hangup of ttyR%d...", info->line);
1643
#endif
1644
        /*
1645
         * If the port is in the process of being closed, just force
1646
         * the transmit buffer to be empty, and let rp_close handle
1647
         * the clean up.
1648
         */
1649
        if (info->flags & ROCKET_CLOSING) {
1650
                cli();
1651
                info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1652
                sti();
1653
                wake_up_interruptible(&tty->write_wait);
1654
                return;
1655
        }
1656
        if (info->count) {
1657
#ifdef MODULE
1658
                MOD_DEC_USE_COUNT;
1659
#endif
1660
                rp_num_ports_open--;
1661
        }
1662
 
1663
        xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
1664
        info->count = 0;
1665
        info->flags &= ~(ROCKET_NORMAL_ACTIVE|ROCKET_CALLOUT_ACTIVE);
1666
        info->tty = 0;
1667
 
1668
        cp = &info->channel;
1669
        sDisRxFIFO(cp);
1670
        sDisTransmit(cp);
1671
        sDisInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
1672
        sDisCTSFlowCtl(cp);
1673
        sDisTxSoftFlowCtl(cp);
1674
        sClrTxXOFF(cp);
1675
        info->flags &= ~ROCKET_INITIALIZED;
1676
 
1677
        wake_up_interruptible(&info->open_wait);
1678
}
1679
 
1680
/*
1681
 * The Rocketport write routines.  The Rocketport driver uses a
1682
 * double-buffering strategy, with the twist that if the in-memory CPU
1683
 * buffer is empty, and there's space in the transmit FIFO, the
1684
 * writing routines will write directly to transmit FIFO.
1685
 *
1686
 * This gets a little tricky, but I'm pretty sure I got it all right.
1687
 */
1688
static void rp_put_char(struct tty_struct *tty, unsigned char ch)
1689
{
1690
        struct r_port * info = (struct r_port *)tty->driver_data;
1691
        CHANNEL_t       *cp;
1692
 
1693
        if (rocket_paranoia_check(info, tty->device, "rp_put_char"))
1694
                return;
1695
 
1696
#ifdef ROCKET_DEBUG_WRITE
1697
        printk("rp_put_char %c...", ch);
1698
#endif
1699
 
1700
        cp = &info->channel;
1701
 
1702
        if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
1703
                info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1704
 
1705
        if (tty->stopped || tty->hw_stopped ||
1706
            info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
1707
                info->xmit_buf[info->xmit_head++] = ch;
1708
                info->xmit_head &= XMIT_BUF_SIZE-1;
1709
                info->xmit_cnt++;
1710
                xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f));
1711
        } else {
1712
                sOutB(sGetTxRxDataIO(cp), ch);
1713
                info->xmit_fifo_room--;
1714
        }
1715
}
1716
 
1717
static int rp_write(struct tty_struct * tty, int from_user,
1718
                    const unsigned char *buf, int count)
1719
{
1720
        struct r_port * info = (struct r_port *)tty->driver_data;
1721
        CHANNEL_t       *cp;
1722
        const unsigned char     *b;
1723
        int             c, retval = 0;
1724
        unsigned long   flags;
1725
 
1726
        if (count <= 0 || rocket_paranoia_check(info, tty->device, "rp_write"))
1727
                return 0;
1728
 
1729
#ifdef ROCKET_DEBUG_WRITE
1730
        printk("rp_write %d chars...", count);
1731
#endif
1732
        cp = &info->channel;
1733
 
1734
        if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
1735
                info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1736
 
1737
        if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0
1738
            && info->xmit_fifo_room >= 0) {
1739
                c = MIN(count, info->xmit_fifo_room);
1740
                b = buf;
1741
                if (from_user) {
1742
                        down(&tmp_buf_sem);
1743
                        c -= copy_from_user(tmp_buf, buf, c);
1744
                        b = tmp_buf;
1745
                        up(&tmp_buf_sem);
1746
                        /* In case we got pre-empted */
1747
                        if (!c) {
1748
                                retval = -EFAULT;
1749
                                goto end;
1750
                        }
1751
                        if (info->tty == 0)
1752
                                goto end;
1753
                        c = MIN(c, info->xmit_fifo_room);
1754
                }
1755
                sOutStrW(sGetTxRxDataIO(cp), b, c/2);
1756
                if (c & 1)
1757
                        sOutB(sGetTxRxDataIO(cp), b[c-1]);
1758
                retval += c;
1759
                buf += c;
1760
                count -= c;
1761
                info->xmit_fifo_room -= c;
1762
        }
1763
        if (!count)
1764
                goto end;
1765
 
1766
        save_flags(flags);
1767
        while (1) {
1768
                if (info->tty == 0) {
1769
                        restore_flags(flags);
1770
                        goto end;
1771
                }
1772
                c = MIN(count, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1,
1773
                                   XMIT_BUF_SIZE - info->xmit_head));
1774
                if (c <= 0)
1775
                        break;
1776
 
1777
                b = buf;
1778
                if (from_user) {
1779
                        down(&tmp_buf_sem);
1780
                        c -= copy_from_user(tmp_buf, buf, c);
1781
                        b = tmp_buf;
1782
                        up(&tmp_buf_sem);
1783
                        if (!c) {
1784
                                if (retval == 0)
1785
                                        retval = -EFAULT;
1786
                                goto end_intr;
1787
                        }
1788
                        /* In case we got pre-empted */
1789
                        if (info->tty == 0)
1790
                                goto end_intr;
1791
                }
1792
                cli();
1793
                c = MIN(c, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1,
1794
                               XMIT_BUF_SIZE - info->xmit_head));
1795
                memcpy(info->xmit_buf + info->xmit_head, b, c);
1796
                info->xmit_head = (info->xmit_head + c) & (XMIT_BUF_SIZE-1);
1797
                info->xmit_cnt += c;
1798
                restore_flags(flags);
1799
                buf += c;
1800
                count -= c;
1801
                retval += c;
1802
        }
1803
end_intr:
1804
        if ((retval > 0) && !tty->stopped && !tty->hw_stopped)
1805
                xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f));
1806
        restore_flags(flags);
1807
end:
1808
        if (info->xmit_cnt < WAKEUP_CHARS) {
1809
                if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1810
                    tty->ldisc.write_wakeup)
1811
                        (tty->ldisc.write_wakeup)(tty);
1812
                wake_up_interruptible(&tty->write_wait);
1813
        }
1814
        return retval;
1815
}
1816
 
1817
/*
1818
 * Return the number of characters that can be sent.  We estimate
1819
 * only using the in-memory transmit buffer only, and ignore the
1820
 * potential space in the transmit FIFO.
1821
 */
1822
static int rp_write_room(struct tty_struct *tty)
1823
{
1824
        struct r_port * info = (struct r_port *)tty->driver_data;
1825
        int     ret;
1826
 
1827
        if (rocket_paranoia_check(info, tty->device, "rp_write_room"))
1828
                return 0;
1829
 
1830
        ret = XMIT_BUF_SIZE - info->xmit_cnt - 1;
1831
        if (ret < 0)
1832
                ret = 0;
1833
#ifdef ROCKET_DEBUG_WRITE
1834
        printk("rp_write_room returns %d...", ret);
1835
#endif
1836
        return ret;
1837
}
1838
 
1839
/*
1840
 * Return the number of characters in the buffer.  Again, this only
1841
 * counts those characters in the in-memory transmit buffer.
1842
 */
1843
static int rp_chars_in_buffer(struct tty_struct *tty)
1844
{
1845
        struct r_port * info = (struct r_port *)tty->driver_data;
1846
        CHANNEL_t       *cp;
1847
 
1848
        if (rocket_paranoia_check(info, tty->device, "rp_chars_in_buffer"))
1849
                return 0;
1850
 
1851
        cp = &info->channel;
1852
 
1853
#ifdef ROCKET_DEBUG_WRITE
1854
        printk("rp_chars_in_buffer returns %d...", info->xmit_cnt);
1855
#endif
1856
        return info->xmit_cnt;
1857
}
1858
 
1859
static void rp_flush_buffer(struct tty_struct *tty)
1860
{
1861
        struct r_port * info = (struct r_port *)tty->driver_data;
1862
        CHANNEL_t       *cp;
1863
 
1864
        if (rocket_paranoia_check(info, tty->device, "rp_flush_buffer"))
1865
                return;
1866
 
1867
        cli();
1868
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1869
        sti();
1870
        wake_up_interruptible(&tty->write_wait);
1871
        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1872
            tty->ldisc.write_wakeup)
1873
                (tty->ldisc.write_wakeup)(tty);
1874
 
1875
        cp = &info->channel;
1876
 
1877
        sFlushTxFIFO(cp);
1878
}
1879
 
1880
#ifdef ENABLE_PCI
1881
#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
1882
/* For compatibility */
1883
static struct pci_dev *pci_find_slot(unsigned char bus,
1884
                                     unsigned char device_fn)
1885
{
1886
        unsigned short          vendor_id, device_id;
1887
        int                     ret, error;
1888
        static struct pci_dev   ret_struct;
1889
 
1890
        error = pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID,
1891
                &vendor_id);
1892
        ret = pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID,
1893
                &device_id);
1894
        if (error == 0)
1895
                error = ret;
1896
 
1897
        if (error) {
1898
                printk("PCI RocketPort error: %s not initializing due to error"
1899
                       "reading configuration space\n",
1900
                       pcibios_strerror(error));
1901
                return(0);
1902
        }
1903
 
1904
        memset(&ret_struct, 0, sizeof(ret_struct));
1905
        ret_struct.device = device_id;
1906
 
1907
        return &ret_struct;
1908
}
1909
#endif
1910
 
1911
int __init register_PCI(int i, unsigned int bus, unsigned int device_fn)
1912
{
1913
        int     num_aiops, aiop, max_num_aiops, num_chan, chan;
1914
        unsigned int    aiopio[MAX_AIOPS_PER_BOARD];
1915
        char *str;
1916
        CONTROLLER_t    *ctlp;
1917
        struct pci_dev *dev = pci_find_slot(bus, device_fn);
1918
#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
1919
        int     ret;
1920
        unsigned int port;
1921
#endif
1922
 
1923
        if (!dev)
1924
                return 0;
1925
 
1926
        if (pci_enable_device(dev))
1927
                return 0;
1928
 
1929
        rcktpt_io_addr[i] = pci_resource_start (dev, 0);
1930
        switch(dev->device) {
1931
        case PCI_DEVICE_ID_RP4QUAD:
1932
                str = "Quadcable";
1933
                max_num_aiops = 1;
1934
                break;
1935
        case PCI_DEVICE_ID_RP8OCTA:
1936
                str = "Octacable";
1937
                max_num_aiops = 1;
1938
                break;
1939
        case PCI_DEVICE_ID_RP8INTF:
1940
                str = "8";
1941
                max_num_aiops = 1;
1942
                break;
1943
        case PCI_DEVICE_ID_RP8J:
1944
                str = "8J";
1945
                max_num_aiops = 1;
1946
                break;
1947
        case PCI_DEVICE_ID_RP4J:
1948
                str = "4J";
1949
                max_num_aiops = 1;
1950
                break;
1951
        case PCI_DEVICE_ID_RP16INTF:
1952
                str = "16";
1953
                max_num_aiops = 2;
1954
                break;
1955
        case PCI_DEVICE_ID_RP32INTF:
1956
                str = "32";
1957
                max_num_aiops = 4;
1958
                break;
1959
        case PCI_DEVICE_ID_RPP4:
1960
                str = "Plus Quadcable";
1961
                max_num_aiops = 1;
1962
                break;
1963
        case PCI_DEVICE_ID_RPP8:
1964
                str = "Plus Octacable";
1965
                max_num_aiops = 1;
1966
                break;
1967
        case PCI_DEVICE_ID_RP8M:
1968
                str = "8-port Modem";
1969
                max_num_aiops = 1;
1970
                break;
1971
        default:
1972
                str = "(unknown/unsupported)";
1973
                max_num_aiops = 0;
1974
                break;
1975
        }
1976
        for(aiop=0;aiop < max_num_aiops;aiop++)
1977
                aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40);
1978
        ctlp = sCtlNumToCtlPtr(i);
1979
        num_aiops = sPCIInitController(ctlp, i,
1980
                                        aiopio, max_num_aiops, 0,
1981
                                        FREQ_DIS, 0);
1982
        printk("Rocketport controller #%d found at %02x:%02x, "
1983
               "%d AIOP(s) (PCI Rocketport %s)\n", i, bus, device_fn,
1984
               num_aiops, str);
1985
        if(num_aiops <= 0) {
1986
                rcktpt_io_addr[i] = 0;
1987
                return(0);
1988
        }
1989
        for(aiop = 0;aiop < num_aiops; aiop++) {
1990
                sResetAiopByNum(ctlp, aiop);
1991
                sEnAiop(ctlp, aiop);
1992
                num_chan = sGetAiopNumChan(ctlp, aiop);
1993
                for(chan=0;chan < num_chan; chan++)
1994
                        init_r_port(i, aiop, chan);
1995
        }
1996
        return(1);
1997
}
1998
 
1999
static int __init init_PCI(int boards_found)
2000
{
2001
        unsigned char   bus, device_fn;
2002
        int     i, count = 0;
2003
 
2004
        for(i=0; i < (NUM_BOARDS - boards_found); i++) {
2005
                if (!pcibios_find_device(PCI_VENDOR_ID_RP,
2006
                        PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn))
2007
                        if (register_PCI(count+boards_found, bus, device_fn))
2008
                                count++;
2009
                if (!pcibios_find_device(PCI_VENDOR_ID_RP,
2010
                        PCI_DEVICE_ID_RP8J, i, &bus, &device_fn))
2011
                        if (register_PCI(count+boards_found, bus, device_fn))
2012
                                count++;
2013
                if (!pcibios_find_device(PCI_VENDOR_ID_RP,
2014
                        PCI_DEVICE_ID_RP4J, i, &bus, &device_fn))
2015
                        if (register_PCI(count+boards_found, bus, device_fn))
2016
                                count++;
2017
                if(!pcibios_find_device(PCI_VENDOR_ID_RP,
2018
                        PCI_DEVICE_ID_RP8OCTA, i, &bus, &device_fn))
2019
                        if(register_PCI(count+boards_found, bus, device_fn))
2020
                                count++;
2021
                if(!pcibios_find_device(PCI_VENDOR_ID_RP,
2022
                        PCI_DEVICE_ID_RP8INTF, i, &bus, &device_fn))
2023
                        if(register_PCI(count+boards_found, bus, device_fn))
2024
                                count++;
2025
                if(!pcibios_find_device(PCI_VENDOR_ID_RP,
2026
                        PCI_DEVICE_ID_RP16INTF, i, &bus, &device_fn))
2027
                        if(register_PCI(count+boards_found, bus, device_fn))
2028
                                count++;
2029
                if(!pcibios_find_device(PCI_VENDOR_ID_RP,
2030
                        PCI_DEVICE_ID_RP32INTF, i, &bus, &device_fn))
2031
                        if(register_PCI(count+boards_found, bus, device_fn))
2032
                                count++;
2033
                if(!pcibios_find_device(PCI_VENDOR_ID_RP,
2034
                        PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn))
2035
                        if(register_PCI(count+boards_found, bus, device_fn))
2036
                                count++;
2037
                if(!pcibios_find_device(PCI_VENDOR_ID_RP,
2038
                        PCI_DEVICE_ID_RP8J, i, &bus, &device_fn))
2039
                        if(register_PCI(count+boards_found, bus, device_fn))
2040
                                count++;
2041
                if(!pcibios_find_device(PCI_VENDOR_ID_RP,
2042
                        PCI_DEVICE_ID_RP4J, i, &bus, &device_fn))
2043
                        if(register_PCI(count+boards_found, bus, device_fn))
2044
                                count++;
2045
                if(!pcibios_find_device(PCI_VENDOR_ID_RP,
2046
                        PCI_DEVICE_ID_RPP4, i, &bus, &device_fn))
2047
                        if(register_PCI(count+boards_found, bus, device_fn))
2048
                                count++;
2049
                if(!pcibios_find_device(PCI_VENDOR_ID_RP,
2050
                        PCI_DEVICE_ID_RPP8, i, &bus, &device_fn))
2051
                        if(register_PCI(count+boards_found, bus, device_fn))
2052
                                count++;
2053
                if(!pcibios_find_device(PCI_VENDOR_ID_RP,
2054
                        PCI_DEVICE_ID_RP8M, i, &bus, &device_fn))
2055
                        if(register_PCI(count+boards_found, bus, device_fn))
2056
                                count++;
2057
        }
2058
        return(count);
2059
}
2060
#endif
2061
 
2062
static int __init init_ISA(int i, int *reserved_controller)
2063
{
2064
        int     num_aiops, num_chan;
2065
        int     aiop, chan;
2066
        unsigned int    aiopio[MAX_AIOPS_PER_BOARD];
2067
        CONTROLLER_t    *ctlp;
2068
 
2069
        if (rcktpt_io_addr[i] == 0)
2070
                return(0);
2071
 
2072
        if (check_region(rcktpt_io_addr[i],64)) {
2073
                printk("RocketPort board address 0x%lx in use...\n",
2074
                        rcktpt_io_addr[i]);
2075
                rcktpt_io_addr[i] = 0;
2076
                return(0);
2077
        }
2078
 
2079
        for (aiop=0; aiop<MAX_AIOPS_PER_BOARD; aiop++)
2080
                aiopio[aiop]= rcktpt_io_addr[i] + (aiop * 0x400);
2081
        ctlp= sCtlNumToCtlPtr(i);
2082
        num_aiops = sInitController(ctlp, i, controller + (i*0x400),
2083
                                    aiopio, MAX_AIOPS_PER_BOARD, 0,
2084
                                    FREQ_DIS, 0);
2085
        if (num_aiops <= 0) {
2086
                rcktpt_io_addr[i] = 0;
2087
                return(0);
2088
        }
2089
        for (aiop = 0; aiop < num_aiops; aiop++) {
2090
                sResetAiopByNum(ctlp, aiop);
2091
                sEnAiop(ctlp, aiop);
2092
                num_chan = sGetAiopNumChan(ctlp,aiop);
2093
                for (chan=0; chan < num_chan; chan++)
2094
                        init_r_port(i, aiop, chan);
2095
        }
2096
        printk("Rocketport controller #%d found at 0x%lx, "
2097
               "%d AIOPs\n", i, rcktpt_io_addr[i],
2098
               num_aiops);
2099
        if (rcktpt_io_addr[i] + 0x40 == controller) {
2100
                *reserved_controller = 1;
2101
                request_region(rcktpt_io_addr[i], 68,
2102
                                       "Comtrol Rocketport");
2103
        } else {
2104
                request_region(rcktpt_io_addr[i], 64,
2105
                               "Comtrol Rocketport");
2106
        }
2107
        return(1);
2108
}
2109
 
2110
 
2111
/*
2112
 * The module "startup" routine; it's run when the module is loaded.
2113
 */
2114
int __init rp_init(void)
2115
{
2116
        int i, retval, pci_boards_found, isa_boards_found;
2117
        int     reserved_controller = 0;
2118
 
2119
        printk("Rocketport device driver module, version %s, %s\n",
2120
               ROCKET_VERSION, ROCKET_DATE);
2121
 
2122
        /*
2123
         * Set up the timer channel.  If it is already in use by
2124
         * some other driver, give up.
2125
         */
2126
        if (rocket_timer.function) {
2127
                printk("rocket.o: Timer already in use!\n");
2128
                return -EBUSY;
2129
        }
2130
        init_timer(&rocket_timer);
2131
        rocket_timer.function = rp_do_poll;
2132
 
2133
        /*
2134
         * Initialize the array of pointers to our own internal state
2135
         * structures.
2136
         */
2137
        memset(rp_table, 0, sizeof(rp_table));
2138
        memset(xmit_flags, 0, sizeof(xmit_flags));
2139
 
2140
        if (board1 == 0)
2141
                board1 = 0x180;
2142
        if (controller == 0)
2143
                controller = board1 + 0x40;
2144
 
2145
        if (check_region(controller, 4)) {
2146
                printk("Controller IO addresses in use, unloading driver.\n");
2147
                return -EBUSY;
2148
        }
2149
 
2150
        rcktpt_io_addr[0] = board1;
2151
        rcktpt_io_addr[1] = board2;
2152
        rcktpt_io_addr[2] = board3;
2153
        rcktpt_io_addr[3] = board4;
2154
 
2155
        /*
2156
         * If support_low_speed is set, use the slow clock prescale,
2157
         * which supports 50 bps
2158
         */
2159
        if (support_low_speed) {
2160
                sClockPrescale = 0x19;  /* mod 9 (divide by 10) prescale */
2161
                rp_baud_base = 230400;
2162
        } else {
2163
                sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */
2164
                rp_baud_base = 460800;
2165
        }
2166
 
2167
        /*
2168
         * OK, let's probe each of the controllers looking for boards.
2169
         */
2170
        isa_boards_found = 0;
2171
        pci_boards_found = 0;
2172
        for (i=0; i < NUM_BOARDS; i++) {
2173
                if(init_ISA(i, &reserved_controller))
2174
                        isa_boards_found++;
2175
        }
2176
#ifdef ENABLE_PCI
2177
        if (pcibios_present()) {
2178
                if(isa_boards_found < NUM_BOARDS)
2179
                        pci_boards_found = init_PCI(isa_boards_found);
2180
        } else {
2181
                printk("No PCI BIOS found\n");
2182
        }
2183
#endif
2184
        max_board = pci_boards_found + isa_boards_found;
2185
 
2186
        if (max_board == 0) {
2187
                printk("No rocketport ports found; unloading driver.\n");
2188
                rocket_timer.function = 0;
2189
                return -ENODEV;
2190
        }
2191
 
2192
        if (reserved_controller == 0)
2193
                request_region(controller, 4, "Comtrol Rocketport");
2194
 
2195
        /*
2196
         * Set up the tty driver structure and then register this
2197
         * driver with the tty layer.
2198
         */
2199
        memset(&rocket_driver, 0, sizeof(struct tty_driver));
2200
        rocket_driver.magic = TTY_DRIVER_MAGIC;
2201
#ifdef CONFIG_DEVFS_FS
2202
        rocket_driver.name = "tts/R%d";
2203
#else
2204
        rocket_driver.name = "ttyR";
2205
#endif
2206
        rocket_driver.major = TTY_ROCKET_MAJOR;
2207
        rocket_driver.minor_start = 0;
2208
        rocket_driver.num = MAX_RP_PORTS;
2209
        rocket_driver.type = TTY_DRIVER_TYPE_SERIAL;
2210
        rocket_driver.subtype = SERIAL_TYPE_NORMAL;
2211
        rocket_driver.init_termios = tty_std_termios;
2212
        rocket_driver.init_termios.c_cflag =
2213
                B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2214
        rocket_driver.flags = TTY_DRIVER_REAL_RAW;
2215
        rocket_driver.refcount = &rocket_refcount;
2216
        rocket_driver.table = rocket_table;
2217
        rocket_driver.termios = rocket_termios;
2218
        rocket_driver.termios_locked = rocket_termios_locked;
2219
 
2220
        rocket_driver.open = rp_open;
2221
        rocket_driver.close = rp_close;
2222
        rocket_driver.write = rp_write;
2223
        rocket_driver.put_char = rp_put_char;
2224
        rocket_driver.write_room = rp_write_room;
2225
        rocket_driver.chars_in_buffer = rp_chars_in_buffer;
2226
        rocket_driver.flush_buffer = rp_flush_buffer;
2227
        rocket_driver.ioctl = rp_ioctl;
2228
        rocket_driver.throttle = rp_throttle;
2229
        rocket_driver.unthrottle = rp_unthrottle;
2230
        rocket_driver.set_termios = rp_set_termios;
2231
        rocket_driver.stop = rp_stop;
2232
        rocket_driver.start = rp_start;
2233
        rocket_driver.hangup = rp_hangup;
2234
#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
2235
        rocket_driver.break_ctl = rp_break;
2236
#endif
2237
#if (LINUX_VERSION_CODE >= 131343)
2238
        rocket_driver.send_xchar = rp_send_xchar;
2239
        rocket_driver.wait_until_sent = rp_wait_until_sent;
2240
#endif
2241
 
2242
        /*
2243
         * The callout device is just like normal device except for
2244
         * the minor number and the subtype code.
2245
         */
2246
        callout_driver = rocket_driver;
2247
#ifdef CONFIG_DEVFS_FS
2248
        callout_driver.name = "cua/R%d";
2249
#else
2250
        callout_driver.name = "cur";
2251
#endif
2252
        callout_driver.major = CUA_ROCKET_MAJOR;
2253
        callout_driver.minor_start = 0;
2254
        callout_driver.subtype = SERIAL_TYPE_CALLOUT;
2255
 
2256
        retval = tty_register_driver(&callout_driver);
2257
        if (retval < 0) {
2258
                printk("Couldn't install Rocketport callout driver "
2259
                       "(error %d)\n", -retval);
2260
                return -1;
2261
        }
2262
 
2263
        retval = tty_register_driver(&rocket_driver);
2264
        if (retval < 0) {
2265
                printk("Couldn't install tty Rocketport driver "
2266
                       "(error %d)\n", -retval);
2267
                return -1;
2268
        }
2269
#ifdef ROCKET_DEBUG_OPEN
2270
        printk("Rocketport driver is major %d, callout is %d\n",
2271
               rocket_driver.major, callout_driver.major);
2272
#endif
2273
 
2274
        return 0;
2275
}
2276
 
2277
#ifdef MODULE
2278
int init_module(void)
2279
{
2280
        return rp_init();
2281
}
2282
 
2283
void
2284
cleanup_module( void) {
2285
        int     retval;
2286
        int     i;
2287
        int     released_controller = 0;
2288
 
2289
        del_timer_sync(&rocket_timer);
2290
 
2291
        retval = tty_unregister_driver(&callout_driver);
2292
        if (retval) {
2293
                printk("Error %d while trying to unregister "
2294
                       "rocketport callout driver\n", -retval);
2295
        }
2296
        retval = tty_unregister_driver(&rocket_driver);
2297
        if (retval) {
2298
                printk("Error %d while trying to unregister "
2299
                       "rocketport driver\n", -retval);
2300
        }
2301
        for (i = 0; i < MAX_RP_PORTS; i++) {
2302
                if (rp_table[i])
2303
                        kfree(rp_table[i]);
2304
        }
2305
        for (i=0; i < NUM_BOARDS; i++) {
2306
                if (rcktpt_io_addr[i] <= 0)
2307
                        continue;
2308
                if (rcktpt_io_addr[i] + 0x40 == controller) {
2309
                        released_controller++;
2310
                        release_region(rcktpt_io_addr[i], 68);
2311
                } else
2312
                        release_region(rcktpt_io_addr[i], 64);
2313
                if (released_controller == 0)
2314
                        release_region(controller, 4);
2315
        }
2316
        if (tmp_buf)
2317
                free_page((unsigned long) tmp_buf);
2318
        rocket_timer.function = 0;
2319
}
2320
#endif
2321
 
2322
/***********************************************************************
2323
                Copyright 1994 Comtrol Corporation.
2324
                        All Rights Reserved.
2325
 
2326
The following source code is subject to Comtrol Corporation's
2327
Developer's License Agreement.
2328
 
2329
This source code is protected by United States copyright law and
2330
international copyright treaties.
2331
 
2332
This source code may only be used to develop software products that
2333
will operate with Comtrol brand hardware.
2334
 
2335
You may not reproduce nor distribute this source code in its original
2336
form but must produce a derivative work which includes portions of
2337
this source code only.
2338
 
2339
The portions of this source code which you use in your derivative
2340
work must bear Comtrol's copyright notice:
2341
 
2342
                Copyright 1994 Comtrol Corporation.
2343
 
2344
***********************************************************************/
2345
 
2346
#ifndef TRUE
2347
#define TRUE 1
2348
#endif
2349
 
2350
#ifndef FALSE
2351
#define FALSE 0
2352
#endif
2353
 
2354
static Byte_t RData[RDATASIZE] =
2355
{
2356
   0x00, 0x09, 0xf6, 0x82,
2357
   0x02, 0x09, 0x86, 0xfb,
2358
   0x04, 0x09, 0x00, 0x0a,
2359
   0x06, 0x09, 0x01, 0x0a,
2360
   0x08, 0x09, 0x8a, 0x13,
2361
   0x0a, 0x09, 0xc5, 0x11,
2362
   0x0c, 0x09, 0x86, 0x85,
2363
   0x0e, 0x09, 0x20, 0x0a,
2364
   0x10, 0x09, 0x21, 0x0a,
2365
   0x12, 0x09, 0x41, 0xff,
2366
   0x14, 0x09, 0x82, 0x00,
2367
   0x16, 0x09, 0x82, 0x7b,
2368
   0x18, 0x09, 0x8a, 0x7d,
2369
   0x1a, 0x09, 0x88, 0x81,
2370
   0x1c, 0x09, 0x86, 0x7a,
2371
   0x1e, 0x09, 0x84, 0x81,
2372
   0x20, 0x09, 0x82, 0x7c,
2373
   0x22, 0x09, 0x0a, 0x0a
2374
};
2375
 
2376
static Byte_t RRegData[RREGDATASIZE]=
2377
{
2378
   0x00, 0x09, 0xf6, 0x82,             /* 00: Stop Rx processor */
2379
   0x08, 0x09, 0x8a, 0x13,             /* 04: Tx software flow control */
2380
   0x0a, 0x09, 0xc5, 0x11,             /* 08: XON char */
2381
   0x0c, 0x09, 0x86, 0x85,             /* 0c: XANY */
2382
   0x12, 0x09, 0x41, 0xff,             /* 10: Rx mask char */
2383
   0x14, 0x09, 0x82, 0x00,             /* 14: Compare/Ignore #0 */
2384
   0x16, 0x09, 0x82, 0x7b,             /* 18: Compare #1 */
2385
   0x18, 0x09, 0x8a, 0x7d,             /* 1c: Compare #2 */
2386
   0x1a, 0x09, 0x88, 0x81,             /* 20: Interrupt #1 */
2387
   0x1c, 0x09, 0x86, 0x7a,             /* 24: Ignore/Replace #1 */
2388
   0x1e, 0x09, 0x84, 0x81,             /* 28: Interrupt #2 */
2389
   0x20, 0x09, 0x82, 0x7c,             /* 2c: Ignore/Replace #2 */
2390
   0x22, 0x09, 0x0a, 0x0a              /* 30: Rx FIFO Enable */
2391
};
2392
 
2393
CONTROLLER_T sController[CTL_SIZE] =
2394
{
2395
   {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}},
2396
   {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}},
2397
   {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}},
2398
   {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}
2399
};
2400
 
2401
#if 0
2402
/* IRQ number to MUDBAC register 2 mapping */
2403
Byte_t sIRQMap[16] =
2404
{
2405
   0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
2406
};
2407
#endif
2408
 
2409
Byte_t sBitMapClrTbl[8] =
2410
{
2411
   0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
2412
};
2413
 
2414
Byte_t sBitMapSetTbl[8] =
2415
{
2416
   0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
2417
};
2418
 
2419
int sClockPrescale = 0x14;
2420
 
2421
/***************************************************************************
2422
Function: sInitController
2423
Purpose:  Initialization of controller global registers and controller
2424
          structure.
2425
Call:     sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
2426
                          IRQNum,Frequency,PeriodicOnly)
2427
          CONTROLLER_T *CtlP; Ptr to controller structure
2428
          int CtlNum; Controller number
2429
          ByteIO_t MudbacIO; Mudbac base I/O address.
2430
          ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2431
             This list must be in the order the AIOPs will be found on the
2432
             controller.  Once an AIOP in the list is not found, it is
2433
             assumed that there are no more AIOPs on the controller.
2434
          int AiopIOListSize; Number of addresses in AiopIOList
2435
          int IRQNum; Interrupt Request number.  Can be any of the following:
2436
                         0: Disable global interrupts
2437
                         3: IRQ 3
2438
                         4: IRQ 4
2439
                         5: IRQ 5
2440
                         9: IRQ 9
2441
                         10: IRQ 10
2442
                         11: IRQ 11
2443
                         12: IRQ 12
2444
                         15: IRQ 15
2445
          Byte_t Frequency: A flag identifying the frequency
2446
                   of the periodic interrupt, can be any one of the following:
2447
                      FREQ_DIS - periodic interrupt disabled
2448
                      FREQ_137HZ - 137 Hertz
2449
                      FREQ_69HZ - 69 Hertz
2450
                      FREQ_34HZ - 34 Hertz
2451
                      FREQ_17HZ - 17 Hertz
2452
                      FREQ_9HZ - 9 Hertz
2453
                      FREQ_4HZ - 4 Hertz
2454
                   If IRQNum is set to 0 the Frequency parameter is
2455
                   overidden, it is forced to a value of FREQ_DIS.
2456
          int PeriodicOnly: TRUE if all interrupts except the periodic
2457
                               interrupt are to be blocked.
2458
                            FALSE is both the periodic interrupt and
2459
                               other channel interrupts are allowed.
2460
                            If IRQNum is set to 0 the PeriodicOnly parameter is
2461
                               overidden, it is forced to a value of FALSE.
2462
Return:   int: Number of AIOPs on the controller, or CTLID_NULL if controller
2463
               initialization failed.
2464
 
2465
Comments:
2466
          If periodic interrupts are to be disabled but AIOP interrupts
2467
          are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
2468
 
2469
          If interrupts are to be completely disabled set IRQNum to 0.
2470
 
2471
          Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
2472
          invalid combination.
2473
 
2474
          This function performs initialization of global interrupt modes,
2475
          but it does not actually enable global interrupts.  To enable
2476
          and disable global interrupts use functions sEnGlobalInt() and
2477
          sDisGlobalInt().  Enabling of global interrupts is normally not
2478
          done until all other initializations are complete.
2479
 
2480
          Even if interrupts are globally enabled, they must also be
2481
          individually enabled for each channel that is to generate
2482
          interrupts.
2483
 
2484
Warnings: No range checking on any of the parameters is done.
2485
 
2486
          No context switches are allowed while executing this function.
2487
 
2488
          After this function all AIOPs on the controller are disabled,
2489
          they can be enabled with sEnAiop().
2490
*/
2491
int sInitController(    CONTROLLER_T *CtlP,
2492
                        int CtlNum,
2493
                        ByteIO_t MudbacIO,
2494
                        ByteIO_t *AiopIOList,
2495
                        int AiopIOListSize,
2496
                        int IRQNum,
2497
                        Byte_t Frequency,
2498
                        int PeriodicOnly)
2499
{
2500
        int             i;
2501
        ByteIO_t        io;
2502
 
2503
   CtlP->CtlNum = CtlNum;
2504
   CtlP->CtlID = CTLID_0001;        /* controller release 1 */
2505
   CtlP->BusType = isISA;
2506
   CtlP->MBaseIO = MudbacIO;
2507
   CtlP->MReg1IO = MudbacIO + 1;
2508
   CtlP->MReg2IO = MudbacIO + 2;
2509
   CtlP->MReg3IO = MudbacIO + 3;
2510
#if 1
2511
   CtlP->MReg2 = 0;                 /* interrupt disable */
2512
   CtlP->MReg3 = 0;                 /* no periodic interrupts */
2513
#else
2514
   if(sIRQMap[IRQNum] == 0)            /* interrupts globally disabled */
2515
   {
2516
      CtlP->MReg2 = 0;                 /* interrupt disable */
2517
      CtlP->MReg3 = 0;                 /* no periodic interrupts */
2518
   }
2519
   else
2520
   {
2521
      CtlP->MReg2 = sIRQMap[IRQNum];   /* set IRQ number */
2522
      CtlP->MReg3 = Frequency;         /* set frequency */
2523
      if(PeriodicOnly)                 /* periodic interrupt only */
2524
      {
2525
         CtlP->MReg3 |= PERIODIC_ONLY;
2526
      }
2527
   }
2528
#endif
2529
   sOutB(CtlP->MReg2IO,CtlP->MReg2);
2530
   sOutB(CtlP->MReg3IO,CtlP->MReg3);
2531
   sControllerEOI(CtlP);               /* clear EOI if warm init */
2532
   /* Init AIOPs */
2533
   CtlP->NumAiop = 0;
2534
   for(i=0; i < AiopIOListSize; i++)
2535
   {
2536
      io = AiopIOList[i];
2537
      CtlP->AiopIO[i] = (WordIO_t)io;
2538
      CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2539
      sOutB(CtlP->MReg2IO,CtlP->MReg2 | (i & 0x03)); /* AIOP index */
2540
      sOutB(MudbacIO,(Byte_t)(io >> 6));        /* set up AIOP I/O in MUDBAC */
2541
      sEnAiop(CtlP,i);                         /* enable the AIOP */
2542
 
2543
      CtlP->AiopID[i] = sReadAiopID(io);       /* read AIOP ID */
2544
      if(CtlP->AiopID[i] == AIOPID_NULL)       /* if AIOP does not exist */
2545
      {
2546
         sDisAiop(CtlP,i);                     /* disable AIOP */
2547
         break;                                /* done looking for AIOPs */
2548
      }
2549
 
2550
      CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */
2551
      sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE);      /* clock prescaler */
2552
      sOutB(io + _INDX_DATA,sClockPrescale);
2553
      CtlP->NumAiop++;                         /* bump count of AIOPs */
2554
      sDisAiop(CtlP,i);                        /* disable AIOP */
2555
   }
2556
 
2557
   if(CtlP->NumAiop == 0)
2558
      return(-1);
2559
   else
2560
      return(CtlP->NumAiop);
2561
}
2562
 
2563
/***************************************************************************
2564
Function: sPCIInitController
2565
Purpose:  Initialization of controller global registers and controller
2566
          structure.
2567
Call:     sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
2568
                          IRQNum,Frequency,PeriodicOnly)
2569
          CONTROLLER_T *CtlP; Ptr to controller structure
2570
          int CtlNum; Controller number
2571
          ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2572
             This list must be in the order the AIOPs will be found on the
2573
             controller.  Once an AIOP in the list is not found, it is
2574
             assumed that there are no more AIOPs on the controller.
2575
          int AiopIOListSize; Number of addresses in AiopIOList
2576
          int IRQNum; Interrupt Request number.  Can be any of the following:
2577
                         0: Disable global interrupts
2578
                         3: IRQ 3
2579
                         4: IRQ 4
2580
                         5: IRQ 5
2581
                         9: IRQ 9
2582
                         10: IRQ 10
2583
                         11: IRQ 11
2584
                         12: IRQ 12
2585
                         15: IRQ 15
2586
          Byte_t Frequency: A flag identifying the frequency
2587
                   of the periodic interrupt, can be any one of the following:
2588
                      FREQ_DIS - periodic interrupt disabled
2589
                      FREQ_137HZ - 137 Hertz
2590
                      FREQ_69HZ - 69 Hertz
2591
                      FREQ_34HZ - 34 Hertz
2592
                      FREQ_17HZ - 17 Hertz
2593
                      FREQ_9HZ - 9 Hertz
2594
                      FREQ_4HZ - 4 Hertz
2595
                   If IRQNum is set to 0 the Frequency parameter is
2596
                   overidden, it is forced to a value of FREQ_DIS.
2597
          int PeriodicOnly: TRUE if all interrupts except the periodic
2598
                               interrupt are to be blocked.
2599
                            FALSE is both the periodic interrupt and
2600
                               other channel interrupts are allowed.
2601
                            If IRQNum is set to 0 the PeriodicOnly parameter is
2602
                               overidden, it is forced to a value of FALSE.
2603
Return:   int: Number of AIOPs on the controller, or CTLID_NULL if controller
2604
               initialization failed.
2605
 
2606
Comments:
2607
          If periodic interrupts are to be disabled but AIOP interrupts
2608
          are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
2609
 
2610
          If interrupts are to be completely disabled set IRQNum to 0.
2611
 
2612
          Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
2613
          invalid combination.
2614
 
2615
          This function performs initialization of global interrupt modes,
2616
          but it does not actually enable global interrupts.  To enable
2617
          and disable global interrupts use functions sEnGlobalInt() and
2618
          sDisGlobalInt().  Enabling of global interrupts is normally not
2619
          done until all other initializations are complete.
2620
 
2621
          Even if interrupts are globally enabled, they must also be
2622
          individually enabled for each channel that is to generate
2623
          interrupts.
2624
 
2625
Warnings: No range checking on any of the parameters is done.
2626
 
2627
          No context switches are allowed while executing this function.
2628
 
2629
          After this function all AIOPs on the controller are disabled,
2630
          they can be enabled with sEnAiop().
2631
*/
2632
int sPCIInitController( CONTROLLER_T *CtlP,
2633
                        int CtlNum,
2634
                        ByteIO_t *AiopIOList,
2635
                        int AiopIOListSize,
2636
                        int IRQNum,
2637
                        Byte_t Frequency,
2638
                        int PeriodicOnly)
2639
{
2640
        int             i;
2641
        ByteIO_t        io;
2642
 
2643
   CtlP->CtlNum = CtlNum;
2644
   CtlP->CtlID = CTLID_0001;        /* controller release 1 */
2645
   CtlP->BusType = isPCI;        /* controller release 1 */
2646
 
2647
   CtlP->PCIIO = (WordIO_t)((ByteIO_t)AiopIOList[0] + _PCI_INT_FUNC);
2648
 
2649
   sPCIControllerEOI(CtlP);               /* clear EOI if warm init */
2650
   /* Init AIOPs */
2651
   CtlP->NumAiop = 0;
2652
   for(i=0; i < AiopIOListSize; i++)
2653
   {
2654
      io = AiopIOList[i];
2655
      CtlP->AiopIO[i] = (WordIO_t)io;
2656
      CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2657
 
2658
      CtlP->AiopID[i] = sReadAiopID(io);       /* read AIOP ID */
2659
      if(CtlP->AiopID[i] == AIOPID_NULL)       /* if AIOP does not exist */
2660
         break;                                /* done looking for AIOPs */
2661
 
2662
      CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */
2663
      sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE);      /* clock prescaler */
2664
      sOutB(io + _INDX_DATA,sClockPrescale);
2665
      CtlP->NumAiop++;                         /* bump count of AIOPs */
2666
   }
2667
 
2668
   if(CtlP->NumAiop == 0)
2669
      return(-1);
2670
   else
2671
      return(CtlP->NumAiop);
2672
}
2673
 
2674
/***************************************************************************
2675
Function: sReadAiopID
2676
Purpose:  Read the AIOP idenfication number directly from an AIOP.
2677
Call:     sReadAiopID(io)
2678
          ByteIO_t io: AIOP base I/O address
2679
Return:   int: Flag AIOPID_XXXX if a valid AIOP is found, where X
2680
                 is replace by an identifying number.
2681
          Flag AIOPID_NULL if no valid AIOP is found
2682
Warnings: No context switches are allowed while executing this function.
2683
 
2684
*/
2685
int sReadAiopID(ByteIO_t io)
2686
{
2687
   Byte_t AiopID;               /* ID byte from AIOP */
2688
 
2689
   sOutB(io + _CMD_REG,RESET_ALL);     /* reset AIOP */
2690
   sOutB(io + _CMD_REG,0x0);
2691
   AiopID = sInB(io + _CHN_STAT0) & 0x07;
2692
   if(AiopID == 0x06)
2693
      return(1);
2694
   else                                /* AIOP does not exist */
2695
      return(-1);
2696
}
2697
 
2698
/***************************************************************************
2699
Function: sReadAiopNumChan
2700
Purpose:  Read the number of channels available in an AIOP directly from
2701
          an AIOP.
2702
Call:     sReadAiopNumChan(io)
2703
          WordIO_t io: AIOP base I/O address
2704
Return:   int: The number of channels available
2705
Comments: The number of channels is determined by write/reads from identical
2706
          offsets within the SRAM address spaces for channels 0 and 4.
2707
          If the channel 4 space is mirrored to channel 0 it is a 4 channel
2708
          AIOP, otherwise it is an 8 channel.
2709
Warnings: No context switches are allowed while executing this function.
2710
*/
2711
int sReadAiopNumChan(WordIO_t io)
2712
{
2713
   Word_t x;
2714
 
2715
   sOutDW((DWordIO_t)io + _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
2716
   sOutW(io + _INDX_ADDR,0);       /* read from SRAM, chan 0 */
2717
   x = sInW(io + _INDX_DATA);
2718
   sOutW(io + _INDX_ADDR,0x4000);  /* read from SRAM, chan 4 */
2719
   if(x != sInW(io + _INDX_DATA))  /* if different must be 8 chan */
2720
      return(8);
2721
   else
2722
      return(4);
2723
}
2724
 
2725
/***************************************************************************
2726
Function: sInitChan
2727
Purpose:  Initialization of a channel and channel structure
2728
Call:     sInitChan(CtlP,ChP,AiopNum,ChanNum)
2729
          CONTROLLER_T *CtlP; Ptr to controller structure
2730
          CHANNEL_T *ChP; Ptr to channel structure
2731
          int AiopNum; AIOP number within controller
2732
          int ChanNum; Channel number within AIOP
2733
Return:   int: TRUE if initialization succeeded, FALSE if it fails because channel
2734
               number exceeds number of channels available in AIOP.
2735
Comments: This function must be called before a channel can be used.
2736
Warnings: No range checking on any of the parameters is done.
2737
 
2738
          No context switches are allowed while executing this function.
2739
*/
2740
int sInitChan(  CONTROLLER_T *CtlP,
2741
                CHANNEL_T *ChP,
2742
                int AiopNum,
2743
                int ChanNum)
2744
{
2745
   int i;
2746
   WordIO_t AiopIO;
2747
   WordIO_t ChIOOff;
2748
   Byte_t *ChR;
2749
   Word_t ChOff;
2750
   static Byte_t R[4];
2751
   int brd9600;
2752
 
2753
   if(ChanNum >= CtlP->AiopNumChan[AiopNum])
2754
      return(FALSE);                   /* exceeds num chans in AIOP */
2755
 
2756
   /* Channel, AIOP, and controller identifiers */
2757
   ChP->CtlP = CtlP;
2758
   ChP->ChanID = CtlP->AiopID[AiopNum];
2759
   ChP->AiopNum = AiopNum;
2760
   ChP->ChanNum = ChanNum;
2761
 
2762
   /* Global direct addresses */
2763
   AiopIO = CtlP->AiopIO[AiopNum];
2764
   ChP->Cmd = (ByteIO_t)AiopIO + _CMD_REG;
2765
   ChP->IntChan = (ByteIO_t)AiopIO + _INT_CHAN;
2766
   ChP->IntMask = (ByteIO_t)AiopIO + _INT_MASK;
2767
   ChP->IndexAddr = (DWordIO_t)AiopIO + _INDX_ADDR;
2768
   ChP->IndexData = AiopIO + _INDX_DATA;
2769
 
2770
   /* Channel direct addresses */
2771
   ChIOOff = AiopIO + ChP->ChanNum * 2;
2772
   ChP->TxRxData = ChIOOff + _TD0;
2773
   ChP->ChanStat = ChIOOff + _CHN_STAT0;
2774
   ChP->TxRxCount = ChIOOff + _FIFO_CNT0;
2775
   ChP->IntID = (ByteIO_t)AiopIO + ChP->ChanNum + _INT_ID0;
2776
 
2777
   /* Initialize the channel from the RData array */
2778
   for(i=0; i < RDATASIZE; i+=4)
2779
   {
2780
      R[0] = RData[i];
2781
      R[1] = RData[i+1] + 0x10 * ChanNum;
2782
      R[2] = RData[i+2];
2783
      R[3] = RData[i+3];
2784
      sOutDW(ChP->IndexAddr,*((DWord_t *)&R[0]));
2785
   }
2786
 
2787
   ChR = ChP->R;
2788
   for(i=0; i < RREGDATASIZE; i+=4)
2789
   {
2790
      ChR[i] = RRegData[i];
2791
      ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
2792
      ChR[i+2] = RRegData[i+2];
2793
      ChR[i+3] = RRegData[i+3];
2794
   }
2795
 
2796
   /* Indexed registers */
2797
   ChOff = (Word_t)ChanNum * 0x1000;
2798
 
2799
   if (sClockPrescale == 0x14)
2800
           brd9600 = 47;
2801
   else
2802
           brd9600 = 23;
2803
 
2804
   ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
2805
   ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
2806
   ChP->BaudDiv[2] = (Byte_t)brd9600;
2807
   ChP->BaudDiv[3] = (Byte_t)(brd9600 >> 8);
2808
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->BaudDiv[0]);
2809
 
2810
   ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
2811
   ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
2812
   ChP->TxControl[2] = 0;
2813
   ChP->TxControl[3] = 0;
2814
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]);
2815
 
2816
   ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
2817
   ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
2818
   ChP->RxControl[2] = 0;
2819
   ChP->RxControl[3] = 0;
2820
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]);
2821
 
2822
   ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
2823
   ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
2824
   ChP->TxEnables[2] = 0;
2825
   ChP->TxEnables[3] = 0;
2826
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxEnables[0]);
2827
 
2828
   ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
2829
   ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
2830
   ChP->TxCompare[2] = 0;
2831
   ChP->TxCompare[3] = 0;
2832
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxCompare[0]);
2833
 
2834
   ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
2835
   ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
2836
   ChP->TxReplace1[2] = 0;
2837
   ChP->TxReplace1[3] = 0;
2838
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace1[0]);
2839
 
2840
   ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
2841
   ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
2842
   ChP->TxReplace2[2] = 0;
2843
   ChP->TxReplace2[3] = 0;
2844
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace2[0]);
2845
 
2846
   ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
2847
   ChP->TxFIFO = ChOff + _TX_FIFO;
2848
 
2849
   sOutB(ChP->Cmd,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
2850
   sOutB(ChP->Cmd,(Byte_t)ChanNum);  /* remove reset Tx FIFO count */
2851
   sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2852
   sOutW(ChP->IndexData,0);
2853
   ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
2854
   ChP->RxFIFO = ChOff + _RX_FIFO;
2855
 
2856
   sOutB(ChP->Cmd,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
2857
   sOutB(ChP->Cmd,(Byte_t)ChanNum);  /* remove reset Rx FIFO count */
2858
   sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */
2859
   sOutW(ChP->IndexData,0);
2860
   sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2861
   sOutW(ChP->IndexData,0);
2862
   ChP->TxPrioCnt = ChOff + _TXP_CNT;
2863
   sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioCnt);
2864
   sOutB(ChP->IndexData,0);
2865
   ChP->TxPrioPtr = ChOff + _TXP_PNTR;
2866
   sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioPtr);
2867
   sOutB(ChP->IndexData,0);
2868
   ChP->TxPrioBuf = ChOff + _TXP_BUF;
2869
   sEnRxProcessor(ChP);                /* start the Rx processor */
2870
 
2871
   return(TRUE);
2872
}
2873
 
2874
/***************************************************************************
2875
Function: sStopRxProcessor
2876
Purpose:  Stop the receive processor from processing a channel.
2877
Call:     sStopRxProcessor(ChP)
2878
          CHANNEL_T *ChP; Ptr to channel structure
2879
 
2880
Comments: The receive processor can be started again with sStartRxProcessor().
2881
          This function causes the receive processor to skip over the
2882
          stopped channel.  It does not stop it from processing other channels.
2883
 
2884
Warnings: No context switches are allowed while executing this function.
2885
 
2886
          Do not leave the receive processor stopped for more than one
2887
          character time.
2888
 
2889
          After calling this function a delay of 4 uS is required to ensure
2890
          that the receive processor is no longer processing this channel.
2891
*/
2892
void sStopRxProcessor(CHANNEL_T *ChP)
2893
{
2894
   Byte_t R[4];
2895
 
2896
   R[0] = ChP->R[0];
2897
   R[1] = ChP->R[1];
2898
   R[2] = 0x0a;
2899
   R[3] = ChP->R[3];
2900
   sOutDW(ChP->IndexAddr,*(DWord_t *)&R[0]);
2901
}
2902
 
2903
/***************************************************************************
2904
Function: sFlushRxFIFO
2905
Purpose:  Flush the Rx FIFO
2906
Call:     sFlushRxFIFO(ChP)
2907
          CHANNEL_T *ChP; Ptr to channel structure
2908
Return:   void
2909
Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2910
          while it is being flushed the receive processor is stopped
2911
          and the transmitter is disabled.  After these operations a
2912
          4 uS delay is done before clearing the pointers to allow
2913
          the receive processor to stop.  These items are handled inside
2914
          this function.
2915
Warnings: No context switches are allowed while executing this function.
2916
*/
2917
void sFlushRxFIFO(CHANNEL_T *ChP)
2918
{
2919
   int i;
2920
   Byte_t Ch;                   /* channel number within AIOP */
2921
   int RxFIFOEnabled;                  /* TRUE if Rx FIFO enabled */
2922
 
2923
   if(sGetRxCnt(ChP) == 0)             /* Rx FIFO empty */
2924
      return;                          /* don't need to flush */
2925
 
2926
   RxFIFOEnabled = FALSE;
2927
   if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
2928
   {
2929
      RxFIFOEnabled = TRUE;
2930
      sDisRxFIFO(ChP);                 /* disable it */
2931
      for(i=0; i < 2000/200; i++)        /* delay 2 uS to allow proc to disable FIFO*/
2932
         sInB(ChP->IntChan);            /* depends on bus i/o timing */
2933
   }
2934
   sGetChanStatus(ChP);          /* clear any pending Rx errors in chan stat */
2935
   Ch = (Byte_t)sGetChanNum(ChP);
2936
   sOutB(ChP->Cmd,Ch | RESRXFCNT);     /* apply reset Rx FIFO count */
2937
   sOutB(ChP->Cmd,Ch);                 /* remove reset Rx FIFO count */
2938
   sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */
2939
   sOutW(ChP->IndexData,0);
2940
   sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2941
   sOutW(ChP->IndexData,0);
2942
   if(RxFIFOEnabled)
2943
      sEnRxFIFO(ChP);                  /* enable Rx FIFO */
2944
}
2945
 
2946
/***************************************************************************
2947
Function: sFlushTxFIFO
2948
Purpose:  Flush the Tx FIFO
2949
Call:     sFlushTxFIFO(ChP)
2950
          CHANNEL_T *ChP; Ptr to channel structure
2951
Return:   void
2952
Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2953
          while it is being flushed the receive processor is stopped
2954
          and the transmitter is disabled.  After these operations a
2955
          4 uS delay is done before clearing the pointers to allow
2956
          the receive processor to stop.  These items are handled inside
2957
          this function.
2958
Warnings: No context switches are allowed while executing this function.
2959
*/
2960
void sFlushTxFIFO(CHANNEL_T *ChP)
2961
{
2962
   int i;
2963
   Byte_t Ch;                   /* channel number within AIOP */
2964
   int TxEnabled;                      /* TRUE if transmitter enabled */
2965
 
2966
   if(sGetTxCnt(ChP) == 0)             /* Tx FIFO empty */
2967
      return;                          /* don't need to flush */
2968
 
2969
   TxEnabled = FALSE;
2970
   if(ChP->TxControl[3] & TX_ENABLE)
2971
   {
2972
      TxEnabled = TRUE;
2973
      sDisTransmit(ChP);               /* disable transmitter */
2974
   }
2975
   sStopRxProcessor(ChP);              /* stop Rx processor */
2976
   for(i = 0; i < 4000/200; i++)         /* delay 4 uS to allow proc to stop */
2977
      sInB(ChP->IntChan);       /* depends on bus i/o timing */
2978
   Ch = (Byte_t)sGetChanNum(ChP);
2979
   sOutB(ChP->Cmd,Ch | RESTXFCNT);     /* apply reset Tx FIFO count */
2980
   sOutB(ChP->Cmd,Ch);                 /* remove reset Tx FIFO count */
2981
   sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2982
   sOutW(ChP->IndexData,0);
2983
   if(TxEnabled)
2984
      sEnTransmit(ChP);                /* enable transmitter */
2985
   sStartRxProcessor(ChP);             /* restart Rx processor */
2986
}
2987
 
2988
/***************************************************************************
2989
Function: sWriteTxPrioByte
2990
Purpose:  Write a byte of priority transmit data to a channel
2991
Call:     sWriteTxPrioByte(ChP,Data)
2992
          CHANNEL_T *ChP; Ptr to channel structure
2993
          Byte_t Data; The transmit data byte
2994
 
2995
Return:   int: 1 if the bytes is successfully written, otherwise 0.
2996
 
2997
Comments: The priority byte is transmitted before any data in the Tx FIFO.
2998
 
2999
Warnings: No context switches are allowed while executing this function.
3000
*/
3001
int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
3002
{
3003
   Byte_t DWBuf[4];             /* buffer for double word writes */
3004
   Word_t *WordPtr;          /* must be far because Win SS != DS */
3005
   register DWordIO_t IndexAddr;
3006
 
3007
   if(sGetTxCnt(ChP) > 1)              /* write it to Tx priority buffer */
3008
   {
3009
      IndexAddr = ChP->IndexAddr;
3010
      sOutW((WordIO_t)IndexAddr,ChP->TxPrioCnt); /* get priority buffer status */
3011
      if(sInB((ByteIO_t)ChP->IndexData) & PRI_PEND) /* priority buffer busy */
3012
         return(0);                    /* nothing sent */
3013
 
3014
      WordPtr = (Word_t *)(&DWBuf[0]);
3015
      *WordPtr = ChP->TxPrioBuf;       /* data byte address */
3016
 
3017
      DWBuf[2] = Data;                 /* data byte value */
3018
      sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */
3019
 
3020
      *WordPtr = ChP->TxPrioCnt;       /* Tx priority count address */
3021
 
3022
      DWBuf[2] = PRI_PEND + 1;         /* indicate 1 byte pending */
3023
      DWBuf[3] = 0;                    /* priority buffer pointer */
3024
      sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */
3025
   }
3026
   else                                /* write it to Tx FIFO */
3027
   {
3028
      sWriteTxByte(sGetTxRxDataIO(ChP),Data);
3029
   }
3030
   return(1);                          /* 1 byte sent */
3031
}
3032
 
3033
/***************************************************************************
3034
Function: sEnInterrupts
3035
Purpose:  Enable one or more interrupts for a channel
3036
Call:     sEnInterrupts(ChP,Flags)
3037
          CHANNEL_T *ChP; Ptr to channel structure
3038
          Word_t Flags: Interrupt enable flags, can be any combination
3039
             of the following flags:
3040
                TXINT_EN:   Interrupt on Tx FIFO empty
3041
                RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
3042
                            sSetRxTrigger())
3043
                SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
3044
                MCINT_EN:   Interrupt on modem input change
3045
                CHANINT_EN: Allow channel interrupt signal to the AIOP's
3046
                            Interrupt Channel Register.
3047
Return:   void
3048
Comments: If an interrupt enable flag is set in Flags, that interrupt will be
3049
          enabled.  If an interrupt enable flag is not set in Flags, that
3050
          interrupt will not be changed.  Interrupts can be disabled with
3051
          function sDisInterrupts().
3052
 
3053
          This function sets the appropriate bit for the channel in the AIOP's
3054
          Interrupt Mask Register if the CHANINT_EN flag is set.  This allows
3055
          this channel's bit to be set in the AIOP's Interrupt Channel Register.
3056
 
3057
          Interrupts must also be globally enabled before channel interrupts
3058
          will be passed on to the host.  This is done with function
3059
          sEnGlobalInt().
3060
 
3061
          In some cases it may be desirable to disable interrupts globally but
3062
          enable channel interrupts.  This would allow the global interrupt
3063
          status register to be used to determine which AIOPs need service.
3064
*/
3065
void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
3066
{
3067
   Byte_t Mask;                 /* Interrupt Mask Register */
3068
 
3069
   ChP->RxControl[2] |=
3070
      ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
3071
 
3072
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]);
3073
 
3074
   ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
3075
 
3076
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]);
3077
 
3078
   if(Flags & CHANINT_EN)
3079
   {
3080
      Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum];
3081
      sOutB(ChP->IntMask,Mask);
3082
   }
3083
}
3084
 
3085
/***************************************************************************
3086
Function: sDisInterrupts
3087
Purpose:  Disable one or more interrupts for a channel
3088
Call:     sDisInterrupts(ChP,Flags)
3089
          CHANNEL_T *ChP; Ptr to channel structure
3090
          Word_t Flags: Interrupt flags, can be any combination
3091
             of the following flags:
3092
                TXINT_EN:   Interrupt on Tx FIFO empty
3093
                RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
3094
                            sSetRxTrigger())
3095
                SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
3096
                MCINT_EN:   Interrupt on modem input change
3097
                CHANINT_EN: Disable channel interrupt signal to the
3098
                            AIOP's Interrupt Channel Register.
3099
Return:   void
3100
Comments: If an interrupt flag is set in Flags, that interrupt will be
3101
          disabled.  If an interrupt flag is not set in Flags, that
3102
          interrupt will not be changed.  Interrupts can be enabled with
3103
          function sEnInterrupts().
3104
 
3105
          This function clears the appropriate bit for the channel in the AIOP's
3106
          Interrupt Mask Register if the CHANINT_EN flag is set.  This blocks
3107
          this channel's bit from being set in the AIOP's Interrupt Channel
3108
          Register.
3109
*/
3110
void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
3111
{
3112
   Byte_t Mask;                 /* Interrupt Mask Register */
3113
 
3114
   ChP->RxControl[2] &=
3115
         ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
3116
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]);
3117
   ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
3118
   sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]);
3119
 
3120
   if(Flags & CHANINT_EN)
3121
   {
3122
      Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum];
3123
      sOutB(ChP->IntMask,Mask);
3124
   }
3125
}

powered by: WebSVN 2.1.0

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