2 * Rocketport device driver for Linux
4 * Written by Theodore Ts'o, 1995, 1996, 1997.
6 * Copyright (C) 1995, 1996, 1997 by Comtrol, Inc.
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.
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.
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.
24 * Minor number schema:
26 * +-------------------------------+
27 * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
28 * +---+-------+-------+-----------+
29 * | C | Board | AIOP | Port # |
30 * +---+-------+-------+-----------+
32 * C=0 implements normal POSIX tty.
33 * C=1 is reserved for the callout device.
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).
42 #include <linux/config.h>
43 #include <linux/version.h>
50 #ifdef LOCAL_ROCKET_H /* We're building standalone */
56 #include <linux/modversions.h>
58 #else /* !NEW_MODULES */
62 #endif /* NEW_MODULES */
64 #include <linux/module.h>
65 #include <linux/errno.h>
66 #include <linux/major.h>
67 #include <linux/kernel.h>
68 #include <linux/signal.h>
69 #include <linux/malloc.h>
72 #include <linux/sched.h>
73 #include <linux/timer.h>
74 #include <linux/interrupt.h>
75 #include <linux/tty.h>
76 #include <linux/tty_flip.h>
77 #include <linux/string.h>
78 #include <linux/fcntl.h>
79 #include <linux/ptrace.h>
80 #include <linux/ioport.h>
82 #include <linux/pci.h>
83 #if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
84 #include <linux/bios32.h>
87 #if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
88 #include <linux/init.h>
91 #include "rocket_int.h"
96 #include <linux/rocket.h>
97 #define ROCKET_VERSION "1.14c"
98 #define ROCKET_DATE "24-Aug-98"
99 #endif /* LOCAL_ROCKET_H */
101 #define ROCKET_PARANOIA_CHECK
102 #define ROCKET_SOFT_FLOW
104 #undef ROCKET_DEBUG_OPEN
105 #undef ROCKET_DEBUG_INTR
106 #undef ROCKET_DEBUG_WRITE
107 #undef ROCKET_DEBUG_FLOW
108 #undef ROCKET_DEBUG_THROTTLE
109 #undef ROCKET_DEBUG_WAIT_UNTIL_SENT
110 #undef ROCKET_DEBUG_RECEIVE
111 #undef ROCKET_DEBUG_HANGUP
114 /* CAUTION!!!!! The TIME_STAT Function relies on the Pentium 64 bit
115 * register. For various reasons related to 1.2.13, the test for this
116 * register is omitted from this driver. If you are going to enable
117 * this option, make sure you are running a Pentium CPU and that a
118 * cat of /proc/cpuinfo shows ability TS Counters as Yes. Warning part
119 * done, don't cry to me if you enable this options and things won't
120 * work. If it gives you any problems, then disable the option. The code
121 * in this function is pretty straight forward, if it breaks on your
122 * CPU, there is probably something funny about your CPU.
125 #undef TIME_STAT /* For performing timing statistics on driver. */
126 /* Produces printks, one every TIME_COUNTER loops, eats */
127 /* some of your CPU time. Good for testing or */
128 /* other checking, otherwise, leave it undefed */
130 #define TIME_STAT_CPU 100 /* This needs to be set to your processor speed */
131 /* For example, 100Mhz CPU, set this to 100 */
132 #define TIME_COUNTER 180000 /* This is how many iterations to run before */
133 /* performing the printk statements. */
134 /* 6000 = 1 minute, 360000 = 1 hour, etc. */
135 /* Since time_stat is long long, this */
136 /* Can be really high if you want :) */
137 #undef TIME_STAT_VERBOSE /* Undef this if you want a terse log message. */
139 #define _INLINE_ inline
143 * NB. we must include the kernel idenfication string in to install the module.
145 /*static*/ char kernel_version
[] = UTS_RELEASE
;
148 static struct r_port
*rp_table
[MAX_RP_PORTS
];
149 static struct tty_struct
*rocket_table
[MAX_RP_PORTS
];
150 static unsigned int xmit_flags
[NUM_BOARDS
];
151 static struct termios
*rocket_termios
[MAX_RP_PORTS
];
152 static struct termios
*rocket_termios_locked
[MAX_RP_PORTS
];
153 static void rp_wait_until_sent(struct tty_struct
*tty
, int timeout
);
154 static void rp_flush_buffer(struct tty_struct
*tty
);
156 static struct tty_driver rocket_driver
, callout_driver
;
157 static int rocket_refcount
= 0;
159 static int rp_num_ports_open
= 0;
161 static struct timer_list rocket_timer
;
163 unsigned long board1
= 0;
164 unsigned long board2
= 0;
165 unsigned long board3
= 0;
166 unsigned long board4
= 0;
167 unsigned long controller
= 0;
168 unsigned long support_low_speed
= 0;
169 int rp_baud_base
= 460800;
170 static unsigned long rcktpt_io_addr
[NUM_BOARDS
];
171 static int max_board
;
173 static unsigned long long time_stat
= 0;
174 static unsigned long time_stat_short
= 0;
175 static unsigned long time_stat_long
= 0;
176 static unsigned long time_counter
= 0;
179 #if ((LINUX_VERSION_CODE > 0x020111) && defined(MODULE))
180 MODULE_AUTHOR("Theodore Ts'o");
181 MODULE_DESCRIPTION("Comtrol Rocketport driver");
182 MODULE_PARM(board1
, "i");
183 MODULE_PARM_DESC(board1
, "I/O port for (ISA) board #1");
184 MODULE_PARM(board2
, "i");
185 MODULE_PARM_DESC(board2
, "I/O port for (ISA) board #2");
186 MODULE_PARM(board3
, "i");
187 MODULE_PARM_DESC(board3
, "I/O port for (ISA) board #3");
188 MODULE_PARM(board4
, "i");
189 MODULE_PARM_DESC(board4
, "I/O port for (ISA) board #4");
190 MODULE_PARM(controller
, "i");
191 MODULE_PARM_DESC(controller
, "I/O port for (ISA) rocketport controller");
192 MODULE_PARM(support_low_speed
, "i");
193 MODULE_PARM_DESC(support_low_speed
, "0 means support 50 baud, 1 means support 460400 baud");
196 #if (LINUX_VERSION_CODE < 131336)
197 int copy_from_user(void *to
, const void *from_user
, unsigned long len
)
201 error
= verify_area(VERIFY_READ
, from_user
, len
);
204 memcpy_fromfs(to
, from_user
, len
);
208 int copy_to_user(void *to_user
, const void *from
, unsigned long len
)
212 error
= verify_area(VERIFY_WRITE
, to_user
, len
);
215 memcpy_tofs(to_user
, from
, len
);
219 static inline int signal_pending(struct task_struct
*p
)
221 return (p
->signal
& ~p
->blocked
) != 0;
225 #include <asm/uaccess.h>
229 * tmp_buf is used as a temporary buffer by rp_write. We need to
230 * lock it in case the memcpy_fromfs blocks while swapping in a page,
231 * and some other program tries to do a serial write at the same time.
232 * Since the lock will only come under contention when the system is
233 * swapping and available memory is low, it makes sense to share one
234 * buffer across all the serial ports, since it significantly saves
235 * memory if large numbers of serial ports are open.
237 static unsigned char *tmp_buf
= 0;
238 static DECLARE_MUTEX(tmp_buf_sem
);
240 static void rp_start(struct tty_struct
*tty
);
242 static inline int rocket_paranoia_check(struct r_port
*info
,
243 kdev_t device
, const char *routine
)
245 #ifdef ROCKET_PARANOIA_CHECK
246 static const char *badmagic
=
247 "Warning: bad magic number for rocketport struct (%d, %d) in %s\n";
250 if (info
->magic
!= RPORT_MAGIC
) {
251 printk(badmagic
, MAJOR(device
), MINOR(device
), routine
);
259 * Here begins the interrupt/polling routine for the Rocketport!
261 static _INLINE_
void rp_do_receive(struct r_port
*info
, struct tty_struct
*tty
,
262 CHANNEL_t
*cp
, unsigned int ChanStatus
)
264 unsigned int CharNStat
;
265 int ToRecv
, wRecv
, space
, count
;
269 ToRecv
= sGetRxCnt(cp
);
270 space
= 2*TTY_FLIPBUF_SIZE
;
271 cbuf
= tty
->flip
.char_buf
;
272 fbuf
= tty
->flip
.flag_buf
;
274 #ifdef ROCKET_DEBUG_INTR
275 printk("rp_do_receive(%d, %d)...", ToRecv
, space
);
277 if (ToRecv
== 0 || (space
<= 0))
281 * determine how many we can actually read in. If we can't
282 * read any in then we have a software overrun condition.
288 * if status indicates there are errored characters in the
289 * FIFO, then enter status mode (a word in FIFO holds
290 * character and status).
292 if (ChanStatus
& (RXFOVERFL
| RXBREAK
| RXFRAME
| RXPARITY
)) {
293 if (!(ChanStatus
& STATMODE
)) {
294 #ifdef ROCKET_DEBUG_RECEIVE
295 printk("Entering STATMODE...");
297 ChanStatus
|= STATMODE
;
303 * if we previously entered status mode, then read down the
304 * FIFO one word at a time, pulling apart the character and
305 * the status. Update error counters depending on status
307 if (ChanStatus
& STATMODE
) {
308 #ifdef ROCKET_DEBUG_RECEIVE
309 printk("Ignore %x, read %x...", info
->ignore_status_mask
,
310 info
->read_status_mask
);
313 CharNStat
= sInW(sGetTxRxDataIO(cp
));
315 #ifdef ROCKET_DEBUG_RECEIVE
316 printk("%x...", CharNStat
);
319 if (CharNStat
& STMBREAKH
)
320 CharNStat
&= ~(STMFRAMEH
| STMPARITYH
);
321 if (CharNStat
& info
->ignore_status_mask
) {
325 CharNStat
&= info
->read_status_mask
;
326 if (CharNStat
& STMBREAKH
) {
329 if (info
->flags
& ROCKET_SAK
)
332 } else if (CharNStat
& STMPARITYH
)
333 *fbuf
++ = TTY_PARITY
;
334 else if (CharNStat
& STMFRAMEH
)
336 else if (CharNStat
& STMRCVROVRH
)
337 *fbuf
++ =TTY_OVERRUN
;
340 *cbuf
++ = CharNStat
& 0xff;
346 * after we've emptied the FIFO in status mode, turn
347 * status mode back off
349 if (sGetRxCnt(cp
) == 0) {
350 #ifdef ROCKET_DEBUG_RECEIVE
351 printk("Status mode off.\n");
353 sDisRxStatusMode(cp
);
357 * we aren't in status mode, so read down the FIFO two
358 * characters at time by doing repeated word IO
363 sInStrW(sGetTxRxDataIO(cp
), cbuf
,
366 cbuf
[ToRecv
-1] = sInB(sGetTxRxDataIO(cp
));
367 memset(fbuf
, 0, ToRecv
);
372 tty
->ldisc
.receive_buf(tty
, tty
->flip
.char_buf
,
373 tty
->flip
.flag_buf
, count
);
377 * This routine is called when a transmit interrupt is found. It's
378 * responsible for pushing data found in the transmit buffer out to
381 static _INLINE_
void rp_do_transmit(struct r_port
*info
)
384 CHANNEL_t
*cp
= &info
->channel
;
385 struct tty_struct
*tty
;
387 #ifdef ROCKET_DEBUG_INTR
388 printk("rp_do_transmit ");
393 printk("rp: WARNING rp_do_transmit called with info->tty==NULL\n");
394 xmit_flags
[info
->line
>> 5] &= ~(1 << (info
->line
& 0x1f));
398 info
->xmit_fifo_room
= TXFIFO_SIZE
- sGetTxCnt(cp
);
400 if (tty
->stopped
|| tty
->hw_stopped
)
402 c
= MIN(info
->xmit_fifo_room
,
404 XMIT_BUF_SIZE
- info
->xmit_tail
));
405 if (c
<= 0 || info
->xmit_fifo_room
<= 0)
407 sOutStrW(sGetTxRxDataIO(cp
),
408 info
->xmit_buf
+ info
->xmit_tail
, c
/2);
410 sOutB(sGetTxRxDataIO(cp
),
411 info
->xmit_buf
[info
->xmit_tail
+ c
-
413 info
->xmit_tail
+= c
;
414 info
->xmit_tail
&= XMIT_BUF_SIZE
-1;
416 info
->xmit_fifo_room
-= c
;
417 #ifdef ROCKET_DEBUG_INTR
418 printk("tx %d chars...", c
);
421 if (info
->xmit_cnt
== 0)
422 xmit_flags
[info
->line
>> 5] &= ~(1 << (info
->line
& 0x1f));
423 if (info
->xmit_cnt
< WAKEUP_CHARS
) {
424 if ((tty
->flags
& (1 << TTY_DO_WRITE_WAKEUP
)) &&
425 tty
->ldisc
.write_wakeup
)
426 (tty
->ldisc
.write_wakeup
)(tty
);
427 wake_up_interruptible(&tty
->write_wait
);
429 #ifdef ROCKET_DEBUG_INTR
430 printk("(%d,%d,%d,%d)...", info
->xmit_cnt
, info
->xmit_head
,
431 info
->xmit_tail
, info
->xmit_fifo_room
);
436 * This function is called for each port which has signalled an
437 * interrupt. It checks what interrupts are pending and services
440 static _INLINE_
void rp_handle_port(struct r_port
*info
)
443 struct tty_struct
*tty
;
444 unsigned int IntMask
, ChanStatus
;
448 if ( (info
->flags
& ROCKET_INITIALIZED
) == 0 ) {
449 printk("rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n");
453 printk("rp: WARNING: rp_handle_port called with info->tty==NULL\n");
459 IntMask
= sGetChanIntID(cp
) & info
->intmask
;
460 #ifdef ROCKET_DEBUG_INTR
461 printk("rp_interrupt %02x...", IntMask
);
463 ChanStatus
= sGetChanStatus(cp
);
464 if (IntMask
& RXF_TRIG
) { /* Rx FIFO trigger level */
465 rp_do_receive(info
, tty
, cp
, ChanStatus
);
468 if (IntMask
& SRC_INT
) { /* Special receive condition */
471 if (IntMask
& DELTA_CD
) { /* CD change */
472 #if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || \
473 defined(ROCKET_DEBUG_HANGUP))
474 printk("ttyR%d CD now %s...", info
->line
,
475 (ChanStatus
& CD_ACT
) ? "on" : "off");
477 if (!(ChanStatus
& CD_ACT
) &&
479 !((info
->flags
& ROCKET_CALLOUT_ACTIVE
) &&
480 (info
->flags
& ROCKET_CALLOUT_NOHUP
))) {
481 #ifdef ROCKET_DEBUG_HANGUP
482 printk("CD drop, calling hangup.\n");
486 info
->cd_status
= (ChanStatus
& CD_ACT
) ? 1 : 0;
487 wake_up_interruptible(&info
->open_wait
);
489 #ifdef ROCKET_DEBUG_INTR
490 if (IntMask
& DELTA_CTS
) { /* CTS change */
491 printk("CTS change...\n");
493 if (IntMask
& DELTA_DSR
) { /* DSR change */
494 printk("DSR change...\n");
500 * The top level polling routine.
502 static void rp_do_poll(unsigned long dummy
)
505 int ctrl
, aiop
, ch
, line
;
506 unsigned int xmitmask
;
507 unsigned char CtlMask
, AiopMask
;
510 unsigned long low
=0, high
=0, loop_time
;
511 unsigned long long time_stat_tmp
=0, time_stat_tmp2
=0;
513 __asm__(".byte 0x0f,0x31"
514 :"=a" (low
), "=d" (high
));
515 time_stat_tmp
= high
;
516 time_stat_tmp
<<= 32;
517 time_stat_tmp
+= low
;
518 #endif /* TIME_STAT */
520 for (ctrl
=0; ctrl
< max_board
; ctrl
++) {
521 if (rcktpt_io_addr
[ctrl
] <= 0)
523 ctlp
= sCtlNumToCtlPtr(ctrl
);
526 if(ctlp
->BusType
== isPCI
)
527 CtlMask
= sPCIGetControllerIntStatus(ctlp
);
530 CtlMask
= sGetControllerIntStatus(ctlp
);
531 for (aiop
=0; CtlMask
; CtlMask
>>= 1, aiop
++) {
533 AiopMask
= sGetAiopIntStatus(ctlp
, aiop
);
534 for (ch
=0; AiopMask
; AiopMask
>>= 1, ch
++) {
538 rp_handle_port(rp_table
[line
]);
543 xmitmask
= xmit_flags
[ctrl
];
544 for (line
= ctrl
<< 5; xmitmask
; xmitmask
>>= 1, line
++) {
546 rp_do_transmit(rp_table
[line
]);
551 * Reset the timer so we get called at the next clock tick.
553 if (rp_num_ports_open
) {
554 mod_timer(&rocket_timer
, jiffies
+ 1);
557 __asm__(".byte 0x0f,0x31"
558 :"=a" (low
), "=d" (high
));
559 time_stat_tmp2
= high
;
560 time_stat_tmp2
<<= 32;
561 time_stat_tmp2
+= low
;
562 time_stat_tmp2
-= time_stat_tmp
;
563 time_stat
+= time_stat_tmp2
;
564 if (time_counter
== 0)
565 time_stat_short
= time_stat_long
= time_stat_tmp2
;
567 if ( time_stat_tmp2
< time_stat_short
)
568 time_stat_short
= time_stat_tmp2
;
569 else if ( time_stat_tmp2
> time_stat_long
)
570 time_stat_long
= time_stat_tmp2
;
572 if ( ++time_counter
== TIME_COUNTER
) {
573 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
)));
574 #ifdef TIME_STAT_VERBOSE
575 printk("rp_do_poll: Interrupt Timings\n");
576 printk(" %5ld iterations; %ld us min,\n",
577 (long)TIME_COUNTER
, (time_stat_short
/TIME_STAT_CPU
));
578 printk(" %5ld us max, %ld us average per iteration.\n",
579 (time_stat_long
/TIME_STAT_CPU
), loop_time
);
580 printk("We want to use < 5,000 us for an iteration.\n");
581 #else /* TIME_STAT_VERBOSE */
582 printk("rp: %ld loops: %ld min, %ld max, %ld us/loop.\n",
583 (long)TIME_COUNTER
, (time_stat_short
/TIME_STAT_CPU
),
584 (time_stat_long
/TIME_STAT_CPU
), loop_time
);
585 #endif /* TIME_STAT_VERBOSE */
586 time_counter
= time_stat
= 0;
587 time_stat_short
= time_stat_long
= 0;
589 #endif /* TIME_STAT */
592 * Here ends the interrupt/polling routine.
597 * This function initializes the r_port structure, as well as enabling
598 * the port on the RocketPort board.
600 static void init_r_port(int board
, int aiop
, int chan
)
607 line
= (board
<< 5) | (aiop
<< 3) | chan
;
609 ctlp
= sCtlNumToCtlPtr(board
);
611 info
= kmalloc(sizeof(struct r_port
), GFP_KERNEL
);
613 printk("Couldn't allocate info struct for line #%d\n", line
);
616 memset(info
, 0, sizeof(struct r_port
));
618 info
->magic
= RPORT_MAGIC
;
624 info
->closing_wait
= 3000;
625 info
->close_delay
= 50;
626 info
->callout_termios
=callout_driver
.init_termios
;
627 info
->normal_termios
= rocket_driver
.init_termios
;
628 init_waitqueue_head(&info
->open_wait
);
629 init_waitqueue_head(&info
->close_wait
);
631 info
->intmask
= RXF_TRIG
| TXFIFO_MT
| SRC_INT
| DELTA_CD
|
632 DELTA_CTS
| DELTA_DSR
;
633 if (sInitChan(ctlp
, &info
->channel
, aiop
, chan
) == 0) {
634 printk("Rocketport sInitChan(%d, %d, %d) failed!\n",
640 rp_table
[line
] = info
;
643 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
644 static int baud_table
[] = {
645 0, 50, 75, 110, 134, 150, 200, 300,
646 600, 1200, 1800, 2400, 4800, 9600, 19200,
647 38400, 57600, 115200, 230400, 460800, 0 };
651 * This routine configures a rocketport port so according to its
654 static void configure_r_port(struct r_port
*info
)
659 #if (LINUX_VERSION_CODE < 131393) /* Linux 2.1.65 */
664 if (!info
->tty
|| !info
->tty
->termios
)
667 cflag
= info
->tty
->termios
->c_cflag
;
669 /* Byte size and parity */
670 if ((cflag
& CSIZE
) == CS8
) {
677 if (cflag
& CSTOPB
) {
684 if (cflag
& PARENB
) {
687 if (cflag
& PARODD
) {
697 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
702 info
->tty
->termios
->c_cflag
&= ~CBAUDEX
;
707 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_HI
)
709 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_VHI
)
711 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_SHI
)
713 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_WARP
)
716 baud
= baud_table
[i
] ? baud_table
[i
] : 9600;
718 baud
= tty_get_baud_rate(info
->tty
);
722 info
->cps
= baud
/ bits
;
723 sSetBaud(cp
, (rp_baud_base
/baud
) - 1);
725 if (cflag
& CRTSCTS
) {
726 info
->intmask
|= DELTA_CTS
;
729 info
->intmask
&= ~DELTA_CTS
;
732 sSetRTS(&info
->channel
);
734 info
->intmask
&= ~DELTA_CD
;
736 save_flags(flags
); cli();
737 if (sGetChanStatus(cp
) & CD_ACT
)
741 info
->intmask
|= DELTA_CD
;
742 restore_flags(flags
);
746 * Handle software flow control in the board
748 #ifdef ROCKET_SOFT_FLOW
749 if (I_IXON(info
->tty
)) {
750 sEnTxSoftFlowCtl(cp
);
751 if (I_IXANY(info
->tty
)) {
756 sSetTxXONChar(cp
, START_CHAR(info
->tty
));
757 sSetTxXOFFChar(cp
, STOP_CHAR(info
->tty
));
759 sDisTxSoftFlowCtl(cp
);
766 * Set up ignore/read mask words
768 info
->read_status_mask
= STMRCVROVRH
| 0xFF;
769 if (I_INPCK(info
->tty
))
770 info
->read_status_mask
|= STMFRAMEH
| STMPARITYH
;
771 if (I_BRKINT(info
->tty
) || I_PARMRK(info
->tty
))
772 info
->read_status_mask
|= STMBREAKH
;
775 * Characters to ignore
777 info
->ignore_status_mask
= 0;
778 if (I_IGNPAR(info
->tty
))
779 info
->ignore_status_mask
|= STMFRAMEH
| STMPARITYH
;
780 if (I_IGNBRK(info
->tty
)) {
781 info
->ignore_status_mask
|= STMBREAKH
;
783 * If we're ignoring parity and break indicators,
784 * ignore overruns too. (For real raw support).
786 if (I_IGNPAR(info
->tty
))
787 info
->ignore_status_mask
|= STMRCVROVRH
;
791 static int block_til_ready(struct tty_struct
*tty
, struct file
* filp
,
794 DECLARE_WAITQUEUE(wait
, current
);
796 int do_clocal
= 0, extra_count
= 0;
800 * If the device is in the middle of being closed, then block
801 * until it's done, and then try again.
803 if (tty_hung_up_p(filp
))
804 return ((info
->flags
& ROCKET_HUP_NOTIFY
) ?
805 -EAGAIN
: -ERESTARTSYS
);
806 if (info
->flags
& ROCKET_CLOSING
) {
807 interruptible_sleep_on(&info
->close_wait
);
808 return ((info
->flags
& ROCKET_HUP_NOTIFY
) ?
809 -EAGAIN
: -ERESTARTSYS
);
813 * If this is a callout device, then just make sure the normal
814 * device isn't being used.
816 if (tty
->driver
.subtype
== SERIAL_TYPE_CALLOUT
) {
817 if (info
->flags
& ROCKET_NORMAL_ACTIVE
)
819 if ((info
->flags
& ROCKET_CALLOUT_ACTIVE
) &&
820 (info
->flags
& ROCKET_SESSION_LOCKOUT
) &&
821 (info
->session
!= current
->session
))
823 if ((info
->flags
& ROCKET_CALLOUT_ACTIVE
) &&
824 (info
->flags
& ROCKET_PGRP_LOCKOUT
) &&
825 (info
->pgrp
!= current
->pgrp
))
827 info
->flags
|= ROCKET_CALLOUT_ACTIVE
;
832 * If non-blocking mode is set, or the port is not enabled,
833 * then make the check up front and then exit.
835 if ((filp
->f_flags
& O_NONBLOCK
) ||
836 (tty
->flags
& (1 << TTY_IO_ERROR
))) {
837 if (info
->flags
& ROCKET_CALLOUT_ACTIVE
)
839 info
->flags
|= ROCKET_NORMAL_ACTIVE
;
843 if (info
->flags
& ROCKET_CALLOUT_ACTIVE
) {
844 if (info
->normal_termios
.c_cflag
& CLOCAL
)
847 if (tty
->termios
->c_cflag
& CLOCAL
)
852 * Block waiting for the carrier detect and the line to become
853 * free (i.e., not in use by the callout). While we are in
854 * this loop, info->count is dropped by one, so that
855 * rp_close() knows when to free things. We restore it upon
856 * exit, either normal or abnormal.
859 add_wait_queue(&info
->open_wait
, &wait
);
860 #ifdef ROCKET_DEBUG_OPEN
861 printk("block_til_ready before block: ttyR%d, count = %d\n",
862 info
->line
, info
->count
);
864 save_flags(flags
); cli();
865 if (!tty_hung_up_p(filp
)) {
869 restore_flags(flags
);
870 info
->blocked_open
++;
872 if (!(info
->flags
& ROCKET_CALLOUT_ACTIVE
) &&
873 (tty
->termios
->c_cflag
& CBAUD
)) {
874 sSetDTR(&info
->channel
);
875 sSetRTS(&info
->channel
);
877 set_current_state(TASK_INTERRUPTIBLE
);
878 if (tty_hung_up_p(filp
) ||
879 !(info
->flags
& ROCKET_INITIALIZED
)) {
880 if (info
->flags
& ROCKET_HUP_NOTIFY
)
883 retval
= -ERESTARTSYS
;
886 if (!(info
->flags
& ROCKET_CALLOUT_ACTIVE
) &&
887 !(info
->flags
& ROCKET_CLOSING
) &&
888 (do_clocal
|| (sGetChanStatusLo(&info
->channel
) &
891 if (signal_pending(current
)) {
892 retval
= -ERESTARTSYS
;
895 #ifdef ROCKET_DEBUG_OPEN
896 printk("block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n",
897 info
->line
, info
->count
, info
->flags
);
901 current
->state
= TASK_RUNNING
;
902 remove_wait_queue(&info
->open_wait
, &wait
);
906 restore_flags(flags
);
907 info
->blocked_open
--;
908 #ifdef ROCKET_DEBUG_OPEN
909 printk("block_til_ready after blocking: ttyR%d, count = %d\n",
910 info
->line
, info
->count
);
914 info
->flags
|= ROCKET_NORMAL_ACTIVE
;
919 * This routine is called whenever a rocketport board is opened.
921 static int rp_open(struct tty_struct
*tty
, struct file
* filp
)
928 line
= MINOR(tty
->device
) - tty
->driver
.minor_start
;
929 if ((line
< 0) || (line
>= MAX_RP_PORTS
))
932 page
= get_free_page(GFP_KERNEL
);
938 tmp_buf
= (unsigned char *) page
;
940 page
= get_free_page(GFP_KERNEL
);
944 tty
->driver_data
= info
= rp_table
[line
];
946 if (info
->flags
& ROCKET_CLOSING
) {
947 interruptible_sleep_on(&info
->close_wait
);
949 return ((info
->flags
& ROCKET_HUP_NOTIFY
) ?
950 -EAGAIN
: -ERESTARTSYS
);
954 * We must not sleep from here until the port is marked fully
957 if (rp_table
[line
] == NULL
) {
958 tty
->flags
= (1 << TTY_IO_ERROR
);
963 printk("rp_open: rp_table[%d] is NULL!\n", line
);
970 info
->xmit_buf
= (unsigned char *) page
;
973 if (info
->flags
& ROCKET_CLOSING
) {
974 interruptible_sleep_on(&info
->close_wait
);
975 return ((info
->flags
& ROCKET_HUP_NOTIFY
) ?
976 -EAGAIN
: -ERESTARTSYS
);
979 if (info
->count
++ == 0) {
984 #ifdef ROCKET_DEBUG_OPEN
985 printk("rocket mod++ = %d...", rp_num_ports_open
);
988 #ifdef ROCKET_DEBUG_OPEN
989 printk("rp_open ttyR%d, count=%d\n", info
->line
, info
->count
);
992 * Info->count is now 1; so it's safe to sleep now.
994 info
->session
= current
->session
;
995 info
->pgrp
= current
->pgrp
;
998 sSetRxTrigger(cp
, TRIG_1
);
999 if (sGetChanStatus(cp
) & CD_ACT
)
1000 info
->cd_status
= 1;
1002 info
->cd_status
= 0;
1003 sDisRxStatusMode(cp
);
1007 sEnInterrupts(cp
, (TXINT_EN
|MCINT_EN
|RXINT_EN
|SRCINT_EN
|CHANINT_EN
));
1008 sSetRxTrigger(cp
, TRIG_1
);
1011 sDisRxStatusMode(cp
);
1015 sDisTxSoftFlowCtl(cp
);
1020 info
->flags
|= ROCKET_INITIALIZED
;
1022 #if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
1024 * Set up the tty->alt_speed kludge
1026 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_HI
)
1027 info
->tty
->alt_speed
= 57600;
1028 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_VHI
)
1029 info
->tty
->alt_speed
= 115200;
1030 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_SHI
)
1031 info
->tty
->alt_speed
= 230400;
1032 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_WARP
)
1033 info
->tty
->alt_speed
= 460800;
1036 configure_r_port(info
);
1037 if (tty
->termios
->c_cflag
& CBAUD
) {
1042 mod_timer(&rocket_timer
, jiffies
+ 1);
1044 retval
= block_til_ready(tty
, filp
, info
);
1046 #ifdef ROCKET_DEBUG_OPEN
1047 printk("rp_open returning after block_til_ready with %d\n",
1053 if ((info
->count
== 1) && (info
->flags
& ROCKET_SPLIT_TERMIOS
)) {
1054 if (tty
->driver
.subtype
== SERIAL_TYPE_NORMAL
)
1055 *tty
->termios
= info
->normal_termios
;
1057 *tty
->termios
= info
->callout_termios
;
1058 configure_r_port(info
);
1064 static void rp_close(struct tty_struct
*tty
, struct file
* filp
)
1066 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1067 unsigned long flags
;
1071 if (rocket_paranoia_check(info
, tty
->device
, "rp_close"))
1074 #ifdef ROCKET_DEBUG_OPEN
1075 printk("rp_close ttyR%d, count = %d\n", info
->line
, info
->count
);
1078 save_flags(flags
); cli();
1080 if (tty_hung_up_p(filp
)) {
1081 restore_flags(flags
);
1084 if ((tty
->count
== 1) && (info
->count
!= 1)) {
1086 * Uh, oh. tty->count is 1, which means that the tty
1087 * structure will be freed. Info->count should always
1088 * be one in these conditions. If it's greater than
1089 * one, we've got real problems, since it means the
1090 * serial port won't be shutdown.
1092 printk("rp_close: bad serial port count; tty->count is 1, "
1093 "info->count is %d\n", info
->count
);
1096 if (--info
->count
< 0) {
1097 printk("rp_close: bad serial port count for ttyR%d: %d\n",
1098 info
->line
, info
->count
);
1102 restore_flags(flags
);
1105 info
->flags
|= ROCKET_CLOSING
;
1107 * Save the termios structure, since this port may have
1108 * separate termios for callout and dialin.
1110 if (info
->flags
& ROCKET_NORMAL_ACTIVE
)
1111 info
->normal_termios
= *tty
->termios
;
1112 if (info
->flags
& ROCKET_CALLOUT_ACTIVE
)
1113 info
->callout_termios
= *tty
->termios
;
1115 cp
= &info
->channel
;
1118 * Notify the line discpline to only process XON/XOFF characters
1123 * If transmission was throttled by the application request,
1124 * just flush the xmit buffer.
1126 #if (LINUX_VERSION_CODE >= 131343)
1127 if (tty
->flow_stopped
)
1128 rp_flush_buffer(tty
);
1132 * Wait for the transmit buffer to clear
1134 if (info
->closing_wait
!= ROCKET_CLOSING_WAIT_NONE
)
1135 tty_wait_until_sent(tty
, info
->closing_wait
);
1137 * Before we drop DTR, make sure the UART transmitter
1138 * has completely drained; this is especially
1139 * important if there is a transmit FIFO!
1141 timeout
= (sGetTxCnt(cp
)+1) * HZ
/ info
->cps
;
1144 rp_wait_until_sent(tty
, timeout
);
1146 xmit_flags
[info
->line
>> 5] &= ~(1 << (info
->line
& 0x1f));
1148 sDisInterrupts(cp
, (TXINT_EN
|MCINT_EN
|RXINT_EN
|SRCINT_EN
|CHANINT_EN
));
1150 sDisTxSoftFlowCtl(cp
);
1158 if (tty
->driver
.flush_buffer
)
1159 tty
->driver
.flush_buffer(tty
);
1160 if (tty
->ldisc
.flush_buffer
)
1161 tty
->ldisc
.flush_buffer(tty
);
1163 xmit_flags
[info
->line
>> 5] &= ~(1 << (info
->line
& 0x1f));
1164 if (info
->blocked_open
) {
1165 if (info
->close_delay
) {
1166 current
->state
= TASK_INTERRUPTIBLE
;
1167 schedule_timeout(info
->close_delay
);
1169 wake_up_interruptible(&info
->open_wait
);
1171 if (info
->xmit_buf
) {
1172 free_page((unsigned long) info
->xmit_buf
);
1176 info
->flags
&= ~(ROCKET_INITIALIZED
| ROCKET_CLOSING
|
1177 ROCKET_CALLOUT_ACTIVE
| ROCKET_NORMAL_ACTIVE
);
1179 wake_up_interruptible(&info
->close_wait
);
1184 rp_num_ports_open
--;
1185 #ifdef ROCKET_DEBUG_OPEN
1186 printk("rocket mod-- = %d...", rp_num_ports_open
);
1188 restore_flags(flags
);
1190 #ifdef ROCKET_DEBUG_OPEN
1191 printk("rp_close ttyR%d complete shutdown\n", info
->line
);
1196 static void rp_set_termios(struct tty_struct
*tty
, struct termios
*old_termios
)
1198 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1203 if (rocket_paranoia_check(info
, tty
->device
, "rp_set_termios"))
1206 cflag
= tty
->termios
->c_cflag
;
1208 if (cflag
== old_termios
->c_cflag
)
1212 * This driver doesn't support CS5 or CS6
1214 if (((cflag
& CSIZE
) == CS5
) ||
1215 ((cflag
& CSIZE
) == CS6
))
1216 tty
->termios
->c_cflag
= ((cflag
& ~CSIZE
) |
1217 (old_termios
->c_cflag
& CSIZE
));
1219 configure_r_port(info
);
1221 cp
= &info
->channel
;
1223 /* Handle transition to B0 status */
1224 if ((old_termios
->c_cflag
& CBAUD
) &&
1225 !(tty
->termios
->c_cflag
& CBAUD
)) {
1230 /* Handle transition away from B0 status */
1231 if (!(old_termios
->c_cflag
& CBAUD
) &&
1232 (tty
->termios
->c_cflag
& CBAUD
)) {
1233 if (!tty
->hw_stopped
||
1234 !(tty
->termios
->c_cflag
& CRTSCTS
)) {
1240 if ((old_termios
->c_cflag
& CRTSCTS
) &&
1241 !(tty
->termios
->c_cflag
& CRTSCTS
)) {
1242 tty
->hw_stopped
= 0;
1248 * Here are the routines used by rp_ioctl
1250 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
1251 static void send_break( struct r_port
* info
, int duration
)
1253 current
->state
= TASK_INTERRUPTIBLE
;
1255 sSendBreak(&info
->channel
);
1256 schedule_timeout(duration
);
1257 sClrBreak(&info
->channel
);
1261 static void rp_break(struct tty_struct
*tty
, int break_state
)
1263 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1264 unsigned long flags
;
1266 if (rocket_paranoia_check(info
, tty
->device
, "rp_break"))
1269 save_flags(flags
); cli();
1270 if (break_state
== -1) {
1271 sSendBreak(&info
->channel
);
1273 sClrBreak(&info
->channel
);
1275 restore_flags(flags
);
1279 static int get_modem_info(struct r_port
* info
, unsigned int *value
)
1281 unsigned int control
, result
, ChanStatus
;
1283 ChanStatus
= sGetChanStatusLo(&info
->channel
);
1285 control
= info
->channel
.TxControl
[3];
1286 result
= ((control
& SET_RTS
) ? TIOCM_RTS
: 0)
1287 | ((control
& SET_DTR
) ? TIOCM_DTR
: 0)
1288 | ((ChanStatus
& CD_ACT
) ? TIOCM_CAR
: 0)
1289 /* TIOCM_RNG not supported */
1290 | ((ChanStatus
& DSR_ACT
) ? TIOCM_DSR
: 0)
1291 | ((ChanStatus
& CTS_ACT
) ? TIOCM_CTS
: 0);
1293 if (copy_to_user(value
, &result
, sizeof(int)))
1298 static int set_modem_info(struct r_port
* info
, unsigned int cmd
,
1299 unsigned int *value
)
1303 if (copy_from_user(&arg
, value
, sizeof(int)))
1308 if (arg
& TIOCM_RTS
)
1309 info
->channel
.TxControl
[3] |= SET_RTS
;
1310 if (arg
& TIOCM_DTR
)
1311 info
->channel
.TxControl
[3] |= SET_DTR
;
1314 if (arg
& TIOCM_RTS
)
1315 info
->channel
.TxControl
[3] &= ~SET_RTS
;
1316 if (arg
& TIOCM_DTR
)
1317 info
->channel
.TxControl
[3] &= ~SET_DTR
;
1320 info
->channel
.TxControl
[3] =
1321 ((info
->channel
.TxControl
[3] & ~(SET_RTS
| SET_DTR
))
1322 | ((arg
& TIOCM_RTS
) ? SET_RTS
: 0)
1323 | ((arg
& TIOCM_DTR
) ? SET_DTR
: 0));
1329 sOutDW(info
->channel
.IndexAddr
,
1330 *(DWord_t
*) &(info
->channel
.TxControl
[0]));
1335 static int get_config(struct r_port
* info
, struct rocket_config
* retinfo
)
1337 struct rocket_config tmp
;
1341 memset(&tmp
, 0, sizeof(tmp
));
1342 tmp
.line
= info
->line
;
1343 tmp
.flags
= info
->flags
;
1344 tmp
.close_delay
= info
->close_delay
;
1345 tmp
.closing_wait
= info
->closing_wait
;
1346 tmp
.port
= rcktpt_io_addr
[(info
->line
>> 5) & 3];
1348 if (copy_to_user(retinfo
,&tmp
,sizeof(*retinfo
)))
1353 static int set_config(struct r_port
* info
, struct rocket_config
* new_info
)
1355 struct rocket_config new_serial
;
1357 if (copy_from_user(&new_serial
, new_info
, sizeof(new_serial
)))
1360 #ifdef CAP_SYS_ADMIN
1361 if (!capable(CAP_SYS_ADMIN
))
1366 if ((new_serial
.flags
& ~ROCKET_USR_MASK
) !=
1367 (info
->flags
& ~ROCKET_USR_MASK
))
1369 info
->flags
= ((info
->flags
& ~ROCKET_USR_MASK
) |
1370 (new_serial
.flags
& ROCKET_USR_MASK
));
1371 configure_r_port(info
);
1375 info
->flags
= ((info
->flags
& ~ROCKET_FLAGS
) |
1376 (new_serial
.flags
& ROCKET_FLAGS
));
1377 info
->close_delay
= new_serial
.close_delay
;
1378 info
->closing_wait
= new_serial
.closing_wait
;
1380 #if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
1381 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_HI
)
1382 info
->tty
->alt_speed
= 57600;
1383 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_VHI
)
1384 info
->tty
->alt_speed
= 115200;
1385 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_SHI
)
1386 info
->tty
->alt_speed
= 230400;
1387 if ((info
->flags
& ROCKET_SPD_MASK
) == ROCKET_SPD_WARP
)
1388 info
->tty
->alt_speed
= 460800;
1391 configure_r_port(info
);
1395 static int get_ports(struct r_port
* info
, struct rocket_ports
* retports
)
1397 struct rocket_ports tmp
;
1398 int board
, port
, index
;
1402 memset(&tmp
, 0, sizeof(tmp
));
1403 tmp
.tty_major
= rocket_driver
.major
;
1404 tmp
.callout_major
= callout_driver
.major
;
1405 for (board
= 0; board
< 4; board
++) {
1407 for (port
= 0; port
< 32; port
++, index
++) {
1408 if (rp_table
[index
])
1409 tmp
.port_bitmap
[board
] |= 1 << port
;
1412 if (copy_to_user(retports
,&tmp
,sizeof(*retports
)))
1417 static int rp_ioctl(struct tty_struct
*tty
, struct file
* file
,
1418 unsigned int cmd
, unsigned long arg
)
1420 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1421 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
1425 if (cmd
!= RCKP_GET_PORTS
&&
1426 rocket_paranoia_check(info
, tty
->device
, "rp_ioctl"))
1430 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
1431 case TCSBRK
: /* SVID version: non-zero arg --> no break */
1432 retval
= tty_check_change(tty
);
1435 tty_wait_until_sent(tty
, 0);
1436 if (signal_pending(current
))
1439 send_break(info
, HZ
/4); /* 1/4 second */
1440 if (signal_pending(current
))
1444 case TCSBRKP
: /* support for POSIX tcsendbreak() */
1445 retval
= tty_check_change(tty
);
1448 tty_wait_until_sent(tty
, 0);
1449 if (signal_pending(current
))
1451 send_break(info
, arg
? arg
*(HZ
/10) : HZ
/4);
1452 if (signal_pending(current
))
1456 tmp
= C_CLOCAL(tty
) ? 1 : 0;
1457 if (copy_to_user((void *)arg
, &tmp
, sizeof(int)))
1461 if (copy_from_user(&tmp
, (void *)arg
, sizeof(int)))
1464 tty
->termios
->c_cflag
=
1465 ((tty
->termios
->c_cflag
& ~CLOCAL
) |
1466 (tmp
? CLOCAL
: 0));
1470 return get_modem_info(info
, (unsigned int *) arg
);
1474 return set_modem_info(info
, cmd
, (unsigned int *) arg
);
1475 case RCKP_GET_STRUCT
:
1476 if (copy_to_user((void *) arg
, info
,
1477 sizeof(struct r_port
)))
1481 case RCKP_GET_CONFIG
:
1482 return get_config(info
, (struct rocket_config
*) arg
);
1483 case RCKP_SET_CONFIG
:
1484 return set_config(info
, (struct rocket_config
*) arg
);
1486 case RCKP_GET_PORTS
:
1487 return get_ports(info
, (struct rocket_ports
*) arg
);
1489 return -ENOIOCTLCMD
;
1494 #if (defined(ROCKET_DEBUG_FLOW) || defined(ROCKET_DEBUG_THROTTLE))
1495 static char *rp_tty_name(struct tty_struct
*tty
, char *buf
)
1498 sprintf(buf
, "%s%d", tty
->driver
.name
,
1499 MINOR(tty
->device
) - tty
->driver
.minor_start
+
1500 tty
->driver
.name_base
);
1502 strcpy(buf
, "NULL tty");
1507 static void rp_send_xchar(struct tty_struct
*tty
, char ch
)
1509 struct r_port
*info
= (struct r_port
*)tty
->driver_data
;
1512 if (rocket_paranoia_check(info
, tty
->device
, "rp_send_xchar"))
1515 cp
= &info
->channel
;
1517 sWriteTxPrioByte(cp
, ch
);
1519 sWriteTxByte(sGetTxRxDataIO(cp
), ch
);
1522 static void rp_throttle(struct tty_struct
* tty
)
1524 struct r_port
*info
= (struct r_port
*)tty
->driver_data
;
1526 #ifdef ROCKET_DEBUG_THROTTLE
1529 printk("throttle %s: %d....\n", rp_tty_name(tty
, buf
),
1530 tty
->ldisc
.chars_in_buffer(tty
));
1533 if (rocket_paranoia_check(info
, tty
->device
, "rp_throttle"))
1536 cp
= &info
->channel
;
1538 rp_send_xchar(tty
, STOP_CHAR(tty
));
1540 sClrRTS(&info
->channel
);
1543 static void rp_unthrottle(struct tty_struct
* tty
)
1545 struct r_port
*info
= (struct r_port
*)tty
->driver_data
;
1547 #ifdef ROCKET_DEBUG_THROTTLE
1550 printk("unthrottle %s: %d....\n", rp_tty_name(tty
, buf
),
1551 tty
->ldisc
.chars_in_buffer(tty
));
1554 if (rocket_paranoia_check(info
, tty
->device
, "rp_throttle"))
1557 cp
= &info
->channel
;
1559 rp_send_xchar(tty
, START_CHAR(tty
));
1561 sSetRTS(&info
->channel
);
1565 * ------------------------------------------------------------
1566 * rp_stop() and rp_start()
1568 * This routines are called before setting or resetting tty->stopped.
1569 * They enable or disable transmitter interrupts, as necessary.
1570 * ------------------------------------------------------------
1572 static void rp_stop(struct tty_struct
*tty
)
1574 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1575 #ifdef ROCKET_DEBUG_FLOW
1578 printk("stop %s: %d %d....\n", rp_tty_name(tty
, buf
),
1579 info
->xmit_cnt
, info
->xmit_fifo_room
);
1582 if (rocket_paranoia_check(info
, tty
->device
, "rp_stop"))
1585 if (sGetTxCnt(&info
->channel
))
1586 sDisTransmit(&info
->channel
);
1589 static void rp_start(struct tty_struct
*tty
)
1591 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1592 #ifdef ROCKET_DEBUG_FLOW
1595 printk("start %s: %d %d....\n", rp_tty_name(tty
, buf
),
1596 info
->xmit_cnt
, info
->xmit_fifo_room
);
1599 if (rocket_paranoia_check(info
, tty
->device
, "rp_stop"))
1602 sEnTransmit(&info
->channel
);
1603 xmit_flags
[info
->line
>> 5] |= (1 << (info
->line
& 0x1f));
1607 * rp_wait_until_sent() --- wait until the transmitter is empty
1609 static void rp_wait_until_sent(struct tty_struct
*tty
, int timeout
)
1611 struct r_port
*info
= (struct r_port
*)tty
->driver_data
;
1613 unsigned long orig_jiffies
;
1614 int check_time
, exit_time
;
1617 if (rocket_paranoia_check(info
, tty
->device
, "rp_wait_until_sent"))
1620 cp
= &info
->channel
;
1622 orig_jiffies
= jiffies
;
1623 #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1624 printk("In RP_wait_until_sent(%d) (jiff=%lu)...", timeout
, jiffies
);
1625 printk("cps=%d...", info
->cps
);
1628 txcnt
= sGetTxCnt(cp
);
1630 if (sGetChanStatusLo(cp
) & TXSHRMT
)
1632 check_time
= (HZ
/ info
->cps
) / 5;
1634 check_time
= HZ
* txcnt
/ info
->cps
;
1636 exit_time
= orig_jiffies
+ timeout
- jiffies
;
1639 if (exit_time
< check_time
)
1640 check_time
= exit_time
;
1642 if (check_time
== 0)
1644 #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1645 printk("txcnt = %d (jiff=%lu,check=%d)...", txcnt
,
1646 jiffies
, check_time
);
1648 current
->state
= TASK_INTERRUPTIBLE
;
1649 schedule_timeout(check_time
);
1650 if (signal_pending(current
))
1653 current
->state
= TASK_RUNNING
;
1654 #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1655 printk("txcnt = %d (jiff=%lu)...done\n", txcnt
, jiffies
);
1660 * rp_hangup() --- called by tty_hangup() when a hangup is signaled.
1662 static void rp_hangup(struct tty_struct
*tty
)
1665 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1667 if (rocket_paranoia_check(info
, tty
->device
, "rp_hangup"))
1670 #if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
1671 printk("rp_hangup of ttyR%d...", info
->line
);
1674 * If the port is in the process of being closed, just force
1675 * the transmit buffer to be empty, and let rp_close handle
1678 if (info
->flags
& ROCKET_CLOSING
) {
1680 info
->xmit_cnt
= info
->xmit_head
= info
->xmit_tail
= 0;
1682 wake_up_interruptible(&tty
->write_wait
);
1689 rp_num_ports_open
--;
1692 xmit_flags
[info
->line
>> 5] &= ~(1 << (info
->line
& 0x1f));
1694 info
->flags
&= ~(ROCKET_NORMAL_ACTIVE
|ROCKET_CALLOUT_ACTIVE
);
1697 cp
= &info
->channel
;
1700 sDisInterrupts(cp
, (TXINT_EN
|MCINT_EN
|RXINT_EN
|SRCINT_EN
|CHANINT_EN
));
1702 sDisTxSoftFlowCtl(cp
);
1704 info
->flags
&= ~ROCKET_INITIALIZED
;
1706 wake_up_interruptible(&info
->open_wait
);
1710 * The Rocketport write routines. The Rocketport driver uses a
1711 * double-buffering strategy, with the twist that if the in-memory CPU
1712 * buffer is empty, and there's space in the transmit FIFO, the
1713 * writing routines will write directly to transmit FIFO.
1715 * This gets a little tricky, but I'm pretty sure I got it all right.
1717 static void rp_put_char(struct tty_struct
*tty
, unsigned char ch
)
1719 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1722 if (rocket_paranoia_check(info
, tty
->device
, "rp_put_char"))
1725 #ifdef ROCKET_DEBUG_WRITE
1726 printk("rp_put_char %c...", ch
);
1729 cp
= &info
->channel
;
1731 if (!tty
->stopped
&& !tty
->hw_stopped
&& info
->xmit_fifo_room
== 0)
1732 info
->xmit_fifo_room
= TXFIFO_SIZE
- sGetTxCnt(cp
);
1734 if (tty
->stopped
|| tty
->hw_stopped
||
1735 info
->xmit_fifo_room
== 0 || info
->xmit_cnt
!= 0) {
1736 info
->xmit_buf
[info
->xmit_head
++] = ch
;
1737 info
->xmit_head
&= XMIT_BUF_SIZE
-1;
1739 xmit_flags
[info
->line
>> 5] |= (1 << (info
->line
& 0x1f));
1741 sOutB(sGetTxRxDataIO(cp
), ch
);
1742 info
->xmit_fifo_room
--;
1746 static int rp_write(struct tty_struct
* tty
, int from_user
,
1747 const unsigned char *buf
, int count
)
1749 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1751 const unsigned char *b
;
1753 unsigned long flags
;
1755 if (count
<= 0 || rocket_paranoia_check(info
, tty
->device
, "rp_write"))
1758 #ifdef ROCKET_DEBUG_WRITE
1759 printk("rp_write %d chars...", count
);
1761 cp
= &info
->channel
;
1763 if (!tty
->stopped
&& !tty
->hw_stopped
&& info
->xmit_fifo_room
== 0)
1764 info
->xmit_fifo_room
= TXFIFO_SIZE
- sGetTxCnt(cp
);
1766 if (!tty
->stopped
&& !tty
->hw_stopped
&& info
->xmit_cnt
== 0
1767 && info
->xmit_fifo_room
>= 0) {
1768 c
= MIN(count
, info
->xmit_fifo_room
);
1772 c
-= copy_from_user(tmp_buf
, buf
, c
);
1775 /* In case we got pre-empted */
1782 c
= MIN(c
, info
->xmit_fifo_room
);
1784 sOutStrW(sGetTxRxDataIO(cp
), b
, c
/2);
1786 sOutB(sGetTxRxDataIO(cp
), b
[c
-1]);
1790 info
->xmit_fifo_room
-= c
;
1797 if (info
->tty
== 0) {
1798 restore_flags(flags
);
1801 c
= MIN(count
, MIN(XMIT_BUF_SIZE
- info
->xmit_cnt
- 1,
1802 XMIT_BUF_SIZE
- info
->xmit_head
));
1809 c
-= copy_from_user(tmp_buf
, buf
, c
);
1817 /* In case we got pre-empted */
1822 c
= MIN(c
, MIN(XMIT_BUF_SIZE
- info
->xmit_cnt
- 1,
1823 XMIT_BUF_SIZE
- info
->xmit_head
));
1824 memcpy(info
->xmit_buf
+ info
->xmit_head
, b
, c
);
1825 info
->xmit_head
= (info
->xmit_head
+ c
) & (XMIT_BUF_SIZE
-1);
1826 info
->xmit_cnt
+= c
;
1827 restore_flags(flags
);
1833 if ((retval
> 0) && !tty
->stopped
&& !tty
->hw_stopped
)
1834 xmit_flags
[info
->line
>> 5] |= (1 << (info
->line
& 0x1f));
1835 restore_flags(flags
);
1837 if (info
->xmit_cnt
< WAKEUP_CHARS
) {
1838 if ((tty
->flags
& (1 << TTY_DO_WRITE_WAKEUP
)) &&
1839 tty
->ldisc
.write_wakeup
)
1840 (tty
->ldisc
.write_wakeup
)(tty
);
1841 wake_up_interruptible(&tty
->write_wait
);
1847 * Return the number of characters that can be sent. We estimate
1848 * only using the in-memory transmit buffer only, and ignore the
1849 * potential space in the transmit FIFO.
1851 static int rp_write_room(struct tty_struct
*tty
)
1853 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1856 if (rocket_paranoia_check(info
, tty
->device
, "rp_write_room"))
1859 ret
= XMIT_BUF_SIZE
- info
->xmit_cnt
- 1;
1862 #ifdef ROCKET_DEBUG_WRITE
1863 printk("rp_write_room returns %d...", ret
);
1869 * Return the number of characters in the buffer. Again, this only
1870 * counts those characters in the in-memory transmit buffer.
1872 static int rp_chars_in_buffer(struct tty_struct
*tty
)
1874 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1877 if (rocket_paranoia_check(info
, tty
->device
, "rp_chars_in_buffer"))
1880 cp
= &info
->channel
;
1882 #ifdef ROCKET_DEBUG_WRITE
1883 printk("rp_chars_in_buffer returns %d...", info
->xmit_cnt
);
1885 return info
->xmit_cnt
;
1888 static void rp_flush_buffer(struct tty_struct
*tty
)
1890 struct r_port
* info
= (struct r_port
*)tty
->driver_data
;
1893 if (rocket_paranoia_check(info
, tty
->device
, "rp_flush_buffer"))
1897 info
->xmit_cnt
= info
->xmit_head
= info
->xmit_tail
= 0;
1899 wake_up_interruptible(&tty
->write_wait
);
1900 if ((tty
->flags
& (1 << TTY_DO_WRITE_WAKEUP
)) &&
1901 tty
->ldisc
.write_wakeup
)
1902 (tty
->ldisc
.write_wakeup
)(tty
);
1904 cp
= &info
->channel
;
1910 #if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
1911 /* For compatibility */
1912 static struct pci_dev
*pci_find_slot(unsigned char bus
,
1913 unsigned char device_fn
)
1915 unsigned short vendor_id
, device_id
;
1917 static struct pci_dev ret_struct
;
1919 error
= pcibios_read_config_word(bus
, device_fn
, PCI_VENDOR_ID
,
1921 ret
= pcibios_read_config_word(bus
, device_fn
, PCI_DEVICE_ID
,
1927 printk("PCI RocketPort error: %s not initializing due to error"
1928 "reading configuration space\n",
1929 pcibios_strerror(error
));
1933 memset(&ret_struct
, 0, sizeof(ret_struct
));
1934 ret_struct
.device
= device_id
;
1940 int __init
register_PCI(int i
, unsigned int bus
, unsigned int device_fn
)
1942 int num_aiops
, aiop
, max_num_aiops
, num_chan
, chan
;
1943 unsigned int aiopio
[MAX_AIOPS_PER_BOARD
];
1946 struct pci_dev
*dev
= pci_find_slot(bus
, device_fn
);
1947 #if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
1955 if (pci_enable_device(dev
))
1958 rcktpt_io_addr
[i
] = pci_resource_start (dev
, 0);
1959 switch(dev
->device
) {
1960 case PCI_DEVICE_ID_RP4QUAD
:
1964 case PCI_DEVICE_ID_RP8OCTA
:
1968 case PCI_DEVICE_ID_RP8INTF
:
1972 case PCI_DEVICE_ID_RP8J
:
1976 case PCI_DEVICE_ID_RP16INTF
:
1980 case PCI_DEVICE_ID_RP32INTF
:
1984 case PCI_DEVICE_ID_RPP4
:
1985 str
= "Plus Quadcable";
1988 case PCI_DEVICE_ID_RPP8
:
1989 str
= "Plus Octacable";
1992 case PCI_DEVICE_ID_RP8M
:
1993 str
= "8-port Modem";
1997 str
= "(unknown/unsupported)";
2001 for(aiop
=0;aiop
< max_num_aiops
;aiop
++)
2002 aiopio
[aiop
] = rcktpt_io_addr
[i
] + (aiop
* 0x40);
2003 ctlp
= sCtlNumToCtlPtr(i
);
2004 num_aiops
= sPCIInitController(ctlp
, i
,
2005 aiopio
, max_num_aiops
, 0,
2007 printk("Rocketport controller #%d found at %02x:%02x, "
2008 "%d AIOP(s) (PCI Rocketport %s)\n", i
, bus
, device_fn
,
2010 if(num_aiops
<= 0) {
2011 rcktpt_io_addr
[i
] = 0;
2014 for(aiop
= 0;aiop
< num_aiops
; aiop
++) {
2015 sResetAiopByNum(ctlp
, aiop
);
2016 sEnAiop(ctlp
, aiop
);
2017 num_chan
= sGetAiopNumChan(ctlp
, aiop
);
2018 for(chan
=0;chan
< num_chan
; chan
++)
2019 init_r_port(i
, aiop
, chan
);
2024 static int __init
init_PCI(int boards_found
)
2026 unsigned char bus
, device_fn
;
2029 for(i
=0; i
< (NUM_BOARDS
- boards_found
); i
++) {
2030 if (!pcibios_find_device(PCI_VENDOR_ID_RP
,
2031 PCI_DEVICE_ID_RP4QUAD
, i
, &bus
, &device_fn
))
2032 if (register_PCI(count
+boards_found
, bus
, device_fn
))
2034 if (!pcibios_find_device(PCI_VENDOR_ID_RP
,
2035 PCI_DEVICE_ID_RP8J
, i
, &bus
, &device_fn
))
2036 if (register_PCI(count
+boards_found
, bus
, device_fn
))
2038 if(!pcibios_find_device(PCI_VENDOR_ID_RP
,
2039 PCI_DEVICE_ID_RP8OCTA
, i
, &bus
, &device_fn
))
2040 if(register_PCI(count
+boards_found
, bus
, device_fn
))
2042 if(!pcibios_find_device(PCI_VENDOR_ID_RP
,
2043 PCI_DEVICE_ID_RP8INTF
, i
, &bus
, &device_fn
))
2044 if(register_PCI(count
+boards_found
, bus
, device_fn
))
2046 if(!pcibios_find_device(PCI_VENDOR_ID_RP
,
2047 PCI_DEVICE_ID_RP16INTF
, i
, &bus
, &device_fn
))
2048 if(register_PCI(count
+boards_found
, bus
, device_fn
))
2050 if(!pcibios_find_device(PCI_VENDOR_ID_RP
,
2051 PCI_DEVICE_ID_RP32INTF
, i
, &bus
, &device_fn
))
2052 if(register_PCI(count
+boards_found
, bus
, device_fn
))
2054 if(!pcibios_find_device(PCI_VENDOR_ID_RP
,
2055 PCI_DEVICE_ID_RP4QUAD
, i
, &bus
, &device_fn
))
2056 if(register_PCI(count
+boards_found
, bus
, device_fn
))
2058 if(!pcibios_find_device(PCI_VENDOR_ID_RP
,
2059 PCI_DEVICE_ID_RP8J
, i
, &bus
, &device_fn
))
2060 if(register_PCI(count
+boards_found
, bus
, device_fn
))
2062 if(!pcibios_find_device(PCI_VENDOR_ID_RP
,
2063 PCI_DEVICE_ID_RPP4
, i
, &bus
, &device_fn
))
2064 if(register_PCI(count
+boards_found
, bus
, device_fn
))
2066 if(!pcibios_find_device(PCI_VENDOR_ID_RP
,
2067 PCI_DEVICE_ID_RPP8
, i
, &bus
, &device_fn
))
2068 if(register_PCI(count
+boards_found
, bus
, device_fn
))
2070 if(!pcibios_find_device(PCI_VENDOR_ID_RP
,
2071 PCI_DEVICE_ID_RP8M
, i
, &bus
, &device_fn
))
2072 if(register_PCI(count
+boards_found
, bus
, device_fn
))
2079 static int __init
init_ISA(int i
, int *reserved_controller
)
2081 int num_aiops
, num_chan
;
2083 unsigned int aiopio
[MAX_AIOPS_PER_BOARD
];
2086 if (rcktpt_io_addr
[i
] == 0)
2089 if (check_region(rcktpt_io_addr
[i
],64)) {
2090 printk("RocketPort board address 0x%lx in use...\n",
2092 rcktpt_io_addr
[i
] = 0;
2096 for (aiop
=0; aiop
<MAX_AIOPS_PER_BOARD
; aiop
++)
2097 aiopio
[aiop
]= rcktpt_io_addr
[i
] + (aiop
* 0x400);
2098 ctlp
= sCtlNumToCtlPtr(i
);
2099 num_aiops
= sInitController(ctlp
, i
, controller
+ (i
*0x400),
2100 aiopio
, MAX_AIOPS_PER_BOARD
, 0,
2102 if (num_aiops
<= 0) {
2103 rcktpt_io_addr
[i
] = 0;
2106 for (aiop
= 0; aiop
< num_aiops
; aiop
++) {
2107 sResetAiopByNum(ctlp
, aiop
);
2108 sEnAiop(ctlp
, aiop
);
2109 num_chan
= sGetAiopNumChan(ctlp
,aiop
);
2110 for (chan
=0; chan
< num_chan
; chan
++)
2111 init_r_port(i
, aiop
, chan
);
2113 printk("Rocketport controller #%d found at 0x%lx, "
2114 "%d AIOPs\n", i
, rcktpt_io_addr
[i
],
2116 if (rcktpt_io_addr
[i
] + 0x40 == controller
) {
2117 *reserved_controller
= 1;
2118 request_region(rcktpt_io_addr
[i
], 68,
2119 "Comtrol Rocketport");
2121 request_region(rcktpt_io_addr
[i
], 64,
2122 "Comtrol Rocketport");
2129 * The module "startup" routine; it's run when the module is loaded.
2131 int __init
rp_init(void)
2133 int i
, retval
, pci_boards_found
, isa_boards_found
;
2134 int reserved_controller
= 0;
2136 printk("Rocketport device driver module, version %s, %s\n",
2137 ROCKET_VERSION
, ROCKET_DATE
);
2140 * Set up the timer channel. If it is already in use by
2141 * some other driver, give up.
2143 if (rocket_timer
.function
) {
2144 printk("rocket.o: Timer already in use!\n");
2147 init_timer(&rocket_timer
);
2148 rocket_timer
.function
= rp_do_poll
;
2151 * Initialize the array of pointers to our own internal state
2154 memset(rp_table
, 0, sizeof(rp_table
));
2155 memset(xmit_flags
, 0, sizeof(xmit_flags
));
2159 if (controller
== 0)
2160 controller
= board1
+ 0x40;
2162 if (check_region(controller
, 4)) {
2163 printk("Controller IO addresses in use, unloading driver.\n");
2167 rcktpt_io_addr
[0] = board1
;
2168 rcktpt_io_addr
[1] = board2
;
2169 rcktpt_io_addr
[2] = board3
;
2170 rcktpt_io_addr
[3] = board4
;
2173 * If support_low_speed is set, use the slow clock prescale,
2174 * which supports 50 bps
2176 if (support_low_speed
) {
2177 sClockPrescale
= 0x19; /* mod 9 (divide by 10) prescale */
2178 rp_baud_base
= 230400;
2180 sClockPrescale
= 0x14; /* mod 4 (devide by 5) prescale */
2181 rp_baud_base
= 460800;
2185 * OK, let's probe each of the controllers looking for boards.
2187 isa_boards_found
= 0;
2188 pci_boards_found
= 0;
2189 for (i
=0; i
< NUM_BOARDS
; i
++) {
2190 if(init_ISA(i
, &reserved_controller
))
2194 if (pcibios_present()) {
2195 if(isa_boards_found
< NUM_BOARDS
)
2196 pci_boards_found
= init_PCI(isa_boards_found
);
2198 printk("No PCI BIOS found\n");
2201 max_board
= pci_boards_found
+ isa_boards_found
;
2203 if (max_board
== 0) {
2204 printk("No rocketport ports found; unloading driver.\n");
2205 rocket_timer
.function
= 0;
2209 if (reserved_controller
== 0)
2210 request_region(controller
, 4, "Comtrol Rocketport");
2213 * Set up the tty driver structure and then register this
2214 * driver with the tty layer.
2216 memset(&rocket_driver
, 0, sizeof(struct tty_driver
));
2217 rocket_driver
.magic
= TTY_DRIVER_MAGIC
;
2218 rocket_driver
.name
= "ttyR";
2219 rocket_driver
.major
= TTY_ROCKET_MAJOR
;
2220 rocket_driver
.minor_start
= 0;
2221 rocket_driver
.num
= MAX_RP_PORTS
;
2222 rocket_driver
.type
= TTY_DRIVER_TYPE_SERIAL
;
2223 rocket_driver
.subtype
= SERIAL_TYPE_NORMAL
;
2224 rocket_driver
.init_termios
= tty_std_termios
;
2225 rocket_driver
.init_termios
.c_cflag
=
2226 B9600
| CS8
| CREAD
| HUPCL
| CLOCAL
;
2227 rocket_driver
.flags
= TTY_DRIVER_REAL_RAW
;
2228 rocket_driver
.refcount
= &rocket_refcount
;
2229 rocket_driver
.table
= rocket_table
;
2230 rocket_driver
.termios
= rocket_termios
;
2231 rocket_driver
.termios_locked
= rocket_termios_locked
;
2233 rocket_driver
.open
= rp_open
;
2234 rocket_driver
.close
= rp_close
;
2235 rocket_driver
.write
= rp_write
;
2236 rocket_driver
.put_char
= rp_put_char
;
2237 rocket_driver
.write_room
= rp_write_room
;
2238 rocket_driver
.chars_in_buffer
= rp_chars_in_buffer
;
2239 rocket_driver
.flush_buffer
= rp_flush_buffer
;
2240 rocket_driver
.ioctl
= rp_ioctl
;
2241 rocket_driver
.throttle
= rp_throttle
;
2242 rocket_driver
.unthrottle
= rp_unthrottle
;
2243 rocket_driver
.set_termios
= rp_set_termios
;
2244 rocket_driver
.stop
= rp_stop
;
2245 rocket_driver
.start
= rp_start
;
2246 rocket_driver
.hangup
= rp_hangup
;
2247 #if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
2248 rocket_driver
.break_ctl
= rp_break
;
2250 #if (LINUX_VERSION_CODE >= 131343)
2251 rocket_driver
.send_xchar
= rp_send_xchar
;
2252 rocket_driver
.wait_until_sent
= rp_wait_until_sent
;
2256 * The callout device is just like normal device except for
2257 * the minor number and the subtype code.
2259 callout_driver
= rocket_driver
;
2260 callout_driver
.name
= "cur";
2261 callout_driver
.major
= CUA_ROCKET_MAJOR
;
2262 callout_driver
.minor_start
= 0;
2263 callout_driver
.subtype
= SERIAL_TYPE_CALLOUT
;
2265 retval
= tty_register_driver(&callout_driver
);
2267 printk("Couldn't install Rocketport callout driver "
2268 "(error %d)\n", -retval
);
2272 retval
= tty_register_driver(&rocket_driver
);
2274 printk("Couldn't install tty Rocketport driver "
2275 "(error %d)\n", -retval
);
2278 #ifdef ROCKET_DEBUG_OPEN
2279 printk("Rocketport driver is major %d, callout is %d\n",
2280 rocket_driver
.major
, callout_driver
.major
);
2287 int init_module(void)
2293 cleanup_module( void) {
2296 int released_controller
= 0;
2298 del_timer_sync(&rocket_timer
);
2300 retval
= tty_unregister_driver(&callout_driver
);
2302 printk("Error %d while trying to unregister "
2303 "rocketport callout driver\n", -retval
);
2305 retval
= tty_unregister_driver(&rocket_driver
);
2307 printk("Error %d while trying to unregister "
2308 "rocketport driver\n", -retval
);
2310 for (i
= 0; i
< MAX_RP_PORTS
; i
++) {
2314 for (i
=0; i
< NUM_BOARDS
; i
++) {
2315 if (rcktpt_io_addr
[i
] <= 0)
2317 if (rcktpt_io_addr
[i
] + 0x40 == controller
) {
2318 released_controller
++;
2319 release_region(rcktpt_io_addr
[i
], 68);
2321 release_region(rcktpt_io_addr
[i
], 64);
2322 if (released_controller
== 0)
2323 release_region(controller
, 4);
2326 free_page((unsigned long) tmp_buf
);
2327 rocket_timer
.function
= 0;
2331 /***********************************************************************
2332 Copyright 1994 Comtrol Corporation.
2333 All Rights Reserved.
2335 The following source code is subject to Comtrol Corporation's
2336 Developer's License Agreement.
2338 This source code is protected by United States copyright law and
2339 international copyright treaties.
2341 This source code may only be used to develop software products that
2342 will operate with Comtrol brand hardware.
2344 You may not reproduce nor distribute this source code in its original
2345 form but must produce a derivative work which includes portions of
2346 this source code only.
2348 The portions of this source code which you use in your derivative
2349 work must bear Comtrol's copyright notice:
2351 Copyright 1994 Comtrol Corporation.
2353 ***********************************************************************/
2363 static Byte_t RData
[RDATASIZE
] =
2365 0x00, 0x09, 0xf6, 0x82,
2366 0x02, 0x09, 0x86, 0xfb,
2367 0x04, 0x09, 0x00, 0x0a,
2368 0x06, 0x09, 0x01, 0x0a,
2369 0x08, 0x09, 0x8a, 0x13,
2370 0x0a, 0x09, 0xc5, 0x11,
2371 0x0c, 0x09, 0x86, 0x85,
2372 0x0e, 0x09, 0x20, 0x0a,
2373 0x10, 0x09, 0x21, 0x0a,
2374 0x12, 0x09, 0x41, 0xff,
2375 0x14, 0x09, 0x82, 0x00,
2376 0x16, 0x09, 0x82, 0x7b,
2377 0x18, 0x09, 0x8a, 0x7d,
2378 0x1a, 0x09, 0x88, 0x81,
2379 0x1c, 0x09, 0x86, 0x7a,
2380 0x1e, 0x09, 0x84, 0x81,
2381 0x20, 0x09, 0x82, 0x7c,
2382 0x22, 0x09, 0x0a, 0x0a
2385 static Byte_t RRegData
[RREGDATASIZE
]=
2387 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
2388 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
2389 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
2390 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
2391 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
2392 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
2393 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
2394 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
2395 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
2396 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
2397 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
2398 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
2399 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
2402 CONTROLLER_T sController
[CTL_SIZE
] =
2404 {-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}},
2405 {-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}},
2406 {-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}},
2407 {-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}}
2411 /* IRQ number to MUDBAC register 2 mapping */
2412 Byte_t sIRQMap
[16] =
2414 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
2418 Byte_t sBitMapClrTbl
[8] =
2420 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
2423 Byte_t sBitMapSetTbl
[8] =
2425 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
2428 int sClockPrescale
= 0x14;
2430 /***************************************************************************
2431 Function: sInitController
2432 Purpose: Initialization of controller global registers and controller
2434 Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
2435 IRQNum,Frequency,PeriodicOnly)
2436 CONTROLLER_T *CtlP; Ptr to controller structure
2437 int CtlNum; Controller number
2438 ByteIO_t MudbacIO; Mudbac base I/O address.
2439 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2440 This list must be in the order the AIOPs will be found on the
2441 controller. Once an AIOP in the list is not found, it is
2442 assumed that there are no more AIOPs on the controller.
2443 int AiopIOListSize; Number of addresses in AiopIOList
2444 int IRQNum; Interrupt Request number. Can be any of the following:
2445 0: Disable global interrupts
2454 Byte_t Frequency: A flag identifying the frequency
2455 of the periodic interrupt, can be any one of the following:
2456 FREQ_DIS - periodic interrupt disabled
2457 FREQ_137HZ - 137 Hertz
2458 FREQ_69HZ - 69 Hertz
2459 FREQ_34HZ - 34 Hertz
2460 FREQ_17HZ - 17 Hertz
2463 If IRQNum is set to 0 the Frequency parameter is
2464 overidden, it is forced to a value of FREQ_DIS.
2465 int PeriodicOnly: TRUE if all interrupts except the periodic
2466 interrupt are to be blocked.
2467 FALSE is both the periodic interrupt and
2468 other channel interrupts are allowed.
2469 If IRQNum is set to 0 the PeriodicOnly parameter is
2470 overidden, it is forced to a value of FALSE.
2471 Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2472 initialization failed.
2475 If periodic interrupts are to be disabled but AIOP interrupts
2476 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
2478 If interrupts are to be completely disabled set IRQNum to 0.
2480 Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
2481 invalid combination.
2483 This function performs initialization of global interrupt modes,
2484 but it does not actually enable global interrupts. To enable
2485 and disable global interrupts use functions sEnGlobalInt() and
2486 sDisGlobalInt(). Enabling of global interrupts is normally not
2487 done until all other initializations are complete.
2489 Even if interrupts are globally enabled, they must also be
2490 individually enabled for each channel that is to generate
2493 Warnings: No range checking on any of the parameters is done.
2495 No context switches are allowed while executing this function.
2497 After this function all AIOPs on the controller are disabled,
2498 they can be enabled with sEnAiop().
2500 int sInitController( CONTROLLER_T
*CtlP
,
2503 ByteIO_t
*AiopIOList
,
2512 CtlP
->CtlNum
= CtlNum
;
2513 CtlP
->CtlID
= CTLID_0001
; /* controller release 1 */
2514 CtlP
->BusType
= isISA
;
2515 CtlP
->MBaseIO
= MudbacIO
;
2516 CtlP
->MReg1IO
= MudbacIO
+ 1;
2517 CtlP
->MReg2IO
= MudbacIO
+ 2;
2518 CtlP
->MReg3IO
= MudbacIO
+ 3;
2520 CtlP
->MReg2
= 0; /* interrupt disable */
2521 CtlP
->MReg3
= 0; /* no periodic interrupts */
2523 if(sIRQMap
[IRQNum
] == 0) /* interrupts globally disabled */
2525 CtlP
->MReg2
= 0; /* interrupt disable */
2526 CtlP
->MReg3
= 0; /* no periodic interrupts */
2530 CtlP
->MReg2
= sIRQMap
[IRQNum
]; /* set IRQ number */
2531 CtlP
->MReg3
= Frequency
; /* set frequency */
2532 if(PeriodicOnly
) /* periodic interrupt only */
2534 CtlP
->MReg3
|= PERIODIC_ONLY
;
2538 sOutB(CtlP
->MReg2IO
,CtlP
->MReg2
);
2539 sOutB(CtlP
->MReg3IO
,CtlP
->MReg3
);
2540 sControllerEOI(CtlP
); /* clear EOI if warm init */
2543 for(i
=0; i
< AiopIOListSize
; i
++)
2546 CtlP
->AiopIO
[i
] = (WordIO_t
)io
;
2547 CtlP
->AiopIntChanIO
[i
] = io
+ _INT_CHAN
;
2548 sOutB(CtlP
->MReg2IO
,CtlP
->MReg2
| (i
& 0x03)); /* AIOP index */
2549 sOutB(MudbacIO
,(Byte_t
)(io
>> 6)); /* set up AIOP I/O in MUDBAC */
2550 sEnAiop(CtlP
,i
); /* enable the AIOP */
2552 CtlP
->AiopID
[i
] = sReadAiopID(io
); /* read AIOP ID */
2553 if(CtlP
->AiopID
[i
] == AIOPID_NULL
) /* if AIOP does not exist */
2555 sDisAiop(CtlP
,i
); /* disable AIOP */
2556 break; /* done looking for AIOPs */
2559 CtlP
->AiopNumChan
[i
] = sReadAiopNumChan((WordIO_t
)io
); /* num channels in AIOP */
2560 sOutW((WordIO_t
)io
+ _INDX_ADDR
,_CLK_PRE
); /* clock prescaler */
2561 sOutB(io
+ _INDX_DATA
,sClockPrescale
);
2562 CtlP
->NumAiop
++; /* bump count of AIOPs */
2563 sDisAiop(CtlP
,i
); /* disable AIOP */
2566 if(CtlP
->NumAiop
== 0)
2569 return(CtlP
->NumAiop
);
2572 /***************************************************************************
2573 Function: sPCIInitController
2574 Purpose: Initialization of controller global registers and controller
2576 Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
2577 IRQNum,Frequency,PeriodicOnly)
2578 CONTROLLER_T *CtlP; Ptr to controller structure
2579 int CtlNum; Controller number
2580 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2581 This list must be in the order the AIOPs will be found on the
2582 controller. Once an AIOP in the list is not found, it is
2583 assumed that there are no more AIOPs on the controller.
2584 int AiopIOListSize; Number of addresses in AiopIOList
2585 int IRQNum; Interrupt Request number. Can be any of the following:
2586 0: Disable global interrupts
2595 Byte_t Frequency: A flag identifying the frequency
2596 of the periodic interrupt, can be any one of the following:
2597 FREQ_DIS - periodic interrupt disabled
2598 FREQ_137HZ - 137 Hertz
2599 FREQ_69HZ - 69 Hertz
2600 FREQ_34HZ - 34 Hertz
2601 FREQ_17HZ - 17 Hertz
2604 If IRQNum is set to 0 the Frequency parameter is
2605 overidden, it is forced to a value of FREQ_DIS.
2606 int PeriodicOnly: TRUE if all interrupts except the periodic
2607 interrupt are to be blocked.
2608 FALSE is both the periodic interrupt and
2609 other channel interrupts are allowed.
2610 If IRQNum is set to 0 the PeriodicOnly parameter is
2611 overidden, it is forced to a value of FALSE.
2612 Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2613 initialization failed.
2616 If periodic interrupts are to be disabled but AIOP interrupts
2617 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
2619 If interrupts are to be completely disabled set IRQNum to 0.
2621 Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
2622 invalid combination.
2624 This function performs initialization of global interrupt modes,
2625 but it does not actually enable global interrupts. To enable
2626 and disable global interrupts use functions sEnGlobalInt() and
2627 sDisGlobalInt(). Enabling of global interrupts is normally not
2628 done until all other initializations are complete.
2630 Even if interrupts are globally enabled, they must also be
2631 individually enabled for each channel that is to generate
2634 Warnings: No range checking on any of the parameters is done.
2636 No context switches are allowed while executing this function.
2638 After this function all AIOPs on the controller are disabled,
2639 they can be enabled with sEnAiop().
2641 int sPCIInitController( CONTROLLER_T
*CtlP
,
2643 ByteIO_t
*AiopIOList
,
2652 CtlP
->CtlNum
= CtlNum
;
2653 CtlP
->CtlID
= CTLID_0001
; /* controller release 1 */
2654 CtlP
->BusType
= isPCI
; /* controller release 1 */
2656 CtlP
->PCIIO
= (WordIO_t
)((ByteIO_t
)AiopIOList
[0] + _PCI_INT_FUNC
);
2658 sPCIControllerEOI(CtlP
); /* clear EOI if warm init */
2661 for(i
=0; i
< AiopIOListSize
; i
++)
2664 CtlP
->AiopIO
[i
] = (WordIO_t
)io
;
2665 CtlP
->AiopIntChanIO
[i
] = io
+ _INT_CHAN
;
2667 CtlP
->AiopID
[i
] = sReadAiopID(io
); /* read AIOP ID */
2668 if(CtlP
->AiopID
[i
] == AIOPID_NULL
) /* if AIOP does not exist */
2669 break; /* done looking for AIOPs */
2671 CtlP
->AiopNumChan
[i
] = sReadAiopNumChan((WordIO_t
)io
); /* num channels in AIOP */
2672 sOutW((WordIO_t
)io
+ _INDX_ADDR
,_CLK_PRE
); /* clock prescaler */
2673 sOutB(io
+ _INDX_DATA
,sClockPrescale
);
2674 CtlP
->NumAiop
++; /* bump count of AIOPs */
2677 if(CtlP
->NumAiop
== 0)
2680 return(CtlP
->NumAiop
);
2683 /***************************************************************************
2684 Function: sReadAiopID
2685 Purpose: Read the AIOP idenfication number directly from an AIOP.
2686 Call: sReadAiopID(io)
2687 ByteIO_t io: AIOP base I/O address
2688 Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
2689 is replace by an identifying number.
2690 Flag AIOPID_NULL if no valid AIOP is found
2691 Warnings: No context switches are allowed while executing this function.
2694 int sReadAiopID(ByteIO_t io
)
2696 Byte_t AiopID
; /* ID byte from AIOP */
2698 sOutB(io
+ _CMD_REG
,RESET_ALL
); /* reset AIOP */
2699 sOutB(io
+ _CMD_REG
,0x0);
2700 AiopID
= sInB(io
+ _CHN_STAT0
) & 0x07;
2703 else /* AIOP does not exist */
2707 /***************************************************************************
2708 Function: sReadAiopNumChan
2709 Purpose: Read the number of channels available in an AIOP directly from
2711 Call: sReadAiopNumChan(io)
2712 WordIO_t io: AIOP base I/O address
2713 Return: int: The number of channels available
2714 Comments: The number of channels is determined by write/reads from identical
2715 offsets within the SRAM address spaces for channels 0 and 4.
2716 If the channel 4 space is mirrored to channel 0 it is a 4 channel
2717 AIOP, otherwise it is an 8 channel.
2718 Warnings: No context switches are allowed while executing this function.
2720 int sReadAiopNumChan(WordIO_t io
)
2724 sOutDW((DWordIO_t
)io
+ _INDX_ADDR
,0x12340000L
); /* write to chan 0 SRAM */
2725 sOutW(io
+ _INDX_ADDR
,0); /* read from SRAM, chan 0 */
2726 x
= sInW(io
+ _INDX_DATA
);
2727 sOutW(io
+ _INDX_ADDR
,0x4000); /* read from SRAM, chan 4 */
2728 if(x
!= sInW(io
+ _INDX_DATA
)) /* if different must be 8 chan */
2734 /***************************************************************************
2736 Purpose: Initialization of a channel and channel structure
2737 Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
2738 CONTROLLER_T *CtlP; Ptr to controller structure
2739 CHANNEL_T *ChP; Ptr to channel structure
2740 int AiopNum; AIOP number within controller
2741 int ChanNum; Channel number within AIOP
2742 Return: int: TRUE if initialization succeeded, FALSE if it fails because channel
2743 number exceeds number of channels available in AIOP.
2744 Comments: This function must be called before a channel can be used.
2745 Warnings: No range checking on any of the parameters is done.
2747 No context switches are allowed while executing this function.
2749 int sInitChan( CONTROLLER_T
*CtlP
,
2762 if(ChanNum
>= CtlP
->AiopNumChan
[AiopNum
])
2763 return(FALSE
); /* exceeds num chans in AIOP */
2765 /* Channel, AIOP, and controller identifiers */
2767 ChP
->ChanID
= CtlP
->AiopID
[AiopNum
];
2768 ChP
->AiopNum
= AiopNum
;
2769 ChP
->ChanNum
= ChanNum
;
2771 /* Global direct addresses */
2772 AiopIO
= CtlP
->AiopIO
[AiopNum
];
2773 ChP
->Cmd
= (ByteIO_t
)AiopIO
+ _CMD_REG
;
2774 ChP
->IntChan
= (ByteIO_t
)AiopIO
+ _INT_CHAN
;
2775 ChP
->IntMask
= (ByteIO_t
)AiopIO
+ _INT_MASK
;
2776 ChP
->IndexAddr
= (DWordIO_t
)AiopIO
+ _INDX_ADDR
;
2777 ChP
->IndexData
= AiopIO
+ _INDX_DATA
;
2779 /* Channel direct addresses */
2780 ChIOOff
= AiopIO
+ ChP
->ChanNum
* 2;
2781 ChP
->TxRxData
= ChIOOff
+ _TD0
;
2782 ChP
->ChanStat
= ChIOOff
+ _CHN_STAT0
;
2783 ChP
->TxRxCount
= ChIOOff
+ _FIFO_CNT0
;
2784 ChP
->IntID
= (ByteIO_t
)AiopIO
+ ChP
->ChanNum
+ _INT_ID0
;
2786 /* Initialize the channel from the RData array */
2787 for(i
=0; i
< RDATASIZE
; i
+=4)
2790 R
[1] = RData
[i
+1] + 0x10 * ChanNum
;
2793 sOutDW(ChP
->IndexAddr
,*((DWord_t
*)&R
[0]));
2797 for(i
=0; i
< RREGDATASIZE
; i
+=4)
2799 ChR
[i
] = RRegData
[i
];
2800 ChR
[i
+1] = RRegData
[i
+1] + 0x10 * ChanNum
;
2801 ChR
[i
+2] = RRegData
[i
+2];
2802 ChR
[i
+3] = RRegData
[i
+3];
2805 /* Indexed registers */
2806 ChOff
= (Word_t
)ChanNum
* 0x1000;
2808 if (sClockPrescale
== 0x14)
2813 ChP
->BaudDiv
[0] = (Byte_t
)(ChOff
+ _BAUD
);
2814 ChP
->BaudDiv
[1] = (Byte_t
)((ChOff
+ _BAUD
) >> 8);
2815 ChP
->BaudDiv
[2] = (Byte_t
)brd9600
;
2816 ChP
->BaudDiv
[3] = (Byte_t
)(brd9600
>> 8);
2817 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->BaudDiv
[0]);
2819 ChP
->TxControl
[0] = (Byte_t
)(ChOff
+ _TX_CTRL
);
2820 ChP
->TxControl
[1] = (Byte_t
)((ChOff
+ _TX_CTRL
) >> 8);
2821 ChP
->TxControl
[2] = 0;
2822 ChP
->TxControl
[3] = 0;
2823 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->TxControl
[0]);
2825 ChP
->RxControl
[0] = (Byte_t
)(ChOff
+ _RX_CTRL
);
2826 ChP
->RxControl
[1] = (Byte_t
)((ChOff
+ _RX_CTRL
) >> 8);
2827 ChP
->RxControl
[2] = 0;
2828 ChP
->RxControl
[3] = 0;
2829 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->RxControl
[0]);
2831 ChP
->TxEnables
[0] = (Byte_t
)(ChOff
+ _TX_ENBLS
);
2832 ChP
->TxEnables
[1] = (Byte_t
)((ChOff
+ _TX_ENBLS
) >> 8);
2833 ChP
->TxEnables
[2] = 0;
2834 ChP
->TxEnables
[3] = 0;
2835 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->TxEnables
[0]);
2837 ChP
->TxCompare
[0] = (Byte_t
)(ChOff
+ _TXCMP1
);
2838 ChP
->TxCompare
[1] = (Byte_t
)((ChOff
+ _TXCMP1
) >> 8);
2839 ChP
->TxCompare
[2] = 0;
2840 ChP
->TxCompare
[3] = 0;
2841 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->TxCompare
[0]);
2843 ChP
->TxReplace1
[0] = (Byte_t
)(ChOff
+ _TXREP1B1
);
2844 ChP
->TxReplace1
[1] = (Byte_t
)((ChOff
+ _TXREP1B1
) >> 8);
2845 ChP
->TxReplace1
[2] = 0;
2846 ChP
->TxReplace1
[3] = 0;
2847 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->TxReplace1
[0]);
2849 ChP
->TxReplace2
[0] = (Byte_t
)(ChOff
+ _TXREP2
);
2850 ChP
->TxReplace2
[1] = (Byte_t
)((ChOff
+ _TXREP2
) >> 8);
2851 ChP
->TxReplace2
[2] = 0;
2852 ChP
->TxReplace2
[3] = 0;
2853 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->TxReplace2
[0]);
2855 ChP
->TxFIFOPtrs
= ChOff
+ _TXF_OUTP
;
2856 ChP
->TxFIFO
= ChOff
+ _TX_FIFO
;
2858 sOutB(ChP
->Cmd
,(Byte_t
)ChanNum
| RESTXFCNT
); /* apply reset Tx FIFO count */
2859 sOutB(ChP
->Cmd
,(Byte_t
)ChanNum
); /* remove reset Tx FIFO count */
2860 sOutW((WordIO_t
)ChP
->IndexAddr
,ChP
->TxFIFOPtrs
); /* clear Tx in/out ptrs */
2861 sOutW(ChP
->IndexData
,0);
2862 ChP
->RxFIFOPtrs
= ChOff
+ _RXF_OUTP
;
2863 ChP
->RxFIFO
= ChOff
+ _RX_FIFO
;
2865 sOutB(ChP
->Cmd
,(Byte_t
)ChanNum
| RESRXFCNT
); /* apply reset Rx FIFO count */
2866 sOutB(ChP
->Cmd
,(Byte_t
)ChanNum
); /* remove reset Rx FIFO count */
2867 sOutW((WordIO_t
)ChP
->IndexAddr
,ChP
->RxFIFOPtrs
); /* clear Rx out ptr */
2868 sOutW(ChP
->IndexData
,0);
2869 sOutW((WordIO_t
)ChP
->IndexAddr
,ChP
->RxFIFOPtrs
+ 2); /* clear Rx in ptr */
2870 sOutW(ChP
->IndexData
,0);
2871 ChP
->TxPrioCnt
= ChOff
+ _TXP_CNT
;
2872 sOutW((WordIO_t
)ChP
->IndexAddr
,ChP
->TxPrioCnt
);
2873 sOutB(ChP
->IndexData
,0);
2874 ChP
->TxPrioPtr
= ChOff
+ _TXP_PNTR
;
2875 sOutW((WordIO_t
)ChP
->IndexAddr
,ChP
->TxPrioPtr
);
2876 sOutB(ChP
->IndexData
,0);
2877 ChP
->TxPrioBuf
= ChOff
+ _TXP_BUF
;
2878 sEnRxProcessor(ChP
); /* start the Rx processor */
2883 /***************************************************************************
2884 Function: sStopRxProcessor
2885 Purpose: Stop the receive processor from processing a channel.
2886 Call: sStopRxProcessor(ChP)
2887 CHANNEL_T *ChP; Ptr to channel structure
2889 Comments: The receive processor can be started again with sStartRxProcessor().
2890 This function causes the receive processor to skip over the
2891 stopped channel. It does not stop it from processing other channels.
2893 Warnings: No context switches are allowed while executing this function.
2895 Do not leave the receive processor stopped for more than one
2898 After calling this function a delay of 4 uS is required to ensure
2899 that the receive processor is no longer processing this channel.
2901 void sStopRxProcessor(CHANNEL_T
*ChP
)
2909 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&R
[0]);
2912 /***************************************************************************
2913 Function: sFlushRxFIFO
2914 Purpose: Flush the Rx FIFO
2915 Call: sFlushRxFIFO(ChP)
2916 CHANNEL_T *ChP; Ptr to channel structure
2918 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2919 while it is being flushed the receive processor is stopped
2920 and the transmitter is disabled. After these operations a
2921 4 uS delay is done before clearing the pointers to allow
2922 the receive processor to stop. These items are handled inside
2924 Warnings: No context switches are allowed while executing this function.
2926 void sFlushRxFIFO(CHANNEL_T
*ChP
)
2929 Byte_t Ch
; /* channel number within AIOP */
2930 int RxFIFOEnabled
; /* TRUE if Rx FIFO enabled */
2932 if(sGetRxCnt(ChP
) == 0) /* Rx FIFO empty */
2933 return; /* don't need to flush */
2935 RxFIFOEnabled
= FALSE
;
2936 if(ChP
->R
[0x32] == 0x08) /* Rx FIFO is enabled */
2938 RxFIFOEnabled
= TRUE
;
2939 sDisRxFIFO(ChP
); /* disable it */
2940 for(i
=0; i
< 2000/200; i
++) /* delay 2 uS to allow proc to disable FIFO*/
2941 sInB(ChP
->IntChan
); /* depends on bus i/o timing */
2943 sGetChanStatus(ChP
); /* clear any pending Rx errors in chan stat */
2944 Ch
= (Byte_t
)sGetChanNum(ChP
);
2945 sOutB(ChP
->Cmd
,Ch
| RESRXFCNT
); /* apply reset Rx FIFO count */
2946 sOutB(ChP
->Cmd
,Ch
); /* remove reset Rx FIFO count */
2947 sOutW((WordIO_t
)ChP
->IndexAddr
,ChP
->RxFIFOPtrs
); /* clear Rx out ptr */
2948 sOutW(ChP
->IndexData
,0);
2949 sOutW((WordIO_t
)ChP
->IndexAddr
,ChP
->RxFIFOPtrs
+ 2); /* clear Rx in ptr */
2950 sOutW(ChP
->IndexData
,0);
2952 sEnRxFIFO(ChP
); /* enable Rx FIFO */
2955 /***************************************************************************
2956 Function: sFlushTxFIFO
2957 Purpose: Flush the Tx FIFO
2958 Call: sFlushTxFIFO(ChP)
2959 CHANNEL_T *ChP; Ptr to channel structure
2961 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2962 while it is being flushed the receive processor is stopped
2963 and the transmitter is disabled. After these operations a
2964 4 uS delay is done before clearing the pointers to allow
2965 the receive processor to stop. These items are handled inside
2967 Warnings: No context switches are allowed while executing this function.
2969 void sFlushTxFIFO(CHANNEL_T
*ChP
)
2972 Byte_t Ch
; /* channel number within AIOP */
2973 int TxEnabled
; /* TRUE if transmitter enabled */
2975 if(sGetTxCnt(ChP
) == 0) /* Tx FIFO empty */
2976 return; /* don't need to flush */
2979 if(ChP
->TxControl
[3] & TX_ENABLE
)
2982 sDisTransmit(ChP
); /* disable transmitter */
2984 sStopRxProcessor(ChP
); /* stop Rx processor */
2985 for(i
= 0; i
< 4000/200; i
++) /* delay 4 uS to allow proc to stop */
2986 sInB(ChP
->IntChan
); /* depends on bus i/o timing */
2987 Ch
= (Byte_t
)sGetChanNum(ChP
);
2988 sOutB(ChP
->Cmd
,Ch
| RESTXFCNT
); /* apply reset Tx FIFO count */
2989 sOutB(ChP
->Cmd
,Ch
); /* remove reset Tx FIFO count */
2990 sOutW((WordIO_t
)ChP
->IndexAddr
,ChP
->TxFIFOPtrs
); /* clear Tx in/out ptrs */
2991 sOutW(ChP
->IndexData
,0);
2993 sEnTransmit(ChP
); /* enable transmitter */
2994 sStartRxProcessor(ChP
); /* restart Rx processor */
2997 /***************************************************************************
2998 Function: sWriteTxPrioByte
2999 Purpose: Write a byte of priority transmit data to a channel
3000 Call: sWriteTxPrioByte(ChP,Data)
3001 CHANNEL_T *ChP; Ptr to channel structure
3002 Byte_t Data; The transmit data byte
3004 Return: int: 1 if the bytes is successfully written, otherwise 0.
3006 Comments: The priority byte is transmitted before any data in the Tx FIFO.
3008 Warnings: No context switches are allowed while executing this function.
3010 int sWriteTxPrioByte(CHANNEL_T
*ChP
, Byte_t Data
)
3012 Byte_t DWBuf
[4]; /* buffer for double word writes */
3013 Word_t
*WordPtr
; /* must be far because Win SS != DS */
3014 register DWordIO_t IndexAddr
;
3016 if(sGetTxCnt(ChP
) > 1) /* write it to Tx priority buffer */
3018 IndexAddr
= ChP
->IndexAddr
;
3019 sOutW((WordIO_t
)IndexAddr
,ChP
->TxPrioCnt
); /* get priority buffer status */
3020 if(sInB((ByteIO_t
)ChP
->IndexData
) & PRI_PEND
) /* priority buffer busy */
3021 return(0); /* nothing sent */
3023 WordPtr
= (Word_t
*)(&DWBuf
[0]);
3024 *WordPtr
= ChP
->TxPrioBuf
; /* data byte address */
3026 DWBuf
[2] = Data
; /* data byte value */
3027 sOutDW(IndexAddr
,*((DWord_t
*)(&DWBuf
[0]))); /* write it out */
3029 *WordPtr
= ChP
->TxPrioCnt
; /* Tx priority count address */
3031 DWBuf
[2] = PRI_PEND
+ 1; /* indicate 1 byte pending */
3032 DWBuf
[3] = 0; /* priority buffer pointer */
3033 sOutDW(IndexAddr
,*((DWord_t
*)(&DWBuf
[0]))); /* write it out */
3035 else /* write it to Tx FIFO */
3037 sWriteTxByte(sGetTxRxDataIO(ChP
),Data
);
3039 return(1); /* 1 byte sent */
3042 /***************************************************************************
3043 Function: sEnInterrupts
3044 Purpose: Enable one or more interrupts for a channel
3045 Call: sEnInterrupts(ChP,Flags)
3046 CHANNEL_T *ChP; Ptr to channel structure
3047 Word_t Flags: Interrupt enable flags, can be any combination
3048 of the following flags:
3049 TXINT_EN: Interrupt on Tx FIFO empty
3050 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3052 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3053 MCINT_EN: Interrupt on modem input change
3054 CHANINT_EN: Allow channel interrupt signal to the AIOP's
3055 Interrupt Channel Register.
3057 Comments: If an interrupt enable flag is set in Flags, that interrupt will be
3058 enabled. If an interrupt enable flag is not set in Flags, that
3059 interrupt will not be changed. Interrupts can be disabled with
3060 function sDisInterrupts().
3062 This function sets the appropriate bit for the channel in the AIOP's
3063 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
3064 this channel's bit to be set in the AIOP's Interrupt Channel Register.
3066 Interrupts must also be globally enabled before channel interrupts
3067 will be passed on to the host. This is done with function
3070 In some cases it may be desirable to disable interrupts globally but
3071 enable channel interrupts. This would allow the global interrupt
3072 status register to be used to determine which AIOPs need service.
3074 void sEnInterrupts(CHANNEL_T
*ChP
,Word_t Flags
)
3076 Byte_t Mask
; /* Interrupt Mask Register */
3078 ChP
->RxControl
[2] |=
3079 ((Byte_t
)Flags
& (RXINT_EN
| SRCINT_EN
| MCINT_EN
));
3081 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->RxControl
[0]);
3083 ChP
->TxControl
[2] |= ((Byte_t
)Flags
& TXINT_EN
);
3085 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->TxControl
[0]);
3087 if(Flags
& CHANINT_EN
)
3089 Mask
= sInB(ChP
->IntMask
) | sBitMapSetTbl
[ChP
->ChanNum
];
3090 sOutB(ChP
->IntMask
,Mask
);
3094 /***************************************************************************
3095 Function: sDisInterrupts
3096 Purpose: Disable one or more interrupts for a channel
3097 Call: sDisInterrupts(ChP,Flags)
3098 CHANNEL_T *ChP; Ptr to channel structure
3099 Word_t Flags: Interrupt flags, can be any combination
3100 of the following flags:
3101 TXINT_EN: Interrupt on Tx FIFO empty
3102 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3104 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3105 MCINT_EN: Interrupt on modem input change
3106 CHANINT_EN: Disable channel interrupt signal to the
3107 AIOP's Interrupt Channel Register.
3109 Comments: If an interrupt flag is set in Flags, that interrupt will be
3110 disabled. If an interrupt flag is not set in Flags, that
3111 interrupt will not be changed. Interrupts can be enabled with
3112 function sEnInterrupts().
3114 This function clears the appropriate bit for the channel in the AIOP's
3115 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
3116 this channel's bit from being set in the AIOP's Interrupt Channel
3119 void sDisInterrupts(CHANNEL_T
*ChP
,Word_t Flags
)
3121 Byte_t Mask
; /* Interrupt Mask Register */
3123 ChP
->RxControl
[2] &=
3124 ~((Byte_t
)Flags
& (RXINT_EN
| SRCINT_EN
| MCINT_EN
));
3125 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->RxControl
[0]);
3126 ChP
->TxControl
[2] &= ~((Byte_t
)Flags
& TXINT_EN
);
3127 sOutDW(ChP
->IndexAddr
,*(DWord_t
*)&ChP
->TxControl
[0]);
3129 if(Flags
& CHANINT_EN
)
3131 Mask
= sInB(ChP
->IntMask
) & sBitMapClrTbl
[ChP
->ChanNum
];
3132 sOutB(ChP
->IntMask
,Mask
);