]> Zhao Yanbai Git Server - minix.git/commitdiff
TTY: seperate hardware dependent parts + add new serial driver
authorThomas Veerman <thomas@minix3.org>
Wed, 17 Oct 2012 14:07:53 +0000 (14:07 +0000)
committerThomas Veerman <thomas@minix3.org>
Tue, 30 Oct 2012 11:33:29 +0000 (11:33 +0000)
.Split TTY in order to support both x86 and ARM.
.Add support for the TI 16750 UARTs on OMAP35x.
.Various other improvements:
  .Kernel messages are printed using generic terminal write
   functions. That is, they are no longer directly displayed
   on the console.
  .The console can now be displayed on any terminal. This
   is configured by the "console={tty00,tty01,ttyc2,ttyc3,ttyc4}"
   boot variable -- basically any valid /dev/tty* terminal.
  .Cutify kernel messages with colors. Configured by
   "kernelclr={1,2,3,4,5,6,7}" boot variable.

14 files changed:
common/include/termios.h
drivers/tty/Makefile
drivers/tty/arch/arm/Makefile.inc [new file with mode: 0644]
drivers/tty/arch/arm/console.c [new file with mode: 0644]
drivers/tty/arch/arm/keyboard.c [new file with mode: 0644]
drivers/tty/arch/arm/omap_serial.h [new file with mode: 0644]
drivers/tty/arch/arm/rs232.c [new file with mode: 0644]
drivers/tty/arch/i386/Makefile.inc [new file with mode: 0644]
drivers/tty/arch/i386/console.c [moved from drivers/tty/console.c with 94% similarity]
drivers/tty/arch/i386/keyboard.c [moved from drivers/tty/keyboard.c with 100% similarity]
drivers/tty/arch/i386/rs232.c [moved from drivers/tty/rs232.c with 98% similarity]
drivers/tty/pty.c
drivers/tty/tty.c
drivers/tty/tty.h

index 5818e31a98ab4f0a3ec6f3521e3eb426d81b7404..9ed08c918d084e77d686b4cf8cd5546b09f124e7 100644 (file)
@@ -145,6 +145,8 @@ int tcsetattr(int _filedes, int _opt_actions, const struct termios
 #define cfsetospeed(termios_p, speed)  ((termios_p)->c_ospeed = (speed), 0)
 #endif
 
+/* Here are the local extensions to the POSIX standard for Minix. */
+
 /* Extensions to the termios c_iflag bit map.  */
 #define IXANY          0x0800  /* allow any key to continue ouptut */
 #define SCANCODES      0x1000  /* send scancodes */
@@ -164,8 +166,16 @@ int tcsetattr(int _filedes, int _opt_actions, const struct termios
 #define VDISCARD          13    /* cc_c[VDISCARD] (^O) */
 
 /* Extensions to baud rate settings. */
+#ifdef _MINIX
 #define B57600         0x0100  /* 57600 baud */
 #define B115200                0x0200  /* 115200 baud */
+#define B230400                0x0400  /* 230400 baud */
+#define B460800                0x0800  /* 460800 baud */
+#define B921600                0x1000  /* 921600 baud */
+#define B1843200       0x2000  /* 1843200 baud */
+#define B3000000       0x4000  /* 3000000 baud */
+#define B3686400       0x8000  /* 3686400 baud */
+#endif /* _MINIX */
 
 /* These are the default settings used by the kernel and by 'stty sane' */
 
index 7d46a7358626d4ad4c00b5240309119143b0ce56..d609aad75e3e924a6a0ace83fee4908e9041d31b 100644 (file)
@@ -1,7 +1,10 @@
 # Makefile for terminal driver (TTY)
 
 PROG=  tty
-SRCS=  tty.c console.c keyboard.c pty.c rs232.c
+
+.include "arch/${MACHINE_ARCH}/Makefile.inc"
+
+SRCS +=        tty.c pty.c
 
 DPADD+=        ${LIBSYS} ${LIBTIMERS}
 LDADD+=        -lsys -ltimers
@@ -13,7 +16,7 @@ BINDIR?= /usr/sbin
 SUBDIR= keymaps
 
 # Needs kernel/const.h, etc
-CPPFLAGS+=     -I${NETBSDSRCDIR}
+CPPFLAGS+=     -I${.CURDIR}    -I${NETBSDSRCDIR}
 
 .include <minix.bootprog.mk>
 .include <bsd.subdir.mk>
diff --git a/drivers/tty/arch/arm/Makefile.inc b/drivers/tty/arch/arm/Makefile.inc
new file mode 100644 (file)
index 0000000..3ad697a
--- /dev/null
@@ -0,0 +1,7 @@
+# Makefile for arch-dependent TTY code
+.include <bsd.own.mk>
+
+HERE=${.CURDIR}/arch/${MACHINE_ARCH}
+.PATH:  ${HERE}
+
+SRCS +=        console.c keyboard.c rs232.c
diff --git a/drivers/tty/arch/arm/console.c b/drivers/tty/arch/arm/console.c
new file mode 100644 (file)
index 0000000..3c820bc
--- /dev/null
@@ -0,0 +1,26 @@
+/* Console unsupport for ARM. Just stubs. */
+#include <minix/ipc.h>
+#include <termios.h>
+#include "tty.h"
+
+void
+do_video(message *m)
+{
+}
+
+void
+scr_init(tty_t *tp)
+{
+}
+
+void
+cons_stop(void)
+{
+}
+
+int
+con_loadfont(message *m)
+{
+       return 0;
+}
+
diff --git a/drivers/tty/arch/arm/keyboard.c b/drivers/tty/arch/arm/keyboard.c
new file mode 100644 (file)
index 0000000..3c6c1e5
--- /dev/null
@@ -0,0 +1,51 @@
+/* Keyboard unsupport for ARM. Just stubs. */
+#include <minix/ipc.h>
+#include <termios.h>
+#include "tty.h"
+
+void
+kbd_interrupt(message *m)
+{
+}
+
+void
+do_fkey_ctl(message *m)
+{
+}
+
+void
+do_kb_inject(message *m)
+{
+}
+
+void
+do_kbd(message *m)
+{
+}
+
+void
+do_kbdaux(message *m)
+{
+}
+
+void
+kb_init_once(void)
+{
+}
+
+int
+kbd_status(message *m)
+{
+       return 0;
+}
+
+int
+kbd_loadmap(message *m)
+{
+       return 0;
+}
+
+void
+kb_init(tty_t *tp)
+{
+}
diff --git a/drivers/tty/arch/arm/omap_serial.h b/drivers/tty/arch/arm/omap_serial.h
new file mode 100644 (file)
index 0000000..ec96eb3
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef _OMAP_SERIAL_H
+#define _OMAP_SERIAL_H
+
+/* UART register map */
+#define OMAP3_UART1_BASE 0x4806A000 /* UART1 physical address */
+#define OMAP3_UART2_BASE 0x4806C000 /* UART2 physical address */
+#define OMAP3_UART3_BASE 0x49020000 /* UART3 physical address */
+
+/* UART registers */
+#define OMAP3_THR              0       /* Transmit holding register */
+#define OMAP3_RHR              0       /* Receive holding register */
+#define OMAP3_DLL              0       /* Divisor latches low */
+#define OMAP3_DLH              1       /* Divisor latches high */
+#define OMAP3_IER              1       /* Interrupt enable register */
+#define OMAP3_IIR              2       /* Interrupt identification register */
+#define OMAP3_EFR              2       /* Extended features register */
+#define OMAP3_FCR              2       /* FIFO control register */
+#define OMAP3_LCR              3       /* Line control register */
+#define OMAP3_MCR              4       /* Modem control register */
+#define OMAP3_LSR              5       /* Line status register */
+#define OMAP3_MSR              6       /* Modem status register */
+#define OMAP3_MDR1             0x08    /* Mode definition register 1 */
+#define OMAP3_MDR2             0x09    /* Mode definition register 2 */
+#define OMAP3_SCR              0x10    /* Supplementary control register */
+#define OMAP3_SSR              0x11    /* Supplementary status register */
+#define OMAP3_SYSC             0x15    /* System configuration register */
+#define OMAP3_SYSS             0x16    /* System status register */
+
+/* Enhanced Features Register bits */
+#define UART_EFR_ECB           0x10    /* Enhanced control bit */
+
+/* Interrupt Enable Register bits */
+#define UART_IER_MSI           0x08    /* Modem status interrupt */
+#define UART_IER_RLSI          0x04    /* Receiver line status interrupt */
+#define UART_IER_THRI          0x02    /* Transmitter holding register int. */ 
+#define UART_IER_RDI           0x01    /* Receiver data interrupt */
+
+/* FIFO control register */
+#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT       6
+#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK                (0x3 << 6)
+#define UART_FCR_ENABLE_FIFO   0x01    /* Enable the fifo */
+#define UART_FCR_CLR_RCVR      0x02    /* Clear the RCVR FIFO */
+#define UART_FCR_CLR_XMIT      0x04    /* Clear the XMIT FIFO */
+
+/* Interrupt Identification Register bits */
+#define UART_IIR_RDI           0x04    /* Data ready interrupt */
+#define UART_IIR_THRI          0x02    /* Transmitter holding register empty */
+#define UART_IIR_NO_INT                0x01    /* No interrupt is pending */
+
+/* Line Control Register bits */
+#define UART_LCR_DLAB          0x80    /* Divisor latch access bit */
+#define UART_LCR_SBC           0x40    /* Set break control */
+#define UART_LCR_EPAR          0x10    /* Even parity select */
+#define UART_LCR_PARITY                0x08    /* Enable parity */
+#define UART_LCR_STOP          0x04    /* Stop bits; 0=1 bit, 1=2 bits */
+#define UART_LCR_WLEN5         0x00    /* Wordlength 5 bits */
+#define UART_LCR_WLEN6         0x01    /* Wordlength 6 bits */
+#define UART_LCR_WLEN7         0x02    /* Wordlength 7 bits */
+#define UART_LCR_WLEN8         0x03    /* Wordlength 8 bits */
+
+#define UART_LCR_CONF_MODE_A   UART_LCR_DLAB   /* Configuration Mode A */
+#define UART_LCR_CONF_MODE_B   0xBF            /* Configuration Mode B */
+
+/* Line Status Register bits */
+#define UART_LSR_THRE          0x20    /* Transmit-hold-register empty */
+#define UART_LSR_BI            0x10    /* Break condition */
+#define UART_LSR_DR            0x01    /* Data ready */
+
+/* Modem Control Register bits */
+#define UART_MCR_TCRTLR                0x40    /* Access TCR/TLR */
+#define UART_MCR_OUT2          0x08    /* Out2 complement */
+#define UART_MCR_RTS           0x02    /* RTS complement */
+#define UART_MCR_DTR           0x01    /* DTR output low */
+
+/* Mode Definition Register 1 bits */
+#define OMAP_MDR1_DISABLE      0x07
+#define OMAP_MDR1_MODE13X      0x03    
+#define OMAP_MDR1_MODE16X      0x00
+
+/* Modem Status Register bits */
+#define UART_MSR_DCD           0x80    /* Data Carrier Detect */
+#define UART_MSR_CTS           0x10    /* Clear to Send */
+#define UART_MSR_DDCD          0x08    /* Delta DCD */
+
+/* Supplementary control Register bits */
+#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK      (1 << 7)
+
+/* System Control Register bits */
+#define UART_SYSC_SOFTRESET    0x02
+
+/* System Status Register bits */
+#define UART_SYSS_RESETDONE    0x01
+
+/* Line status register fields */
+#define OMAP3_LSR_TX_FIFO_E    (1 << 5) /* Transmit FIFO empty */
+#define OMAP3_LSR_RX_FIFO_E    (1 << 0) /* Receive FIFO empty */
+
+/* Supplementary status register fields */
+#define OMAP3_SSR_TX_FIFO_FULL (1 << 0) /* Transmit FIFO full */
+
+#define OMAP3_UART3_THR (OMAP3_UART3_BASE + OMAP3_THR)
+#define OMAP3_UART3_IIR (OMAP3_UART3_BASE + OMAP3_IIR)
+#define OMAP3_UART3_LSR (OMAP3_UART3_BASE + OMAP3_LSR)
+#define OMAP3_UART3_SSR (OMAP3_UART3_BASE + OMAP3_SSR)
+
+#endif /* _OMAP_SERIAL_H */
diff --git a/drivers/tty/arch/arm/rs232.c b/drivers/tty/arch/arm/rs232.c
new file mode 100644 (file)
index 0000000..3a3b256
--- /dev/null
@@ -0,0 +1,797 @@
+#include <minix/config.h>
+#include <minix/drivers.h>
+#include <minix/vm.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <signal.h>
+#include <termios.h>
+#include "omap_serial.h"
+#include "tty.h"
+
+#if NR_RS_LINES > 0
+
+#define UART_FREQ       48000000L      /* timer frequency */
+#if 0
+#define DFLT_BAUD      TSPEED_DEF              /* default baud rate */
+#else
+#define DFLT_BAUD      B115200         /* default baud rate */
+#endif
+
+
+#define RS_IBUFSIZE          1024      /* RS232 input buffer size */
+#define RS_OBUFSIZE          1024      /* RS232 output buffer size */
+
+/* Input buffer watermarks.
+ * The external device is asked to stop sending when the buffer
+ * exactly reaches high water, or when TTY requests it.  Sending restarts
+ * when the input buffer empties below the low watermark.
+ */
+#define RS_ILOWWATER   (1 * RS_IBUFSIZE / 4)
+#define RS_IHIGHWATER  (3 * RS_IBUFSIZE / 4)
+
+/* Output buffer low watermark.
+ * TTY is notified when the output buffer empties below the low watermark, so
+ * it may continue filling the buffer if doing a large write.
+ */
+#define RS_OLOWWATER   (1 * RS_OBUFSIZE / 4)
+
+/* Macros to handle flow control.
+ * Interrupts must be off when they are used.
+ * Time is critical - already the function call for outb() is annoying.
+ * If outb() can be done in-line, tests to avoid it can be dropped.
+ * istart() tells external device we are ready by raising RTS.
+ * istop() tells external device we are not ready by dropping RTS.
+ * DTR is kept high all the time (it probably should be raised by open and
+ * dropped by close of the device).
+ * OUT2 is also kept high all the time.
+ */
+#define istart(rs) \
+       (serial_out((rs), OMAP3_MCR, UART_MCR_OUT2|UART_MCR_RTS|UART_MCR_DTR),\
+               (rs)->idevready = TRUE)
+#define istop(rs) \
+       (serial_out((rs), OMAP3_MCR, UART_MCR_OUT2|UART_MCR_DTR), \
+               (rs)->idevready = FALSE)
+
+/* Macro to tell if device is ready.  The rs->cts field is set to UART_MSR_CTS
+ * if CLOCAL is in effect for a line without a CTS wire.
+ */
+#define devready(rs) ((serial_in(rs, OMAP3_MSR) | rs->cts) & UART_MSR_CTS)
+
+/* Macro to tell if transmitter is ready. */
+#define txready(rs) (serial_in(rs, OMAP3_LSR) & UART_LSR_THRE)
+
+/* RS232 device structure, one per device. */
+typedef struct rs232 {
+  tty_t *tty;                  /* associated TTY structure */
+
+  int icount;                  /* number of bytes in the input buffer */
+  char *ihead;                 /* next free spot in input buffer */
+  char *itail;                 /* first byte to give to TTY */
+  char idevready;              /* nonzero if we are ready to receive (RTS) */
+  char cts;                    /* normally 0, but MS_CTS if CLOCAL is set */
+
+  unsigned char ostate;                /* combination of flags: */
+#define ODONE          1       /* output completed (< output enable bits) */
+#define ORAW           2       /* raw mode for xoff disable (< enab. bits) */
+#define OWAKEUP        4       /* tty_wakeup() pending (asm code only) */
+#define ODEVREADY UART_MSR_CTS /* external device hardware ready (CTS) */
+#define OQUEUED     0x20       /* output buffer not empty */
+#define OSWREADY    0x40       /* external device software ready (no xoff) */
+#define ODEVHUP  UART_MSR_DCD  /* external device has dropped carrier */
+#define OSOFTBITS  (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)
+                               /* user-defined bits */
+#if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS
+                               /* a weak sanity check */
+#error                         /* bits are not unique */
+#endif
+  unsigned char oxoff;         /* char to stop output */
+  char inhibited;              /* output inhibited? (follows tty_inhibited) */
+  char drain;                  /* if set drain output and reconfigure line */
+  int ocount;                  /* number of bytes in the output buffer */
+  char *ohead;                 /* next free spot in output buffer */
+  char *otail;                 /* next char to output */
+
+  phys_bytes phys_base;                /* UART physical base address (I/O map) */
+  unsigned int reg_offset;     /* UART register offset */
+  unsigned int ier;            /* copy of ier register */
+  unsigned int scr;            /* copy of scr register */
+  unsigned int fcr;            /* copy of fcr register */
+  unsigned int dll;            /* copy of dll register */
+  unsigned int dlh;            /* copy of dlh register */
+  unsigned int uartclk;                /* UART clock rate */
+
+  unsigned char lstatus;       /* last line status */
+  unsigned framing_errors;     /* error counts (no reporting yet) */
+  unsigned overrun_errors;
+  unsigned parity_errors;
+  unsigned break_interrupts;
+
+  int irq;                     /* irq for this line */
+  int irq_hook_id;             /* interrupt hook */
+
+  char ibuf[RS_IBUFSIZE];      /* input buffer */
+  char obuf[RS_OBUFSIZE];      /* output buffer */
+} rs232_t;
+
+static rs232_t rs_lines[NR_RS_LINES];
+
+typedef struct uart_port {
+       phys_bytes base_addr;
+       int irq;
+} uart_port_t;
+
+/* OMAP3 UART base addresses. */
+static uart_port_t omap3[] = {
+  { OMAP3_UART1_BASE, 72},     /* UART1 */
+  { OMAP3_UART2_BASE, 73},     /* UART2 */
+  { OMAP3_UART3_BASE, 74},     /* UART3 */
+  { 0, 0 }
+};
+
+static int rs_write(tty_t *tp, int try);
+static void rs_echo(tty_t *tp, int c);
+static int rs_ioctl(tty_t *tp, int try);
+static void rs_config(rs232_t *rs);
+static int rs_read(tty_t *tp, int try);
+static int rs_icancel(tty_t *tp, int try);
+static int rs_ocancel(tty_t *tp, int try);
+static void rs_ostart(rs232_t *rs);
+static int rs_break(tty_t *tp, int try);
+static int rs_close(tty_t *tp, int try);
+static int rs_open(tty_t *tp, int try);
+static void rs232_handler(rs232_t *rs);
+static void rs_reset(rs232_t *rs);
+static unsigned int check_modem_status(rs232_t *rs);
+static int termios_baud_rate(struct termios *term);
+
+static inline unsigned int readw(vir_bytes addr);
+static inline unsigned int serial_in(rs232_t *rs, int offset);
+static inline void serial_out(rs232_t *rs, int offset, int val);
+static inline void writew(vir_bytes addr, int val);
+static void write_chars(rs232_t *rs);
+static void read_chars(rs232_t *rs, unsigned int status);
+
+static inline unsigned int
+readw(vir_bytes addr)
+{
+       return *((volatile unsigned int *) addr);
+}
+
+static inline void
+writew(vir_bytes addr, int val)
+{
+       *((volatile unsigned int *) addr) = val;
+}
+
+static inline unsigned int
+serial_in(rs232_t *rs, int offset)
+{
+       offset <<= rs->reg_offset;
+       return readw(rs->phys_base + offset);
+}
+
+static inline void
+serial_out(rs232_t *rs, int offset, int val)
+{
+       offset <<= rs->reg_offset;
+       writew(rs->phys_base + offset, val);
+}
+
+static void
+rs_reset(rs232_t *rs)
+{
+       u32_t syss;
+
+       serial_out(rs, OMAP3_SYSC, UART_SYSC_SOFTRESET);
+
+       /* Poll until done */
+       do {
+               syss = serial_in(rs, OMAP3_SYSS);
+       } while (!(syss & UART_SYSS_RESETDONE));
+}
+
+static int
+rs_write(register tty_t *tp, int try)
+{
+/* (*devwrite)() routine for RS232. */
+
+       rs232_t *rs = tp->tty_priv;
+       int r, count, ocount;
+
+       if (rs->inhibited != tp->tty_inhibited) {
+               /* Inhibition state has changed. */
+               rs->ostate |= OSWREADY;
+               if (tp->tty_inhibited) rs->ostate &= ~OSWREADY;
+               rs->inhibited = tp->tty_inhibited;
+       }
+
+       if (rs->drain) {
+               /* Wait for the line to drain then reconfigure and continue
+                * output. */
+               if (rs->ocount > 0) return 0;
+               rs->drain = FALSE;
+               rs_config(rs);
+       }
+       /* While there is something to do. */
+       for (;;) {
+               ocount = buflen(rs->obuf) - rs->ocount;
+               count = bufend(rs->obuf) - rs->ohead;
+               if (count > ocount) count = ocount;
+               if (count > tp->tty_outleft) count = tp->tty_outleft;
+               if (count == 0 || tp->tty_inhibited) {
+                       if (try) return 0;
+                       break;
+               }
+
+               if (try) return 1;
+
+               /* Copy from user space to the RS232 output buffer. */
+               if (tp->tty_outcaller == KERNEL) {
+                       /* We're trying to print on kernel's behalf */
+                       memcpy(rs->ohead,
+                               (void *) tp->tty_outgrant + tp->tty_outoffset,
+                               count);
+               } else {
+                       if ((r = sys_safecopyfrom(tp->tty_outcaller,
+                               tp->tty_outgrant, tp->tty_outoffset,
+                               (vir_bytes) rs->ohead, count)) != OK) {
+                               return 0;
+                       }
+               }
+
+               /* Perform output processing on the output buffer. */
+               out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count,
+                   &ocount);
+               if (count == 0) {
+                       break;
+               }
+
+               /* Assume echoing messed up by output. */
+               tp->tty_reprint = TRUE;
+
+               /* Bookkeeping. */
+               rs->ocount += ocount;
+               rs_ostart(rs);
+               if ((rs->ohead += ocount) >= bufend(rs->obuf))
+                       rs->ohead -= buflen(rs->obuf);
+               tp->tty_outoffset += count;
+               tp->tty_outcum += count;
+               if ((tp->tty_outleft -= count) == 0) {
+                       /* Output is finished, reply to the writer. */
+                       if(tp->tty_outrepcode == TTY_REVIVE) {
+                               notify(tp->tty_outcaller);
+                               tp->tty_outrevived = 1;
+                       } else {
+                               tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
+                                       tp->tty_outproc, tp->tty_outcum);
+                               tp->tty_outcum = 0;
+                       }
+               }
+
+       }
+       if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
+               /* Oops, the line has hung up. */
+               if(tp->tty_outrepcode == TTY_REVIVE) {
+                       notify(tp->tty_outcaller);
+                       tp->tty_outrevived = 1;
+               } else {
+                       tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
+                               tp->tty_outproc, EIO);
+                       tp->tty_outleft = tp->tty_outcum = 0;
+               }
+       }
+
+       return 1;
+}
+
+static void
+rs_echo(tty_t *tp, int character)
+{
+/* Echo one character.  (Like rs_write, but only one character, optionally.) */
+
+       rs232_t *rs = tp->tty_priv;
+       int count, ocount;
+
+       ocount = buflen(rs->obuf) - rs->ocount;
+       if (ocount == 0) return;                /* output buffer full */
+       count = 1;
+       *rs->ohead = character;                 /* add one character */
+
+       out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
+       if (count == 0) return;
+
+       rs->ocount += ocount;
+       rs_ostart(rs);
+       if ((rs->ohead += ocount) >= bufend(rs->obuf))
+               rs->ohead -= buflen(rs->obuf);
+}
+
+static int
+rs_ioctl(tty_t *tp, int UNUSED(dummy))
+{
+/* Reconfigure the line as soon as the output has drained. */
+       rs232_t *rs = tp->tty_priv;
+
+       rs->drain = TRUE;
+       return 0;       /* dummy */
+}
+
+static unsigned int
+omap_get_divisor(rs232_t *rs, unsigned int baud)
+{
+/* Calculate divisor value. The 16750 has two oversampling modes to reach
+ * high baud rates with little error rate (see table 17-1 in OMAP TRM).
+ * Baud rates 460800, 921600, 1843200, and 3686400 use 13x oversampling,
+ * the other rates 16x. The baud rate is calculated as follows:
+ * baud rate = (functional clock / oversampling) / divisor.
+ */
+
+       unsigned int oversampling;
+       assert(baud != 0);
+
+       switch(baud) {
+       case B460800:   /* Fall through */
+       case B921600:   /* Fall through */
+       case B1843200:  /* Fall through */
+       case B3686400:  oversampling = 13; break;
+       default:        oversampling = 16;
+       }
+
+       return (rs->uartclk / oversampling) / baud;
+}
+
+static int
+termios_baud_rate(struct termios *term)
+{
+       int baud;
+       switch(term->c_ospeed) {
+       case B0: term->c_ospeed = DFLT_BAUD; baud = termios_baud_rate(term);
+       case B300: baud = 300; break;
+       case B600: baud = 600; break;
+       case B1200: baud = 1200; break;
+       case B2400: baud = 2400; break;
+       case B4800: baud = 4800; break;
+       case B9600: baud = 9600; break;
+       case B38400: baud = 38400; break;
+       case B57600: baud = 57600; break;
+       case B115200: baud = 115200; break;
+       default: term->c_ospeed = DFLT_BAUD; baud = termios_baud_rate(term);
+       }
+
+       return baud;
+}
+static void rs_config(rs232_t *rs)
+{
+/* Set various line control parameters for RS232 I/O.  */
+       tty_t *tp = rs->tty;
+       unsigned int divisor, efr, lcr, mcr, baud;
+
+       /* Fifo and DMA settings */
+       /* See OMAP35x TRM 17.5.1.1.2 */
+       lcr = serial_in(rs, OMAP3_LCR);                         /* 1a */
+       serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B);        /* 1b */
+       efr = serial_in(rs, OMAP3_EFR);                         /* 2a */
+       serial_out(rs, OMAP3_EFR, efr | UART_EFR_ECB);          /* 2b */
+       serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_A);        /* 3  */
+       mcr = serial_in(rs, OMAP3_MCR);                         /* 4a */
+       serial_out(rs, OMAP3_MCR, mcr | UART_MCR_TCRTLR);       /* 4b */
+       /* Set up FIFO for 1 byte */
+       rs->fcr = 0;
+       rs->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK;
+       rs->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT);
+       serial_out(rs, OMAP3_FCR, rs->fcr);                     /* 5  */
+       serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B);        /* 6  */
+       /* DMA triggers, not supported by this driver */        /* 7  */
+       rs->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;
+       serial_out(rs, OMAP3_SCR, rs->scr);                     /* 8  */
+       serial_out(rs, OMAP3_EFR, efr);                         /* 9  */
+       serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_A);        /* 10 */
+       serial_out(rs, OMAP3_MCR, mcr);                         /* 11 */
+       serial_out(rs, OMAP3_LCR, lcr);                         /* 12 */
+       
+       /* RS232 needs to know the xoff character, and if CTS works. */
+       rs->oxoff = tp->tty_termios.c_cc[VSTOP];
+       rs->cts = (tp->tty_termios.c_cflag & CLOCAL) ? UART_MSR_CTS : 0;
+       baud = termios_baud_rate(&tp->tty_termios);
+
+       /* Look up the 16750 rate divisor from the output speed. */
+       divisor = omap_get_divisor(rs, baud);
+       rs->dll = divisor & 0xFF;
+       rs->dlh = divisor >> 8;
+
+       /* Compute line control flag bits. */
+       lcr = 0;
+       if (tp->tty_termios.c_cflag & PARENB) {
+               lcr |= UART_LCR_PARITY;
+               if (!(tp->tty_termios.c_cflag & PARODD)) lcr |= UART_LCR_EPAR;
+       }
+       if (tp->tty_termios.c_cflag & CSTOPB) lcr |= UART_LCR_STOP;
+       switch(tp->tty_termios.c_cflag & CSIZE) {
+       case CS5:
+               lcr |= UART_LCR_WLEN5;
+               break;
+       case CS6:
+               lcr |= UART_LCR_WLEN6;
+               break;
+       case CS7:
+               lcr |= UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               lcr |= UART_LCR_WLEN8;
+               break;
+       }
+
+       /* Lock out interrupts while setting the speed. The receiver register
+        * is going to be hidden by the div_low register, but the input
+        * interrupt handler relies on reading it to clear the interrupt and
+        * avoid looping forever.
+        */
+
+       if (sys_irqdisable(&rs->irq_hook_id) != OK)
+               panic("unable to disable interrupts");
+
+       /* Select the baud rate divisor registers and change the rate. */
+       /* See OMAP35x TRM 17.5.1.1.3 */
+       serial_out(rs, OMAP3_MDR1, OMAP_MDR1_DISABLE);          /* 1  */
+       serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B);        /* 2  */
+       efr = serial_in(rs, OMAP3_EFR);                         /* 3a */
+       serial_out(rs, OMAP3_EFR, efr | UART_EFR_ECB);          /* 3b */
+       serial_out(rs, OMAP3_LCR, 0);                           /* 4  */
+       serial_out(rs, OMAP3_IER, 0);                           /* 5  */
+       serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B);        /* 6  */
+       serial_out(rs, OMAP3_DLL, rs->dll);                     /* 7  */
+       serial_out(rs, OMAP3_DLH, rs->dlh);                     /* 7  */
+       serial_out(rs, OMAP3_LCR, 0);                           /* 8  */
+       serial_out(rs, OMAP3_IER, rs->ier);                     /* 9  */
+       serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B);        /* 10 */
+       serial_out(rs, OMAP3_EFR, efr);                         /* 11 */
+       serial_out(rs, OMAP3_LCR, lcr);                         /* 12 */
+       if (baud > 230400 && baud != 3000000)
+               serial_out(rs, OMAP3_MDR1, OMAP_MDR1_MODE13X);  /* 13 */
+       else
+               serial_out(rs, OMAP3_MDR1, OMAP_MDR1_MODE16X);
+       
+       rs->ostate = devready(rs) | ORAW | OSWREADY;    /* reads MSR */
+       if ((tp->tty_termios.c_lflag & IXON) && rs->oxoff != _POSIX_VDISABLE)
+               rs->ostate &= ~ORAW;
+       (void) serial_in(rs, OMAP3_IIR);
+       if (sys_irqenable(&rs->irq_hook_id) != OK)
+               panic("unable to enable interrupts");
+}
+
+void
+rs_init(tty_t *tp)
+{
+/* Initialize RS232 for one line. */
+       register rs232_t *rs;
+       int line;
+       uart_port_t this_omap3;
+       char l[10];
+       struct minix_mem_range mr;
+
+       /* Associate RS232 and TTY structures. */
+       line = tp - &tty_table[NR_CONS];
+
+       /* See if kernel debugging is enabled; if so, don't initialize this
+        * serial line, making tty not look at the irq and returning ENXIO
+        * for all requests on it from userland. (The kernel will use it.)
+        */
+       if(env_get_param(SERVARNAME, l, sizeof(l)-1) == OK && atoi(l) == line){
+               printf("TTY: rs232 line %d not initialized (used by kernel)\n",
+                       line);
+               return;
+       }
+
+       rs = tp->tty_priv = &rs_lines[line];
+       rs->tty = tp;
+
+       /* Set up input queue. */
+       rs->ihead = rs->itail = rs->ibuf;
+
+       this_omap3 = omap3[line];
+       if (this_omap3.base_addr == 0) return;
+
+       /* Configure memory access */
+       mr.mr_base = rs->phys_base;
+       mr.mr_limit = rs->phys_base + 0x100;
+       if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
+               panic("Unable to request access to UART memory");
+       }
+       rs->phys_base = (vir_bytes) vm_map_phys(SELF,
+                                       (void *) this_omap3.base_addr, 0x100);
+       
+       if (rs->phys_base ==  (vir_bytes) MAP_FAILED) {
+               panic("Unable to request access to UART memory");
+       }
+       rs->reg_offset = 2;
+
+       rs->uartclk = UART_FREQ;
+       rs->ohead = rs->otail = rs->obuf;
+
+       /* Override system default baud rate. We do this because u-boot
+        * configures the UART for a baud rate of 115200 b/s and the kernel
+        * directly sends data over serial out upon boot up. If we then
+        * suddenly change the settings, the output will be garbled during
+        * booting.
+        */
+       tp->tty_termios.c_ospeed = DFLT_BAUD;
+
+       /* Configure IRQ */
+       rs->irq = this_omap3.irq;
+       rs->irq_hook_id = 1 << line;    /* call back with irq line number */
+       if (sys_irqsetpolicy(rs->irq, 0, &rs->irq_hook_id) != OK) {
+               printf("RS232: Couldn't obtain hook for irq %d\n", rs->irq);
+       } else {
+               if (sys_irqenable(&rs->irq_hook_id) != OK)  {
+                       printf("RS232: Couldn't enable irq %d (hooked)\n",
+                               rs->irq);
+               }
+       }
+       rs_irq_set |= (1 << (rs->irq_hook_id + 1));
+
+       /* Enable interrupts */
+       rs_reset(rs);
+       rs->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_MSI;
+       rs_config(rs);
+
+       /* Fill in TTY function hooks. */
+       tp->tty_devread = rs_read;
+       tp->tty_devwrite = rs_write;
+       tp->tty_echo = rs_echo;
+       tp->tty_icancel = rs_icancel;
+       tp->tty_ocancel = rs_ocancel;
+       tp->tty_ioctl = rs_ioctl;
+       tp->tty_break = rs_break;
+       tp->tty_open = rs_open;
+       tp->tty_close = rs_close;
+
+       /* Tell external device we are ready. */
+       istart(rs);
+}
+
+void
+rs_interrupt(message *m)
+{
+       unsigned long irq_set;
+       int line;
+       rs232_t *rs;
+
+       irq_set = m->NOTIFY_ARG;
+       for (line = 0, rs = rs_lines; line < NR_RS_LINES; line++, rs++) {
+               if (irq_set & (1 << (rs->irq_hook_id+1))) {
+                       rs232_handler(rs);
+                       if (sys_irqenable(&rs->irq_hook_id) != OK)
+                               panic("unable to enable interrupts");
+               }
+       }
+}
+
+static int
+rs_icancel(tty_t *tp, int UNUSED(dummy))
+{
+/* Cancel waiting input. */
+       rs232_t *rs = tp->tty_priv;
+
+       rs->icount = 0;
+       rs->itail = rs->ihead;
+       istart(rs);
+       return 0;       /* dummy */
+}
+
+static int
+rs_ocancel(tty_t *tp, int UNUSED(dummy))
+{
+/* Cancel pending output. */
+       rs232_t *rs = tp->tty_priv;
+
+       rs->ostate &= ~(ODONE | OQUEUED);
+       rs->ocount = 0;
+       rs->otail = rs->ohead;
+
+       return 0;       /* dummy */
+}
+
+static int
+rs_read(tty_t *tp, int try)
+{
+/* Process characters from the circular input buffer. */
+
+       rs232_t *rs = tp->tty_priv;
+       int icount, count, ostate;
+
+       if (!(tp->tty_termios.c_cflag & CLOCAL)) {
+               if (try) return 1;
+
+               /* Send a SIGHUP if hangup detected. */
+               ostate = rs->ostate;
+               rs->ostate &= ~ODEVHUP;         /* save ostate, clear DEVHUP */
+               if (ostate & ODEVHUP) {
+                       sigchar(tp, SIGHUP, 1);
+                       tp->tty_termios.c_ospeed = B0;/* Disable further I/O.*/
+                       return 0;
+               }
+       }
+
+       if (try) {
+               return(rs->icount > 0);
+       }
+
+       while ((count = rs->icount) > 0) {
+               icount = bufend(rs->ibuf) - rs->itail;
+               if (count > icount) count = icount;
+
+               /* Perform input processing on (part of) the input buffer. */
+               if ((count = in_process(tp, rs->itail, count, -1)) == 0) break;
+               rs->icount -= count;
+               if (!rs->idevready && rs->icount < RS_ILOWWATER) istart(rs);
+               if ((rs->itail += count) == bufend(rs->ibuf))
+                       rs->itail = rs->ibuf;
+       }
+
+       return 0;
+}
+
+static void
+rs_ostart(rs232_t *rs)
+{
+/* Tell RS232 there is something waiting in the output buffer. */
+
+       rs->ostate |= OQUEUED;
+       if (txready(rs)) write_chars(rs);
+}
+
+static int
+rs_break(tty_t *tp, int UNUSED(dummy))
+{
+/* Generate a break condition by setting the BREAK bit for 0.4 sec. */
+       rs232_t *rs = tp->tty_priv;
+       unsigned int lsr;
+
+       lsr = serial_in(rs, OMAP3_LSR);
+       serial_out(rs, OMAP3_LSR, lsr | UART_LSR_BI);
+       /* XXX */
+       /* milli_delay(400); */                         /* ouch */
+       serial_out(rs, OMAP3_LSR, lsr);
+       return 0;       /* dummy */
+}
+
+static int
+rs_open(tty_t *tp, int UNUSED(dummy))
+{
+       /* Set the speed to 115200 by default */
+       tp->tty_termios.c_ospeed = DFLT_BAUD;
+       return 0;
+}
+
+static int
+rs_close(tty_t *tp, int UNUSED(dummy))
+{
+/* The line is closed; optionally hang up. */
+       rs232_t *rs = tp->tty_priv;
+
+       if (tp->tty_termios.c_cflag & HUPCL) {
+               serial_out(rs, OMAP3_MCR, UART_MCR_OUT2|UART_MCR_RTS);
+               if (rs->ier & UART_IER_THRI) {
+                       rs->ier &= ~UART_IER_THRI;
+                       serial_out(rs, OMAP3_IER, rs->ier);
+               }
+       }
+       return 0;       /* dummy */
+}
+
+/* Low level (interrupt) routines. */
+
+static void
+rs232_handler(struct rs232 *rs)
+{
+/* Handle interrupt of a UART port */
+       unsigned int iir, lsr;
+
+       iir = serial_in(rs, OMAP3_IIR);
+       if (iir & UART_IIR_NO_INT)      /* No interrupt */
+               return;
+
+       lsr = serial_in(rs, OMAP3_LSR);
+       if (iir & UART_IIR_RDI) {       /* Data ready interrupt */
+               if (lsr & UART_LSR_DR)  {
+                       read_chars(rs, lsr);
+               }
+       }
+       check_modem_status(rs);
+       if (iir & UART_IIR_THRI) {
+               if (lsr & UART_LSR_THRE) {
+                       /* Ready to send and space available */
+                       write_chars(rs);
+               }
+       }
+}
+
+static void
+read_chars(rs232_t *rs, unsigned int status)
+{
+       unsigned char c;
+       unsigned int lsr;
+
+       lsr = status;
+
+       if (lsr & UART_LSR_DR) {
+               c = serial_in(rs, OMAP3_RHR);
+               if (!(rs->ostate & ORAW)) {
+                       if (c == rs->oxoff) {
+                               rs->ostate &= ~OSWREADY;
+                       } else if (!(rs->ostate & OSWREADY)) {
+                               rs->ostate = OSWREADY;
+                       }
+               }
+
+               if (rs->icount == buflen(rs->ibuf)) {
+                       printf("%s:%d buffer full, discarding byte\n",
+                               __FUNCTION__, __LINE__);
+                       return;
+               }
+
+               if (++rs->icount == RS_IHIGHWATER && rs->idevready) istop(rs);
+               *rs->ihead = c;
+               if (++rs->ihead == bufend(rs->ibuf)) rs->ihead = rs->ibuf;
+               if (rs->icount == 1) {
+                       rs->tty->tty_events = 1;
+               }
+       }
+}
+
+static void
+write_chars(rs232_t *rs)
+{
+/* If there is output to do and everything is ready, do it (local device is
+ * known ready).
+ * Notify TTY when the buffer goes empty.
+ */
+
+       if (rs->ostate >= (ODEVREADY | OQUEUED | OSWREADY)) {
+               /* Bit test allows ORAW and requires the others. */
+               serial_out(rs, OMAP3_THR, *rs->otail);
+               if (++rs->otail == bufend(rs->obuf))
+                       rs->otail = rs->obuf;
+               if (--rs->ocount == 0) {
+                       /* Turn on ODONE flag, turn off OQUEUED */
+                       rs->ostate ^= (ODONE | OQUEUED); 
+                       rs->tty->tty_events = 1;
+                       if (rs->ier & UART_IER_THRI) {
+                               rs->ier &= ~UART_IER_THRI;
+                               serial_out(rs, OMAP3_IER, rs->ier);
+                       }
+               } else  {
+                       if (rs->icount == RS_OLOWWATER)
+                               rs->tty->tty_events = 1;
+                       if (!(rs->ier & UART_IER_THRI)) {
+                               rs->ier |= UART_IER_THRI;
+                               serial_out(rs, OMAP3_IER, rs->ier);
+                       }
+               }
+       }
+}
+
+static unsigned int
+check_modem_status(rs232_t *rs)
+{
+/* Check modem status */
+
+       unsigned int msr;
+
+       msr = serial_in(rs, OMAP3_MSR); /* Resets modem interrupt */
+       if ((msr & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD) {
+               rs->ostate |= ODEVHUP;
+               rs->tty->tty_events = 1;
+       }
+
+       if (!devready(rs))
+               rs->ostate &= ~ODEVREADY;
+       else
+               rs->ostate |= ODEVREADY;
+
+       return msr;
+}
+
+#endif /* NR_RS_LINES > 0 */
+
diff --git a/drivers/tty/arch/i386/Makefile.inc b/drivers/tty/arch/i386/Makefile.inc
new file mode 100644 (file)
index 0000000..3ad697a
--- /dev/null
@@ -0,0 +1,7 @@
+# Makefile for arch-dependent TTY code
+.include <bsd.own.mk>
+
+HERE=${.CURDIR}/arch/${MACHINE_ARCH}
+.PATH:  ${HERE}
+
+SRCS +=        console.c keyboard.c rs232.c
similarity index 94%
rename from drivers/tty/console.c
rename to drivers/tty/arch/i386/console.c
index 6ec7fb4ebf1c96efd0e674e7c50748c22a6b36f6..de50c67f4f5e5d4dfceb9d7297f307a9621de84c 100644 (file)
@@ -122,7 +122,6 @@ struct sequence {
 static int cons_write(struct tty *tp, int try);
 static void cons_echo(tty_t *tp, int c);
 static void out_char(console_t *cons, int c);
-static void cons_putk(int c);
 static void beep(void);
 static void do_escape(console_t *cons, int c);
 static void flush(console_t *cons);
@@ -172,9 +171,17 @@ int try;
    */
   do {
        if (count > sizeof(buf)) count = sizeof(buf);
-       if ((result = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant,
-               tp->tty_outoffset, (vir_bytes) buf, count)) != OK)
-               break;
+       if (tp->tty_outcaller == KERNEL) {
+               /* We're trying to print on kernel's behalf */
+               memcpy(buf, (void *) tp->tty_outgrant + tp->tty_outoffset,
+                       count);
+       } else {
+               if ((result = sys_safecopyfrom(tp->tty_outcaller,
+                               tp->tty_outgrant, tp->tty_outoffset,
+                               (vir_bytes) buf, count)) != OK) {
+                       break;
+               }
+       }
        tp->tty_outoffset += count;
        tbuf = buf;
 
@@ -1008,64 +1015,6 @@ tty_t *tp;
   cons_ioctl(tp, 0);
 }
 
-extern struct minix_kerninfo *_minix_kerninfo;
-
-/*===========================================================================*
- *                             do_new_kmess                                 *
- *===========================================================================*/
-void do_new_kmess()
-{
-/* Notification for a new kernel message. */
-  struct kmessages *kmess_ptr;         /* kmessages structure */
-  static int prev_next = 0;                    /* previous next seen */
-  int bytes;
-  int r;
-
-  assert(_minix_kerninfo);
-  kmess_ptr = _minix_kerninfo->kmessages;
-
-  /* Print only the new part. Determine how many new bytes there are with 
-   * help of the current and previous 'next' index. Note that the kernel
-   * buffer is circular. This works fine if less then _KMESS_BUF_SIZE bytes
-   * is new data; else we miss % _KMESS_BUF_SIZE here.  
-   * Check for size being positive, the buffer might as well be emptied!
-   */
-  if (kmess_ptr->km_size > 0) {
-      bytes = ((kmess_ptr->km_next + _KMESS_BUF_SIZE) - prev_next) % _KMESS_BUF_SIZE;
-      r=prev_next;                             /* start at previous old */ 
-      while (bytes > 0) {                      
-          cons_putk( kmess_ptr->km_buf[(r%_KMESS_BUF_SIZE)] );
-          bytes --;
-          r ++;
-      }
-      cons_putk(0);                    /* terminate to flush output */
-  }
-
-  /* Almost done, store 'next' so that we can determine what part of the
-   * kernel messages buffer to print next time a notification arrives.
-   */
-  prev_next = kmess_ptr->km_next;
-}
-
-/*===========================================================================*
- *                             cons_putk                                    *
- *===========================================================================*/
-static void cons_putk(c)
-int c;                         /* character to print */
-{
-/* This procedure is used to print a character on the console.
- */
-  if (c != 0) {
-       if (c == '\n') cons_putk('\r');
-       out_char(&cons_table[0], (int) c);
-#if 0
-       ser_putc(c);
-#endif
-  } else {
-       flush(&cons_table[0]);
-  }
-}
-
 /*===========================================================================*
  *                             toggle_scroll                                *
  *===========================================================================*/
similarity index 98%
rename from drivers/tty/rs232.c
rename to drivers/tty/arch/i386/rs232.c
index 4a58134391fbc9d29b29bc78549955de9b09a648..7525c2784de92a4dd067056d8e7d558606384044 100644 (file)
@@ -248,9 +248,14 @@ static int rs_write(register tty_t *tp, int try)
        if (try) return 1;
 
        /* Copy from user space to the RS232 output buffer. */
-       if ((r = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant,
-               tp->tty_outoffset, (vir_bytes) rs->ohead, count)) != OK)
-               printf("TTY: sys_safecopyfrom() failed: %d", r);
+       if (tp->tty_outcaller == KERNEL) {
+               /* We're trying to print on kernel's behalf */
+               memcpy(rs->ohead, (void *) tp->tty_outgrant + tp->tty_outoffset, count);
+       } else {
+               if ((r = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant,
+                       tp->tty_outoffset, (vir_bytes) rs->ohead, count)) != OK)
+                               printf("TTY: sys_safecopyfrom() failed: %d", r);
+       }
 
        /* Perform output processing on the output buffer. */
        out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
@@ -754,8 +759,6 @@ static void in_int(register rs232_t *rs)
        rs->tty->tty_events = 1;
        force_timeout();
   }
-  else
-       printf("in_int: icount = %d\n", rs->icount);
 }
 
 /*===========================================================================*
index 9d718214bff8c4e9d908952ca1fad7933d2109bc..72e4724eb66df92c8f65a5b5565c1a8254183bd8 100644 (file)
@@ -242,9 +242,16 @@ static int pty_write(tty_t *tp, int try)
                break;
 
        /* Copy from user space to the PTY output buffer. */
-       if ((s = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant,
-               tp->tty_outoffset, (vir_bytes) pp->ohead, count))!=OK) {
-               break;
+       if (tp->tty_outcaller == KERNEL) {
+               /* We're trying to print on kernel's behalf */
+               memcpy(pp->ohead, (void *) tp->tty_outgrant + tp->tty_outoffset,
+                       count);
+       } else {
+               if ((s = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant,
+                               tp->tty_outoffset, (vir_bytes) pp->ohead,
+                               count)) != OK) {
+                       break;
+               }
        }
 
        /* Perform output processing on the output buffer. */
index 206498f57d31f332ad6a86f0144354c56857caba..29d65a054a175220a361b37ea0d806df0c4875f7 100644 (file)
@@ -57,6 +57,7 @@
  *   Jul 13, 2004   support for function key observers  (Jorrit N. Herder)  
  */
 
+#include <assert.h>
 #include <minix/drivers.h>
 #include <minix/driver.h>
 #include <termios.h>
@@ -80,7 +81,7 @@ unsigned long rs_irq_set = 0;
 
 /* Macros for magic tty types. */
 #define isconsole(tp)  ((tp) < tty_addr(NR_CONS))
-#define ispty(tp)      ((tp) >= tty_addr(NR_CONS+NR_RS_LINES))
+#define ispty(tp)      ((tp) != NULL && (tp)->tty_minor >= TTYPX_MINOR)
 
 /* Macros for magic tty structure pointers. */
 #define FIRST_TTY      tty_addr(0)
@@ -120,6 +121,12 @@ static void dev_ioctl(tty_t *tp);
 static void setattr(tty_t *tp);
 static void tty_icancel(tty_t *tp);
 static void tty_init(void);
+static void do_new_kmess(void);
+static tty_t * line2tty(int line);
+static void set_console_line(char term[CONS_ARG]);
+static void set_kernel_color(char color[CONS_ARG]);
+static void set_color(tty_t *tp, int color);
+static void reset_color(tty_t *tp);
 
 /* Default attributes. */
 static struct termios termios_defaults = {
@@ -137,12 +144,16 @@ tty_t tty_table[NR_CONS+NR_RS_LINES+NR_PTYS];
 int ccurrent;                  /* currently active console */
 struct machine machine;                /* kernel environment variables */
 u32_t system_hz;
+u32_t consoleline = CONS_MINOR;
+u32_t kernel_msg_color = 0;
 
 /* SEF functions and variables. */
 static void sef_local_startup(void);
 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
 static void sef_cb_signal_handler(int signo);
 
+extern struct minix_kerninfo *_minix_kerninfo;
+
 /*===========================================================================*
  *                             tty_task                                     *
  *===========================================================================*/
@@ -158,7 +169,6 @@ int main(void)
 
   /* SEF local startup. */
   sef_local_startup();
-
   while (TRUE) {
        /* Check for and handle any events on any of the ttys. */
        for (tp = FIRST_TTY; tp < END_TTY; tp++) {
@@ -229,6 +239,14 @@ int main(void)
                continue;
        }
        line = tty_mess.TTY_LINE;
+       if (line == CONS_MINOR || line == LOG_MINOR) {
+               /* /dev/log output goes to /dev/console */
+               if (consoleline != CONS_MINOR) {
+                       /* Console output must redirected */
+                       line = consoleline;
+                       tty_mess.TTY_LINE = line;
+               }
+       }
        if (line == KBD_MINOR) {
                do_kbd(&tty_mess);
                continue;
@@ -238,30 +256,26 @@ int main(void)
        } else if (line == VIDEO_MINOR) {
                do_video(&tty_mess);
                continue;
-       } else if ((line - CONS_MINOR) < NR_CONS) {
-               tp = tty_addr(line - CONS_MINOR);
-       } else if (line == LOG_MINOR) {
-               tp = tty_addr(0);
-       } else if ((line - RS232_MINOR) < NR_RS_LINES) {
-               tp = tty_addr(line - RS232_MINOR + NR_CONS);
-       } else if ((line - TTYPX_MINOR) < NR_PTYS) {
-               tp = tty_addr(line - TTYPX_MINOR + NR_CONS + NR_RS_LINES);
-       } else if ((line - PTYPX_MINOR) < NR_PTYS) {
-               tp = tty_addr(line - PTYPX_MINOR + NR_CONS + NR_RS_LINES);
-               if (tty_mess.m_type != DEV_IOCTL_S) {
+       } else {
+               tp = line2tty(line);
+
+               /* Terminals and pseudo terminals belong together. We can only
+                * make a distinction between the two based on position in the
+                * tty_table and not on minor number (i.e., use ispty macro).
+                * Hence this special case.
+                */
+               if (line - PTYPX_MINOR < NR_PTYS &&
+                                               tty_mess.m_type != DEV_IOCTL_S){
                        do_pty(tp, &tty_mess);
                        continue;
                }
-       } else {
-               tp = NULL;
        }
 
        /* If the device doesn't exist or is not configured return ENXIO. */
        if (tp == NULL || ! tty_active(tp)) {
-               if (tty_mess.m_source != LOG_PROC_NR)
-               {
+               if (tty_mess.m_source != LOG_PROC_NR) {
                        tty_reply(TASK_REPLY, tty_mess.m_source,
-                                               tty_mess.USER_ENDPT, ENXIO);
+                                 tty_mess.USER_ENDPT, ENXIO);
                }
                continue;
        }
@@ -286,6 +300,61 @@ int main(void)
   return 0;
 }
 
+static void
+set_color(tty_t *tp, int color)
+{
+       message msg;
+       char buf[8];
+
+       buf[0] = '\033';
+       snprintf(&buf[1], sizeof(buf) - 1, "[1;%dm", color);
+       msg.m_source = KERNEL;
+       msg.IO_GRANT = buf;
+       msg.COUNT = sizeof(buf);
+       do_write(tp, &msg);
+}
+
+static void
+reset_color(tty_t *tp)
+{
+       message msg;
+       char buf[8];
+
+#define SGR_COLOR_RESET        39
+       buf[0] = '\033';
+       snprintf(&buf[1], sizeof(buf) - 1, "[0;%dm", SGR_COLOR_RESET);
+       msg.m_source = KERNEL;
+       msg.IO_GRANT = buf;
+       msg.COUNT = sizeof(buf);
+       do_write(tp, &msg);
+}
+
+static tty_t *
+line2tty(int line)
+{
+/* Convert a terminal line to tty_table pointer */
+
+       tty_t* tp;
+
+       if (line == KBD_MINOR || line == KBDAUX_MINOR || line == VIDEO_MINOR) {
+               return(NULL);
+       } else if ((line - CONS_MINOR) < NR_CONS) {
+               tp = tty_addr(line - CONS_MINOR);
+       } else if (line == LOG_MINOR) {
+               tp = tty_addr(consoleline);
+       } else if ((line - RS232_MINOR) < NR_RS_LINES) {
+               tp = tty_addr(line - RS232_MINOR + NR_CONS);
+       } else if ((line - TTYPX_MINOR) < NR_PTYS) {
+               tp = tty_addr(line - TTYPX_MINOR + NR_CONS + NR_RS_LINES);
+       } else if ((line - PTYPX_MINOR) < NR_PTYS) {
+               tp = tty_addr(line - PTYPX_MINOR + NR_CONS + NR_RS_LINES);
+       } else {
+               tp = NULL;
+       }
+
+       return(tp);
+}
+
 /*===========================================================================*
  *                            sef_local_startup                             *
  *===========================================================================*/
@@ -311,12 +380,21 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
 {
 /* Initialize the tty driver. */
   int r;
+  char val[CONS_ARG];
 
   /* Get kernel environment (protected_mode, pc_at and ega are needed). */ 
   if (OK != (r=sys_getmachine(&machine))) {
     panic("Couldn't obtain kernel environment: %d", r);
   }
 
+  if (env_get_param("console", val, sizeof(val)) == OK) {
+       set_console_line(val);
+  }
+
+  if ((r = env_get_param("kernelclr", val, sizeof(val))) == OK) {
+       set_kernel_color(val);
+  }
+
   /* Initialize the TTY driver. */
   tty_init();
 
@@ -326,6 +404,115 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
   return(OK);
 }
 
+static void
+set_console_line(char term[CONS_ARG])
+{
+/* Parse 'term' and redirect console output there. */
+       int i;
+
+       /* Console */
+       if (!strncmp(term, "console", CONS_ARG - 1)) {
+               consoleline = CONS_MINOR+0;
+       }
+
+       /* The other console terminals */
+       for (i = 1; i < NR_CONS; i++) {
+               char cons[6];
+               strlcpy(cons, "ttyc0", sizeof(cons));
+               cons[4] += i;
+               if (!strncmp(term, cons,
+                   CONS_ARG < sizeof(cons) ? CONS_ARG-1 : sizeof(cons) - 1))
+                       consoleline = CONS_MINOR + i;
+       }
+
+       /* Serial lines */
+       for (i = 0; i < NR_RS_LINES; i++) {
+               char sercons[6];
+               strlcpy(sercons, "tty00", sizeof(sercons));
+               sercons[4] += i;
+               if (!strncmp(term, sercons,
+                   CONS_ARG < sizeof(sercons) ? CONS_ARG-1:sizeof(sercons)-1))
+                       consoleline = RS232_MINOR + i;
+       }
+}
+
+static void
+set_kernel_color(char color[CONS_ARG])
+{
+       int def_color;
+
+#define SGR_COLOR_START        30
+#define SGR_COLOR_END  37
+
+       def_color = atoi(color);
+       if ((SGR_COLOR_START + def_color) >= SGR_COLOR_START &&
+           (SGR_COLOR_START + def_color) <= SGR_COLOR_END) {
+               kernel_msg_color = def_color + SGR_COLOR_START;
+       }
+}
+
+static void
+do_new_kmess(void)
+{
+/* Kernel wants to print a new message */
+       struct kmessages *kmess_ptr;    /* kmessages structure */
+       char kernel_buf_copy[2*_KMESS_BUF_SIZE];
+       static int prev_next = 0;
+       int bytes, copy, restore = 0;
+       tty_t *tp, rtp;
+       message print_kmsg;
+
+       assert(_minix_kerninfo);
+       kmess_ptr = _minix_kerninfo->kmessages;
+
+       /* The kernel buffer is circular; print only the new part. Determine
+        * how many new bytes there are with the help of current and
+        * previous 'next' index. This works fine if less than _KMESS_BUF_SIZE
+        * bytes is new data; else we miss % _KMESS_BUF_SIZE here.
+        * Check for size being positive; the buffer might as well be emptied!
+        */
+       if (kmess_ptr->km_size > 0) {
+               bytes = ((kmess_ptr->km_next + _KMESS_BUF_SIZE) - prev_next) %
+                                                               _KMESS_BUF_SIZE;
+               /* Copy from current position to end of buffer */
+               copy = (prev_next + bytes) % _KMESS_BUF_SIZE;
+               memcpy(kernel_buf_copy, &kmess_ptr->km_buf[prev_next], copy);
+
+               /* Copy remainder from start of buffer */
+               if (copy < bytes) {
+                       memcpy(&kernel_buf_copy[copy], &kmess_ptr->km_buf[0],
+                               bytes - copy);
+               }
+
+               tp = line2tty(consoleline);
+               if (tp == NULL || !tty_active(tp))
+                       panic("Don't know where to send kernel messages");
+               if (tp->tty_outleft > 0) {
+                       /* Terminal is already printing */
+                       rtp = *tp;      /* Make backup */
+                       tp->tty_outleft = 0; /* So do_write is happy */
+                       restore = 1;
+               }
+
+               if (kernel_msg_color != 0)
+                       set_color(tp, kernel_msg_color);
+               print_kmsg.m_source = KERNEL;
+               print_kmsg.IO_GRANT = kernel_buf_copy;
+               print_kmsg.COUNT = bytes;
+               do_write(tp, &print_kmsg);
+               if (kernel_msg_color != 0)
+                       reset_color(tp);
+               if (restore) {
+                       *tp = rtp;
+               }
+       }
+
+       /* Store 'next' pointer so that we can determine what part of the
+        * kernel messages buffer to print next time a notification arrives.
+        */
+       prev_next = kmess_ptr->km_next;
+}
+
 /*===========================================================================*
  *                        sef_cb_signal_handler                             *
  *===========================================================================*/
@@ -335,7 +522,7 @@ static void sef_cb_signal_handler(int signo)
   switch(signo) {
       /* There is a pending message from the kernel. */
       case SIGKMESS:
-          do_new_kmess();
+         do_new_kmess();
       break;
       /* Switch to primary console on termination. */
       case SIGTERM:
@@ -586,7 +773,6 @@ message *m_ptr;                     /* pointer to message sent to task */
         size = sizeof(struct winsize);
         break;
 
-#if defined(__i386__)
     case KIOCSMAP:     /* load keymap (Minix extension) */
         size = sizeof(keymap_t);
         break;
@@ -595,7 +781,6 @@ message *m_ptr;                     /* pointer to message sent to task */
         size = sizeof(u8_t [8192]);
         break;
 
-#endif
     case TCDRAIN:      /* Posix tcdrain function -- no parameter */
     default:           size = 0;
   }
@@ -679,7 +864,6 @@ message *m_ptr;                     /* pointer to message sent to task */
        sigchar(tp, SIGWINCH, 0);
        break;
 
-#if defined(__i386__)
     case KIOCSMAP:
        /* Load a new keymap (only /dev/console). */
        if (isconsole(tp)) r = kbd_loadmap(m_ptr);
@@ -692,7 +876,6 @@ message *m_ptr;                     /* pointer to message sent to task */
        /* Load a font into an EGA or VGA card (hs@hck.hr) */
        if (isconsole(tp)) r = con_loadfont(m_ptr);
        break;
-#endif
 
 /* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is 
  * not defined.
@@ -729,6 +912,10 @@ message *m_ptr;                    /* pointer to message sent to task */
                r = 1;
        }
        tp->tty_openct++;
+       if (tp->tty_openct == 1) {
+               /* Tell the device that the tty is opened */
+               (*tp->tty_open)(tp, 0);
+       }
   }
   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r);
 }
@@ -1476,6 +1663,9 @@ int status;                       /* reply code */
   tty_mess.REP_ENDPT = proc_nr;
   tty_mess.REP_STATUS = status;
 
+  /* Don't reply to KERNEL (kernel messages) */
+  if (replyee == KERNEL) return;
+
   /* TTY is not supposed to send a TTY_REVIVE message. The
    * REVIVE message is gone, TTY_REVIVE is only used as an internal
    * placeholder for something that is not supposed to be a message.
@@ -1555,10 +1745,11 @@ static void tty_init()
   system_hz = sys_hz();
 
   /* Initialize the terminal lines. */
+  memset(tty_table, '\0' , sizeof(tty_table));
+
   for (tp = FIRST_TTY,s=0; tp < END_TTY; tp++,s++) {
 
        tp->tty_index = s;
-
        init_timer(&tp->tty_tmr);
 
        tp->tty_intail = tp->tty_inhead = tp->tty_inbuf;
@@ -1566,7 +1757,7 @@ static void tty_init()
        tp->tty_ingrant = tp->tty_outgrant = tp->tty_iogrant = GRANT_INVALID;
        tp->tty_termios = termios_defaults;
        tp->tty_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close =
-                                                               tty_devnop;
+                         tp->tty_open = tty_devnop;
        if (tp < tty_addr(NR_CONS)) {
                scr_init(tp);
 
index 311befbc6cb7e9b1178da8703f13442b39a7f203..9bf4147de447dcd60e03528c0f19cc847327a1e4 100644 (file)
@@ -17,6 +17,7 @@
 #define TTYPX_MINOR     128
 #define PTYPX_MINOR     192
 
+#define CONS_ARG         30    /* console= boot param length (incl. nul) */
 #define LINEWRAP          1    /* console.c - wrap lines at column 80 */
 
 #define TTY_IN_BYTES     256   /* tty input queue size */
@@ -91,6 +92,7 @@ typedef struct tty {
 
   /* Miscellaneous. */
   devfun_t tty_ioctl;          /* set line speed, etc. at the device level */
+  devfun_t tty_open;           /* tell the device that the tty is opened */ 
   devfun_t tty_close;          /* tell the device that the tty is closed */
   void *tty_priv;              /* pointer to per device private data */
   struct termios tty_termios;  /* terminal attributes */
@@ -154,11 +156,9 @@ int select_retry(struct tty *tp);
 void rs_init(struct tty *tp);
 void rs_interrupt(message *m);
 
-#if defined(__i386__)
 /* console.c */
 void kputc(int c);
 void cons_stop(void);
-void do_new_kmess(void);
 void scr_init(struct tty *tp);
 void toggle_scroll(void);
 int con_loadfont(message *m);
@@ -183,5 +183,3 @@ void pty_init(struct tty *tp);
 void select_retry_pty(struct tty *tp);
 int pty_status(message *m_ptr);
 
-#endif /* defined(__i386__) */
-