ast@cs.vu.nl (Andy Tanenbaum) (07/14/88)
: This is a shar archive. Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'tty.c.part2'
sed 's/^X//' > 'tty.c.part2' << '+ END-OF-FILE ''tty.c.part2'
X /* Update terminal data structure. */
X count = offset - offset1; /* # characters printed */
X tp->tty_phys += count; /* advance physical data pointer */
X tp->tty_cum += count; /* number of characters printed */
X
X /* If all data has been copied to the terminal, send the reply. */
X if (tp->tty_outleft == 0) finish(tp, tp->tty_cum);
X}
X
X
X/*===========================================================================*
X * out_char *
X *===========================================================================*/
XPRIVATE out_char(tp, c)
Xregister struct tty_struct *tp; /* pointer to tty struct */
Xchar c; /* character to be output */
X{
X/* Output a character on the console. Check for escape sequences first. */
X
X if (tp->tty_esc_state > 0) {
X parse_escape(tp, c);
X return;
X }
X
X switch(c) {
X case 007: /* ring the bell */
X flush(tp); /* print any chars queued for output */
X beep(BEEP_FREQ);/* BEEP_FREQ gives bell tone */
X return;
X
X case 013: /* CTRL-K */
X move_to(tp, tp->tty_column, tp->tty_row - 1);
X return;
X
X case 014: /* CTRL-L */
X move_to(tp, tp->tty_column + 1, tp->tty_row);
X return;
X
X case 016: /* CTRL-N */
X move_to(tp, tp->tty_column + 1, tp->tty_row);
X return;
X
X case '\b': /* backspace */
X move_to(tp, tp->tty_column - 1, tp->tty_row);
X return;
X
X case '\n': /* line feed */
X if (tp->tty_mode & CRMOD) out_char(tp, '\r');
X if (tp->tty_row == SCR_LINES-1)
X scroll_screen(tp, GO_FORWARD);
X else
X tp->tty_row++;
X move_to(tp, tp->tty_column, tp->tty_row);
X return;
X
X case '\r': /* carriage return */
X move_to(tp, 0, tp->tty_row);
X return;
X
X case '\t': /* tab */
X if ( (tp->tty_mode & XTABS) == XTABS) {
X do {
X out_char(tp, ' ');
X } while (tp->tty_column & TAB_MASK);
X return;
X }
X /* Ignore tab if XTABS is off--video RAM has no hardware tab */
X return;
X
X case 033: /* ESC - start of an escape sequence */
X flush(tp); /* print any chars queued for output */
X tp->tty_esc_state = 1; /* mark ESC as seen */
X return;
X
X default: /* printable chars are stored in ramqueue */
X if (tp->tty_column >= LINE_WIDTH) return; /* long line */
X if (tp->tty_rwords == TTY_RAM_WORDS) flush(tp);
X tp->tty_ramqueue[tp->tty_rwords++]=tp->tty_attribute|(c & BYTE);
X tp->tty_column++; /* next column */
X return;
X }
X}
X
X/*===========================================================================*
X * scroll_screen *
X *===========================================================================*/
XPRIVATE scroll_screen(tp, dir)
Xregister struct tty_struct *tp; /* pointer to tty struct */
Xint dir; /* GO_FORWARD or GO_BACKWARD */
X{
X int amount, offset, bytes;
X
X bytes = 2 * (SCR_LINES - 1) * LINE_WIDTH; /* 2 * 24 * 80 bytes */
X
X /* Scrolling the screen is a real nuisance due to the various incompatible
X * video cards. This driver supports hardware scrolling (mono and CGA cards)
X * and software scrolling (EGA cards).
X */
X if (softscroll) {
X /* Software scrolling for non-IBM compatible EGA cards. */
X if (dir == GO_FORWARD) {
X scr_up(vid_base);
X vid_copy(NIL_PTR, vid_base, tp->tty_org+bytes, LINE_WIDTH);
X } else {
X scr_down(vid_base);
X vid_copy(NIL_PTR, vid_base, tp->tty_org, LINE_WIDTH);
X }
X } else {
X /* Normal scrolling using the 6845 registers. */
X amount = (dir == GO_FORWARD ? 2 * LINE_WIDTH : -2 * LINE_WIDTH);
X tp->tty_org = (tp->tty_org + amount) & vid_mask;
X if (dir == GO_FORWARD)
X offset = (tp->tty_org + bytes) & vid_mask;
X else
X offset = tp->tty_org;
X
X /* Blank the new line at top or bottom. */
X vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH);
X set_6845(VID_ORG, tp->tty_org >> 1); /* 6845 thinks in words */
X }
X}
X
X
X/*===========================================================================*
X * flush *
X *===========================================================================*/
XPRIVATE flush(tp)
Xregister struct tty_struct *tp; /* pointer to tty struct */
X{
X/* Have the characters in 'ramqueue' transferred to the screen. */
X
X if (tp->tty_rwords == 0) return;
X vid_copy((char *)tp->tty_ramqueue, vid_base, tp->tty_vid, tp->tty_rwords);
X
X /* Update the video parameters and cursor. */
X tp->tty_vid = (tp->tty_vid + 2 * tp->tty_rwords);
X set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */
X tp->tty_rwords = 0;
X}
X
X
X/*===========================================================================*
X * move_to *
X *===========================================================================*/
XPRIVATE move_to(tp, x, y)
Xstruct tty_struct *tp; /* pointer to tty struct */
Xint x; /* column (0 <= x <= 79) */
Xint y; /* row (0 <= y <= 24, 0 at top) */
X{
X/* Move the cursor to (x, y). */
X
X flush(tp); /* flush any pending characters */
X if (x < 0 || x >= LINE_WIDTH || y < 0 || y >= SCR_LINES) return;
X tp->tty_column = x; /* set x co-ordinate */
X tp->tty_row = y; /* set y co-ordinate */
X tp->tty_vid = (tp->tty_org + 2*y*LINE_WIDTH + 2*x);
X set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */
X}
X
X
X/*===========================================================================*
X * escape *
X *===========================================================================*/
XPRIVATE parse_escape(tp, c)
Xregister struct tty_struct *tp; /* pointer to tty struct */
Xchar c; /* next character in escape sequence */
X{
X/* The following ANSI escape sequences are currently supported:
X * ESC M to reverse index the screen
X * ESC [ y ; x H to move cursor to (x, y) [default (1,1)]
X * ESC [ 0 J to clear from cursor to end of screen
X * ESC [ n m to set the screen rendition
X * n: 0 = normal [default]
X * 7 = reverse
X */
X
X switch (tp->tty_esc_state) {
X case 1: /* ESC seen */
X tp->tty_esc_intro = '\0';
X tp->tty_esc_parmp = tp->tty_esc_parmv;
X tp->tty_esc_parmv[0] = tp->tty_esc_parmv[1] = 0;
X switch (c) {
X case '[': /* Control Sequence Introducer */
X tp->tty_esc_intro = c;
X tp->tty_esc_state = 2;
X break;
X case 'M': /* Reverse Index */
X do_escape(tp, c);
X break;
X default:
X tp->tty_esc_state = 0;
X break;
X }
X break;
X
X case 2: /* ESC [ seen */
X if (c >= '0' && c <= '9') {
X if (tp->tty_esc_parmp
X < tp->tty_esc_parmv + MAX_ESC_PARMS)
X *tp->tty_esc_parmp =
X *tp->tty_esc_parmp * 10 + (c - '0');
X break;
X }
X else if (c == ';') {
X if (++tp->tty_esc_parmp
X < tp->tty_esc_parmv + MAX_ESC_PARMS)
X *tp->tty_esc_parmp = 0;
X break;
X }
X else {
X do_escape(tp, c);
X }
X break;
X default: /* illegal state */
X tp->tty_esc_state = 0;
X break;
X }
X}
X
X
X/*===========================================================================*
X * do_escape *
X *===========================================================================*/
XPRIVATE do_escape(tp, c)
Xregister struct tty_struct *tp; /* pointer to tty struct */
Xchar c; /* next character in escape sequence */
X{
X int n, ct, vx;
X
X /* Handle a sequence beginning with just ESC */
X if (tp->tty_esc_intro == '\0') {
X switch (c) {
X case 'M': /* Reverse Index */
X if (tp->tty_row == 0)
X scroll_screen(tp, GO_BACKWARD);
X else
X tp->tty_row--;
X move_to(tp, tp->tty_column, tp->tty_row);
X break;
X default: break;
X }
X }
X else
X /* Handle a sequence beginning with ESC [ and parameters */
X if (tp->tty_esc_intro == '[') {
X switch (c) {
X case 'H': /* Position cursor */
X move_to(tp,
X MAX(1, MIN(LINE_WIDTH, tp->tty_esc_parmv[1])) - 1,
X MAX(1, MIN(SCR_LINES, tp->tty_esc_parmv[0])) - 1 );
X break;
X case 'J': /* Clear from cursor to end of screen */
X if (tp->tty_esc_parmv[0] == 0) {
X n = 2 * ((SCR_LINES - (tp->tty_row + 1)) * LINE_WIDTH
X + LINE_WIDTH - (tp->tty_column));
X vx = tp->tty_vid;
X while (n > 0) {
X ct = MIN(n, vid_retrace);
X vid_copy(NIL_PTR, vid_base, vx, ct/2);
X vx += ct;
X n -= ct;
X }
X }
X break;
X case 'm': /* Set graphic rendition */
X switch (tp->tty_esc_parmv[0]) {
X case 1: /* BOLD (light green on black) */
X tp->tty_attribute = 0x0A << 8;
X break;
X
X case 4: /* UNDERLINE (blue on red) */
X tp->tty_attribute = 0x41 << 8;
X break;
X
X case 5: /* BLINKING (light grey on black) */
X tp->tty_attribute = 0x87 << 8;
X break;
X
X case 7: /* REVERSE (black on light grey) */
X tp->tty_attribute = 0x70 << 8;
X break;
X
X default: tp->tty_attribute = 0007 << 8;
X break;
X }
X break;
X default:
X break;
X }
X }
X tp->tty_esc_state = 0;
X}
X
X
X/*===========================================================================*
X * set_6845 *
X *===========================================================================*/
XPRIVATE set_6845(reg, val)
Xint reg; /* which register pair to set */
Xint val; /* 16-bit value to set it to */
X{
X/* Set a register pair inside the 6845.
X * Registers 10-11 control the format of the cursor (how high it is, etc).
X * Registers 12-13 tell the 6845 where in video ram to start (in WORDS)
X * Registers 14-15 tell the 6845 where to put the cursor (in WORDS)
X *
X * Note that registers 12-15 work in words, i.e. 0x0000 is the top left
X * character, but 0x0001 (not 0x0002) is the next character. This addressing
X * is different from the way the 8088 addresses the video ram, where 0x0002
X * is the address of the next character.
X */
X port_out(vid_port + INDEX, reg); /* set the index register */
X port_out(vid_port + DATA, (val>>8) & BYTE); /* output high byte */
X port_out(vid_port + INDEX, reg + 1); /* again */
X port_out(vid_port + DATA, val&BYTE); /* output low byte */
X}
X
X
X/*===========================================================================*
X * beep *
X *===========================================================================*/
XPRIVATE beep(f)
Xint f; /* this value determines beep frequency */
X{
X/* Making a beeping sound on the speaker (output for CRTL-G). The beep is
X * kept short, because interrupts must be disabled during beeping, and it
X * is undesirable to keep them off too long. This routine works by turning
X * on the bits in port B of the 8255 chip that drive the speaker.
X */
X
X int x, k, s;
X
X s = lock(); /* disable interrupts */
X port_out(TIMER3,0xB6); /* set up timer channel 2 mode */
X port_out(TIMER2, f&BYTE); /* load low-order bits of frequency in timer */
X port_out(TIMER2,(f>>8)&BYTE); /* now high-order bits of frequency in timer */
X port_in(PORT_B,&x); /* acquire status of port B */
X port_out(PORT_B, x|3); /* turn bits 0 and 1 on to beep */
X for (k = 0; k < B_TIME; k++); /* delay loop while beeper sounding */
X port_out(PORT_B, x); /* restore port B the way it was */
X restore(s); /* re-enable interrupts to previous state */
X}
X
X
X/*===========================================================================*
X * set_leds *
X *===========================================================================*/
XPRIVATE set_leds()
X{
X/* Set the LEDs on the caps lock and num lock keys */
X
X int leds, dummy, i;
X
X if (pc_at == 0) return; /* PC/XT doesn't have LEDs */
X leds = (numlock<<1) | (capslock<<2); /* encode LED bits */
X port_out(KEYBD, LED_CODE); /* prepare keyboard to accept LED values */
X port_in(KEYBD, &dummy); /* keyboard sends ack; accept it */
X for (i = 0; i < LED_DELAY; i++) ; /* delay needed */
X port_out(KEYBD, leds); /* give keyboard LED values */
X port_in(KEYBD, &dummy); /* keyboard sends ack; accept it */
X}
X
X
X/*===========================================================================*
X * tty_init *
X *===========================================================================*/
XPRIVATE tty_init()
X{
X/* Initialize the tty tables. */
X
X register struct tty_struct *tp;
X
X /* Tell the EGA card, if any, to simulate a 16K CGA card. */
X port_out(EGA + INDEX, 4); /* register select */
X port_out(EGA + DATA, 1); /* no extended memory to be used */
X
X for (tp = &tty_struct[0]; tp < &tty_struct[NR_CONS]; tp++) {
X tp->tty_inhead = tp->tty_inqueue;
X tp->tty_intail = tp->tty_inqueue;
X tp->tty_mode = CRMOD | XTABS | ECHO;
X tp->tty_devstart = console;
X tp->tty_makebreak = TWO_INTS;
X tp->tty_attribute = BLANK;
X tp->tty_erase = ERASE_CHAR;
X tp->tty_kill = KILL_CHAR;
X tp->tty_intr = INTR_CHAR;
X tp->tty_quit = QUIT_CHAR;
X tp->tty_xon = XON_CHAR;
X tp->tty_xoff = XOFF_CHAR;
X tp->tty_eof = EOT_CHAR;
X }
X
X if (color) {
X vid_base = COLOR_BASE;
X vid_mask = C_VID_MASK;
X vid_port = C_6845;
X vid_retrace = C_RETRACE;
X } else {
X vid_base = MONO_BASE;
X vid_mask = M_VID_MASK;
X vid_port = M_6845;
X vid_retrace = M_RETRACE;
X }
X tty_driver_buf[1] = MAX_OVERRUN; /* set up limit on keyboard buffering*/
X set_6845(CUR_SIZE, 31); /* set cursor shape */
X set_6845(VID_ORG, 0); /* use page 0 of video ram */
X move_to(&tty_struct[0], 0, SCR_LINES-1); /* move cursor to lower left */
X
X /* Determine which keyboard type is attached. The bootstrap program asks
X * the user to type an '='. The scan codes for '=' differ depending on the
X * keyboard in use.
X */
X if (scan_code == OLIVETTI_EQUAL) olivetti = TRUE;
X}
X
X
X/*===========================================================================*
X * putc *
X *===========================================================================*/
XPUBLIC putc(c)
Xchar c; /* character to print */
X{
X/* This procedure is used by the version of printf() that is linked with
X * the kernel itself. The one in the library sends a message to FS, which is
X * not what is needed for printing within the kernel. This version just queues
X * the character and starts the output.
X */
X
X out_char(&tty_struct[0], c);
X}
X
X
X/*===========================================================================*
X * func_key *
X *===========================================================================*/
XPRIVATE func_key(ch)
Xchar ch; /* scan code for a function key */
X{
X/* This procedure traps function keys for debugging purposes. When MINIX is
X * fully debugged, it should be removed.
X */
X
X if (ch == F1) p_dmp(); /* print process table */
X if (ch == F2) map_dmp(); /* print memory map */
X if (ch == F3) { /* hardware vs. software scrolling */
X softscroll = 1 - softscroll; /* toggle scroll mode */
X tty_struct[0].tty_org = 0;
X move_to(&tty_struct[0], 0, SCR_LINES-1); /* cursor to lower left */
X set_6845(VID_ORG, 0);
X if (softscroll)
X printf("\033[H\033[JSoftware scrolling enabled.\n");
X else
X printf("\033[H\033[JHardware scrolling enabled.\n");
X }
X
X#ifdef AM_KERNEL
X#ifndef NONET
X if (ch == F4) net_init(); /* re-initialise the ethernet card */
X#endif NONET
X#endif AM_KERNEL
X if (ch == F9) sigchar(&tty_struct[0], SIGKILL); /* issue SIGKILL */
X}
X#endif
X
X/****************************************************************************
X ****************************************************************************
X ****************************************************************************
X ****************************************************************************/
X
X
X#ifdef i8088
X/* Now begins the code and data for the device RS232 drivers. */
X
X/* Definitions used by the RS232 driver. */
X#define RS_BUF_SIZE 256 /* output buffer per serial line */
X#define PRIMARY 0x3F8 /* I/O port of primary RS232 */
X#define SECONDARY 0x2F8 /* I/O port of secondary RS232 */
X#define SPARE 16 /* leave room in buffer for echoes */
X#define THRESHOLD 20 /* # chars to accumulate before msg */
X
X/* Constants relating to the 8250. */
X#define RS232_RATE_DIVISOR 0 /* address of baud rate divisor reg */
X#define RS232_TRANSMIT_HOLDING 0 /* address of transmitter holding reg*/
X#define RS232_RECEIVER_DATA_REG 0 /* address of receiver data register */
X#define RS232_INTERRUPTS 1 /* address of interrupt enable reg */
X#define RS232_INTERRUPT_ID_REG 2 /* address of interrupt id register */
X#define RS232_LINE_CONTROL 3 /* address of line control register */
X#define RS232_MODEM_CONTROL 4 /* address of modem control register */
X#define RS232_LINE_STATUS 5 /* address of line status register */
X#define RS232_MODEM_STATUS 6 /* address of modem status register */
X#define LINE_CONTROLS 0x0B /* odd parity,1 stop bit,8 data bits */
X#define MODEM_CONTROLS 0x0B /* RTS & DTR */
X#define ADDRESS_DIVISOR 0x80 /* value to address divisor */
X#define HOLDING_REG_EMPTY 0x20 /* transmitter holding reg empty */
X#define RS232_INTERRUPT_CLASSES 0x03 /* receiver Data Ready & xmt empty */
X#define UART_FREQ 115200L /* UART timer frequency */
X#define DEF_BAUD 1200 /* default baud rate */
X
X/* Line control setting related constants. */
X#define ODD 0
X#define EVEN 1
X#define NONE -1
X#define PARITY_ON_OFF 0x08 /* position of parity bit in line reg*/
X#define PARITY_TYPE_SHIFT 4 /* shift count for parity_type bit */
X#define STOP_BITS_SHIFT 2 /* shift count for # stop_bits */
X#define DATA_LEN 8 /* how much to shift sg_mode for len */
X
X/* RS232 interrupt types. */
X#define MODEM_STATUS 0x00 /* UART modem status change */
X#define TRANSMITTER_READY 0x02 /* transmitter ready to accept data */
X#define RECEIVER_READY 0x04 /* data received interrupt */
X#define LINE_STATUS 0x06 /* UART line status change */
X#define INT_TYPE_MASK 0x06 /* mask to mask out interrupt type */
X#define INT_PENDING 0x01 /* position of interrupt-pending bit */
X
X/* Status register values. */
X#define DATA_REGISTER_EMPTY 0x20 /* mask to see if data reg is empty */
X#define DATA_RECEIVED 0x01 /* mask to see if data has arrived */
X
X/* Global variables used by the RS232 driver. */
XPUBLIC message rs232_rd_mess; /* used when chars arrive from tty */
XPUBLIC message rs232_wt_mess; /* used when output to tty done */
XPUBLIC int flush_flag; /* indicates chars in tty_driver_buf */
XPRIVATE int first_rs_write_int_seen = FALSE;
X
XPRIVATE struct rs_struct{
X int rs_base; /* 0x3F8 for primary, 0x2F8 secondary*/
X int rs_busy; /* line is idle or not */
X int rs_left; /* # chars left in buffer to output */
X char *rs_next; /* pointer to next char to output */
X char rs_buf[RS_BUF_SIZE]; /* output buffer */
X} rs_struct[NR_RS_LINES];
X
X
X/*===========================================================================*
X * rs232 *
X *===========================================================================*/
XPUBLIC rs232(unit)
Xint unit; /* which unit caused the interrupt */
X{
X/* When an RS232 interrupt occurs, mpx88.s catches it and calls rs232().
X * Because more than one interrupt condition can occur at the same
X * time, the conditions are presented in the interrupt-identification
X * register in priority order, we have to keep scanning until the
X * interrupt-pending bit goes down. Only one communications port is really
X * supported here because the other vector is used by the Ethernet.
X */
X
X int interrupt_type, t, old_state, val;
X struct rs_struct *rs;
X
X old_state = lock();
X rs = &rs_struct[unit - NR_CONS];
X while (TRUE) {
X port_in(rs->rs_base + RS232_INTERRUPT_ID_REG, &interrupt_type);
X if ((interrupt_type & INT_PENDING) == 1) break; /* 1 = no interrupt */
X t = interrupt_type & INT_TYPE_MASK;
X switch(t) {
X case RECEIVER_READY: /* a character has arrived */
X rs_read_int(unit);
X break;
X
X case TRANSMITTER_READY: /* a character has been output */
X rs_write_int(unit);
X break;
X
X case LINE_STATUS: /* line status event, (disabled) */
X port_in(rs_struct[unit-1].rs_base + RS232_LINE_STATUS, &val);
X printf("RS 232 line status event %x\n", val);
X break;
X
X case MODEM_STATUS: /* modem status event, (disabled) */
X port_in(rs_struct[unit-1].rs_base + RS232_MODEM_STATUS, &val);
X printf("RS 232 modem status event %x\n", val);
X break;
X }
X }
X restore(old_state);
X}
X
X
X/*===========================================================================*
X * rs_read_int *
X *===========================================================================*/
XPRIVATE rs_read_int(line)
Xint line;
X{
X int val, k, base;
X
X base = rs_struct[line - NR_CONS].rs_base;
X
X /* Fetch the character from the RS232 hardware. */
X port_in(base + RS232_RECEIVER_DATA_REG, &val);
X
X /* Store the character in memory so the task can get at it later */
X if ((k = tty_driver_buf[0]) < tty_driver_buf[1]) {
X /* There is room to store this character, do it */
X k = k + k; /* each entry contains two bytes */
X tty_driver_buf[k + 2] = val; /* store the ascii code */
X tty_driver_buf[k + 3] = line; /* tell wich line it came from */
X tty_driver_buf[0]++; /* increment counter */
X
X if (tty_driver_buf[0] < THRESHOLD) {
X /* Don't send message. Just accumulate. Let clock do it. */
X port_out(INT_CTL, ENABLE);
X flush_flag++;
X return;
X }
X rs_flush(); /* send TTY task a message */
X } else {
X /* Too many character have been buffered. Discard excess */
X port_out(INT_CTL, ENABLE); /* re-enable 8259A controller */
X }
X}
X
X
X/*===========================================================================*
X * rs_flush *
X *===========================================================================*/
XPUBLIC rs_flush()
X{
X/* Flush the tty_driver_buf by sending a message to TTY. This procedure can
X * be triggered locally, when a character arrives, or by the clock task.
X */
X
X /* Build and send the interrupt message */
X flush_flag = 0;
X if (tty_driver_buf[0] == 0) return; /* nothing to flush */
X rs232_rd_mess.m_type = TTY_CHAR_INT;
X rs232_rd_mess.ADDRESS = tty_driver_buf;
X interrupt(TTY, &rs232_rd_mess); /* send a message to the tty task */
X}
X
X
X/*===========================================================================*
X * rs_write_int *
X *===========================================================================*/
XPRIVATE rs_write_int(line)
Xint line;
X{
X/* An output ready interrupt has occurred, or a write has been done to an idle
X * line. In both cases, start the output.
X */
X
X char byte;
X int val;
X struct tty_struct *tp;
X struct rs_struct *rs;
X
X if (first_rs_write_int_seen == FALSE) {
X first_rs_write_int_seen = TRUE;
X port_out(INT_CTL, ENABLE); /* re-enable 8259A controller */
X return;
X }
X
X /* On the XT and clones, check for spurious write-completed interrupts. */
X rs = &rs_struct[line - NR_CONS];
X port_in(rs->rs_base + RS232_LINE_STATUS, &val);
X if ( (val & HOLDING_REG_EMPTY) == 0) {
X port_out(INT_CTL, ENABLE); /* re-enable 8259A controller */
X return;
X }
X
X /* If there are more characters in rs_buf, output the next one. */
X if (rs->rs_left > 0) {
X rs_feed(rs); /* output the next char in rs_buf */
X port_out(INT_CTL, ENABLE); /* re-enable 8259A controller */
X return;
X }
X
X /* The current rs_buf is finished. See if the complete user buf is done. */
X tp = &tty_struct[line];
X rs->rs_busy = FALSE;
X rs->rs_next = &rs->rs_buf[0];
X if (tp->tty_outleft > 0) {
X serial_out(tp); /* copy the next chunk to rs_buf */
X port_out(INT_CTL, ENABLE); /* re-enable 8259A controller */
X return;
X }
X
X /* The current output buffer is finished. Send a message to the tty task. */
X if (tp->tty_waiting == WAITING) {
X rs232_wt_mess.m_type = TTY_O_DONE; /* build the message */
X rs232_wt_mess.ADDRESS = tty_driver_buf; /* pro forma */
X rs232_wt_mess.TTY_LINE = line; /* which line is finished */
X tp->tty_waiting = COMPLETED; /* mark this line as done */
X output_done++; /* # of RS232 lines now completed */
X interrupt(TTY, &rs232_wt_mess); /* send the message to the tty task */
X } else {
X port_out(INT_CTL, ENABLE); /* re-enable 8259A controller */
X }
X}
X
X
X/*===========================================================================*
X * rs_feed *
X *===========================================================================*/
XPRIVATE rs_feed(rs)
Xstruct rs_struct *rs; /* which line */
X{
X/* If there is more output queued, output the next character. */
X
X char byte;
X
X if (rs->rs_left > 0) {
X byte = *rs->rs_next;
X port_out(rs->rs_base + RS232_TRANSMIT_HOLDING, (int) byte);
X rs->rs_next++;
X rs->rs_left--; /* one char done */
X }
X}
X
X
X/*===========================================================================*
X * start_rs232 *
X *===========================================================================*/
XPRIVATE start_rs232(tp)
Xstruct tty_struct *tp; /* which tty */
X{
X int old_state;
X
X old_state = lock();
X serial_out(tp);
X restore(old_state);
X}
X
X
X/*===========================================================================*
X * serial_out *
X *===========================================================================*/
XPRIVATE serial_out(tp)
Xregister struct tty_struct *tp; /* tells which terminal is to be used */
X{
X/* Copy as much data as possible to the output queue, then start I/O if
X * necessary.
X */
X int bytes, line;
X char c, *limit;
X unsigned short segment, offset, offset1;
X register struct rs_struct *rs;
X extern char get_byte();
X
X if (tp->tty_inhibited != RUNNING) return;
X
X line = tp - &tty_struct[0]; /* line is index into tty_struct */
X rs = &rs_struct[line - NR_CONS]; /* 0 to NR_CONS - 1 are consoles */
X
X /* Copy bytes from user space to rs_buf. */
X limit = &rs->rs_buf[RS_BUF_SIZE - SPARE];
X segment = (tp->tty_phys >> 4) & WORD_MASK;
X offset = tp->tty_phys & OFF_MASK;
X offset1 = offset;
X
X /* While there is still data to output and there is still room in buf, copy*/
X while (tp->tty_outleft > 0 && rs->rs_next + rs->rs_left < limit) {
X c = get_byte(segment, offset); /* fetch 1 byte */
X offset++;
X tp->tty_outleft--;
X if (c < ' ') {
X rs_expand(tp, rs, c); /* insert the char in rs_buf */
X } else {
X *(rs->rs_next + rs->rs_left) = c; /* avoid proc call */
X rs->rs_left++;
X tp->tty_column++;
X }
X }
X
X bytes = offset - offset1; /* does not include '\r' or tab exp */
X tp->tty_cum += bytes; /* update cumulative total */
X tp->tty_phys += bytes; /* next time, take different bytes */
X
X if (!rs->rs_busy) { /* is the line idle? */
X rs->rs_busy = TRUE; /* if so, mark it as busy */
X rs_feed(rs); /* and start it going */
X }
X}
X
X
X/*===========================================================================*
X * rs_out_char *
X *===========================================================================*/
XPRIVATE rs_out_char(tp, c)
Xregister struct tty_struct *tp; /* pointer to tty struct */
Xchar c; /* character to be output */
X{
X/* Output a character on an RS232 line. */
X
X int line, old_state;
X register struct rs_struct *rs;
X
X /* See if there is room to store a character, and if so, do it. */
X old_state = lock();
X line = tp - tty_struct;
X rs = &rs_struct[line - NR_CONS];
X if (rs->rs_next + rs->rs_left == &rs->rs_buf[RS_BUF_SIZE]) return; /*full */
X rs_expand(tp, rs, c);
X
X if (!rs->rs_busy) { /* if terminal line is idle, start it */
X rs->rs_busy = TRUE;
X rs_feed(rs);
X }
X restore(old_state);
X}
X
X
X/*===========================================================================*
X * rs_expand *
X *===========================================================================*/
XPRIVATE rs_expand(tp, rs, c)
Xregister struct tty_struct *tp; /* pointer to tty struct */
Xregister struct rs_struct *rs; /* pointer to rs struct */
Xchar c; /* character to be output */
X{
X/* Some characters output to RS-232 lines need special processing, such as
X * tab expansion and LF to CR+CF mapping. These things are done here.
X */
X
X int mode, count, count1;
X char *deposit; /* where to deposit the next character */
X
X mode = tp->tty_mode;
X deposit = rs->rs_next + rs->rs_left;
X
X switch(c) {
X case '\b':
X tp->tty_column -= 2; /* it is incremented later */
X break;
X
X case '\r':
X tp->tty_column = -1; /* it is incremented below */
X break;
X
X case '\n':
X /* Check to see if LF has to be mapped to CR + LF. */
X if (mode & CRMOD) {
X *deposit++ = '\r';
X rs->rs_left++;
X tp->tty_column = -1;
X }
X break;
X
X case '\t':
X count = 8 - (tp->tty_column % 8); /* # spaces */
X count1 = count;
X if ((mode & XTABS) == XTABS) {
X /* Tabs must be expanded. */
X while (count1--) *deposit++ = ' ';
X rs->rs_left += count;
X tp->tty_column += count;
X return;
X } else {
X /* Tabs are sent to the terminal hardware. */
X tp->tty_column += count - 1;
X }
X }
X
X /* Output character and update counters. */
X *deposit = c; /* copy character to rs_buf */
X rs->rs_left++; /* there is one more character to print */
X tp->tty_column++; /* update column */
X}
X
X
X/*===========================================================================*
X * tty_o_done *
X *===========================================================================*/
XPRIVATE int tty_o_done(tp)
Xregister struct tty_struct *tp; /* pointer to tty_struct */
X{
X/* A write request on an RS232 line has completed. Send FS a message. */
X
X int replyee, caller, old_state;
X struct tty_struct *tp;
X
X /* See if any of the RS232 lines are complete. Send at most one message. */
X old_state = lock();
X for (tp = &tty_struct[NR_CONS]; tp < &tty_struct[NR_CONS+NR_RS_LINES]; tp++){
X if (tp->tty_waiting == COMPLETED) {
X replyee = (int) tp->tty_otcaller;
X caller = (int) tp->tty_outproc;
X tty_reply(REVIVE, replyee, caller, tp->tty_cum, 0L, 0L);
X tp->tty_waiting = NOT_WAITING;
X output_done--;
X restore(old_state);
X return(1);
X }
X }
X restore(old_state);
X return(0);
X}
X
X/*===========================================================================*
X * rs_sig *
X *===========================================================================*/
XPRIVATE rs_sig(tp)
Xstruct tty_struct *tp;
X{
X/* Called when a DEL character is typed. It resets the output. */
X
X int line;
X struct rs_struct *rs;
X
X line = tp - tty_struct;
X rs = &rs_struct[line - NR_CONS];
X rs->rs_left = 0;
X rs->rs_busy = 0;
X rs->rs_next = &rs->rs_buf[0];
X}
X
X
X/*===========================================================================*
X * init_rs232 *
X *===========================================================================*/
XPRIVATE init_rs232()
X{
X register struct tty_struct *tp;
X register struct rs_struct *rs;
X int line;
X
X for (tp = &tty_struct[NR_CONS]; tp < &tty_struct[NR_CONS+NR_RS_LINES]; tp++){
X tp->tty_inhead = tp->tty_inqueue;
X tp->tty_intail = tp->tty_inqueue;
X tp->tty_mode = CRMOD | XTABS | ECHO;
X tp->tty_devstart = start_rs232;
X tp->tty_erase = ERASE_CHAR;
X tp->tty_kill = KILL_CHAR;
X tp->tty_intr = INTR_CHAR;
X tp->tty_quit = QUIT_CHAR;
X tp->tty_xon = XON_CHAR;
X tp->tty_xoff = XOFF_CHAR;
X tp->tty_eof = EOT_CHAR;
X tp->tty_makebreak = ONE_INT; /* RS232 only interrupts once/char */
X }
X
X rs_struct[0].rs_base = PRIMARY;
X rs_struct[1].rs_base = SECONDARY;
X
X for (rs = &rs_struct[0]; rs < &rs_struct[NR_RS_LINES]; rs++) {
X line = rs - rs_struct + NR_CONS;
X rs->rs_next = & rs->rs_buf[0];
X rs->rs_left = 0;
X rs->rs_busy = FALSE;
X config_rs232(line, DEF_BAUD, DEF_BAUD, NONE, 1, 8); /* set params */
X port_out(rs->rs_base + RS232_MODEM_CONTROL, MODEM_CONTROLS);
X port_out(rs->rs_base + RS232_INTERRUPTS, RS232_INTERRUPT_CLASSES);
X }
X}
X
X
X/*===========================================================================*
X * set_uart *
X *===========================================================================*/
XPRIVATE set_uart(line, mode, speeds)
Xint line; /* which line number (>= NR_CONS) */
Xint mode; /* sgtty.h sg_mode word */
Xint speeds; /* low byte is input speed, next is output */
X{
X/* Set the UART parameters. */
X int in_baud, out_baud, parity, stop_bits, data_bits;
X
X in_baud = 100 * (speeds & BYTE);
X if (in_baud == 100) in_baud = 110;
X out_baud = 100 * ((speeds >> 8) & BYTE);
X if (out_baud == 100) out_baud = 110;
X parity = NONE;
X if (mode & ODDP) parity = ODD;
X if (mode & EVENP) parity = EVEN;
X stop_bits = (in_baud == 110 ? 2 : 1); /* not quite cricket */
X data_bits = 5 + ((mode >> DATA_LEN) & 03);
X config_rs232(line, in_baud, out_baud, parity, stop_bits, data_bits);
X}
X
X
X/*===========================================================================*
X * config_rs232 *
X *===========================================================================*/
XPRIVATE config_rs232(line, in_baud, out_baud, parity, stop_bits, data_bits)
Xint line; /* which tty */
Xint in_baud; /* input speed: 110, 300, 1200, etc. */
Xint out_baud; /* output speed: 110, 300, 1200, etc. */
Xint parity; /* EVEN, ODD, or NONE */
Xint stop_bits; /* 2 (110 baud) or 1 (other speeds) */
Xint data_bits; /* 5, 6, 7, or 8 */
X{
X/* Set various line control parameters for RS232 I/O.
X * If DataBits == 5 and StopBits == 2, UART will generate 1.5 stop bits
X * The 8250 can't handle split speed, but we have propagated both speeds
X * anyway for the benefit of future UART chips.
X */
X
X int line_controls = 0, base, freq;
X
X base = rs_struct[line - NR_CONS].rs_base;
X
X /* First tell line control register to address baud rate divisor */
X port_out(base + RS232_LINE_CONTROL, ADDRESS_DIVISOR);
X
X /* Now set the baud rate. */
X if (in_baud < 50) in_baud = DEF_BAUD; /* prevent divide overflow */
X if (out_baud < 50) out_baud = DEF_BAUD; /* prevent divide overflow */
X freq = (int) (UART_FREQ / in_baud); /* UART can't hack 2 speeds */
X port_out(base + RS232_RATE_DIVISOR, freq & BYTE);
X port_out(base + RS232_RATE_DIVISOR+1, (freq >> 8) & BYTE);
X tty_struct[line].tty_speed = ((out_baud/100) << 8) | (in_baud/100);
X
X /* Put parity_type bits in line_controls */
X if (parity != NONE) {
X line_controls |= PARITY_ON_OFF;
X line_controls |= (parity << PARITY_TYPE_SHIFT);
X }
X
X /* Put #stop_bits bits in line_controls */
X if (stop_bits == 1 || stop_bits == 2)
X line_controls |= (stop_bits - 1) << STOP_BITS_SHIFT;
X
X /* Put #data_bits bits in line_controls */
X if (data_bits >=5 && data_bits <= 8)
X line_controls |= (data_bits - 5);
X
X port_out(base + RS232_LINE_CONTROL, line_controls);
X}
X
X#endif
X
+ END-OF-FILE tty.c.part2
chmod 'u=rw,g=r,o=r' 'tty.c.part2'
set `wc -c 'tty.c.part2'`
count=$1
case $count in
33602) :;;
*) echo 'Bad character count in ''tty.c.part2' >&2
echo 'Count should be 33602' >&2
esac
exit 0