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