[parisc-linux-cvs] [PATCH] First pass for the Serial Mux
Ryan Bradetich
rbradetich@uswest.net
04 Nov 2002 21:51:39 -0700
--=-3WXjfD0Fca6IFD7NCecJ
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
I have committed the first pass for the Serial Mux ported to the new
serial core. Input/Output currently works, but the driver still needs
lots of cleanups.
- Ryan
--=-3WXjfD0Fca6IFD7NCecJ
Content-Disposition: attachment; filename=mux.diff
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-patch; name=mux.diff; charset=ISO-8859-1
Index: Makefile
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/linux-2.5/Makefile,v
retrieving revision 1.27
diff -u -p -r1.27 Makefile
--- Makefile 4 Nov 2002 16:41:36 -0000 1.27
+++ Makefile 5 Nov 2002 04:37:26 -0000
@@ -1,7 +1,7 @@
VERSION =3D 2
PATCHLEVEL =3D 5
SUBLEVEL =3D 45
-EXTRAVERSION =3D -pa6
+EXTRAVERSION =3D -pa7
=20
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
Index: arch/parisc/kernel/pdc_cons.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/linux-2.5/arch/parisc/kernel/pdc_cons.c,v
retrieving revision 1.6
diff -u -p -r1.6 pdc_cons.c
--- arch/parisc/kernel/pdc_cons.c 31 Oct 2002 06:07:33 -0000 1.6
+++ arch/parisc/kernel/pdc_cons.c 5 Nov 2002 04:37:26 -0000
@@ -52,15 +52,12 @@ static int pdc_console_setup(struct cons
return 0;
}
=20
-#ifdef CONFIG_PDC_CONSOLE
+#if defined(CONFIG_PDC_CONSOLE) || defined(CONFIG_SERIAL_MUX)
+#define PDC_CONSOLE_DEVICE pdc_console_device
static kdev_t pdc_console_device (struct console *c)
{
return mk_kdev(PDCCONS_MAJOR, 0);
}
-#endif
-
-#ifdef CONFIG_PDC_CONSOLE
-#define PDC_CONSOLE_DEVICE pdc_console_device
#else
#define PDC_CONSOLE_DEVICE NULL
#endif
@@ -95,7 +92,7 @@ static void pdc_console_init_force(void)
=20
void __init pdc_console_init(void)
{
-#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE)
+#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE) || defined(=
CONFIG_SERIAL_MUX)
pdc_console_init_force();
#endif
#ifdef EARLY_BOOTUP_DEBUG
Index: drivers/serial/Kconfig
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/linux-2.5/drivers/serial/Kconfig,v
retrieving revision 1.2
diff -u -p -r1.2 Kconfig
--- drivers/serial/Kconfig 31 Oct 2002 23:30:15 -0000 1.2
+++ drivers/serial/Kconfig 5 Nov 2002 04:37:26 -0000
@@ -317,9 +317,32 @@ config SERIAL_SUNSU
mouse on (PCI) UltraSPARC systems. Say Y or M if you want to be able
to these serial ports.
=20
+config SERIAL_MUX
+ bool "Serial MUX support"
+ depends on PARISC
+ default y
+ help
+ Saying Y here will enable the hardware MUX serial driver for
+ the Nova and K class systems. The hardware MUX is not 8250/16550=20
+ compatable therefore the /dev/ttyB0 device is shared between the=20
+ Serial MUX and the PDC software console. The following steps=20
+ need to be completed to use the Serial MUX:
+
+ 1. create the device entry (mknod /dev/ttyB0 c 60 0)
+ 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
+ 3. Add device ttyB0 to /etc/securetty (if you want to log on as
+ root on this console.)
+ 4. Change the kernel command console parameter to: console=3DttyB0
+
+config SERIAL_MUX_CONSOLE
+ bool
+ depends on SERIAL_MUX
+ default y
+
config PDC_CONSOLE
bool "PDC software console support"
- depends on PARISC
+ depends on PARISC && !SERIAL_MUX
+ default n
help
Saying Y here will enable the software based PDC console to be=20
used as the system console. This is useful for machines in=20
Index: drivers/serial/Makefile
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/linux-2.5/drivers/serial/Makefile,v
retrieving revision 1.5
diff -u -p -r1.5 Makefile
--- drivers/serial/Makefile 21 Oct 2002 03:45:50 -0000 1.5
+++ drivers/serial/Makefile 5 Nov 2002 04:37:26 -0000
@@ -24,5 +24,6 @@ obj-$(CONFIG_SERIAL_SUNCORE) +=3D suncore.
obj-$(CONFIG_SERIAL_SUNZILOG) +=3D sunzilog.o
obj-$(CONFIG_SERIAL_SUNSU) +=3D sunsu.o
obj-$(CONFIG_SERIAL_SUNSAB) +=3D sunsab.o
+obj-$(CONFIG_SERIAL_MUX) +=3D mux.o
=20
include $(TOPDIR)/Rules.make
Index: drivers/serial/core.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/linux-2.5/drivers/serial/core.c,v
retrieving revision 1.5
diff -u -p -r1.5 core.c
--- drivers/serial/core.c 2 Nov 2002 22:48:54 -0000 1.5
+++ drivers/serial/core.c 5 Nov 2002 04:37:27 -0000
@@ -522,7 +522,7 @@ static void uart_flush_buffer(struct tty
unsigned long flags;
=20
DPRINTK("uart_flush_buffer(%d) called\n",
- MINOR(tty->device) - tty->driver.minor_start);
+ minor(tty->device) - tty->driver.minor_start);
=20
spin_lock_irqsave(&info->port->lock, flags);
uart_circ_clear(&info->xmit);
Index: drivers/serial/mux.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: drivers/serial/mux.c
diff -N drivers/serial/mux.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ drivers/serial/mux.c 5 Nov 2002 04:37:27 -0000
@@ -0,0 +1,452 @@
+/*
+** mux.c:
+** MUX console for the NOVA and K-Class systems.
+**
+** (c) Copyright 2002 Ryan Bradetich
+** (c) Copyright 2002 Hewlett-Packard Company
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This Driver currently only supports the console (port 0) on the MUX.
+** Additional work will be needed on this driver to enable the full
+** functionality of the MUX.
+**
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define MUX_NR 1
+
+#define MUX_OFFSET 0x800
+#define MUX_LINE_OFFSET 0x80
+
+#define MUX_FIFO_SIZE 255
+#define MUX_MIN_FREE_SIZE 32
+
+#define MUX_FIFO_DRAIN_DELAY 1
+/* #define MUX_POLL_DELAY (30 * HZ / 1000) */
+#define MUX_POLL_DELAY HZ
+
+#define IO_COMMAND_REG_OFFSET 0x30
+#define IO_STATUS_REG_OFFSET 0x34
+#define IO_DATA_REG_OFFSET 0x3c
+#define IO_DCOUNT_REG_OFFSET 0x40
+#define IO_UCOUNT_REG_OFFSET 0x44
+#define IO_FIFOS_REG_OFFSET 0x48
+
+#define MUX_EOFIFO(status) ((status & 0xF000) =3D=3D 0xF000)
+#define MUX_STATUS(status) ((status & 0xF000) =3D=3D 0x8000)
+#define MUX_BREAK(status) ((status & 0xF000) =3D=3D 0x2000)
+
+
+static struct uart_port mux_ports[MUX_NR];
+static struct timer_list mux_timer;
+
+#define UART_PUT_CHAR(p, c) __raw_writel((c), (unsigned long)(p)->membase =
+ IO_DATA_REG_OFFSET)
+
+
+/**
+ * mux_tx_empty - Check if the transmitter fifo is empty.
+ * @port: Ptr to the uart_port.
+ *
+ * This function test if the transmitter fifo for the port
+ * described by 'port' is empty. If it is empty, this function
+ * should return TIOCSER_TEMT, otherwise return 0.
+ */
+static unsigned int mux_tx_empty(struct uart_port *port)
+{
+ unsigned int cnt =3D __raw_readl((unsigned long)port->membase=20
+ + IO_DCOUNT_REG_OFFSET);
+
+ return cnt ? 0 : TIOCSER_TEMT;
+}=20
+
+/**
+ * mux_set_mctrl - Set the current state of the modem control inputs.
+ * @ports: Ptr to the uart_port.
+ * @mctrl: Modem control bits.
+ *
+ * The Serial MUX does not support CTS, DCD or DSR so this function
+ * is ignored.
+ */
+static void mux_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/**
+ * mux_get_mctrl - Returns the current state of modem control inputs.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial MUX does not support CTS, DCD or DSR so these lines are
+ * treated as permanently active.
+ */
+static unsigned int mux_get_mctrl(struct uart_port *port)
+{=20
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void mux_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+}
+
+static void mux_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+}
+
+static void mux_stop_rx(struct uart_port *port)
+{
+}
+
+static void mux_enable_ms(struct uart_port *port)
+{
+}
+
+static void mux_break_ctl(struct uart_port *port, int break_state)
+{
+}
+/**
+ * mux_write - Write chars to the mux fifo.
+ * @port: Ptr to the uart_port.
+ *
+ * This function writes all the data from the uart buffer to
+ * the mux fifo.
+ */
+static void mux_write(struct uart_port *port)
+{
+ int count;
+ struct circ_buf *xmit =3D &port->info->xmit;
+
+ if(port->x_char) {
+ UART_PUT_CHAR(port, port->x_char);
+ port->icount.tx++;
+ port->x_char =3D 0;
+ return;
+ }
+
+ if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ mux_stop_tx(port, 0);
+ return;
+ }
+
+ count =3D port->fifosize >> 1;
+ do {
+ UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+ xmit->tail =3D (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if(uart_circ_empty(xmit))
+ break;
+
+ } while(--count > 0);
+
+ if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_event(port, EVT_WRITE_WAKEUP);
+
+ if (uart_circ_empty(xmit))
+ mux_stop_tx(port, 0);
+}
+
+/**
+ * mux_read - Read chars from the mux fifo.
+ * @port: Ptr to the uart_port.
+ *
+ * This reads all available data from the mux's fifo and pushes
+ * the data to the tty layer.
+ */
+static void mux_read(struct uart_port *port)
+{
+ int data;
+ struct tty_struct *tty =3D port->info->tty;
+
+ while(1) {
+ data =3D __raw_readl((unsigned long)port->membase
+ + IO_DATA_REG_OFFSET);
+
+ if (MUX_STATUS(data))
+ continue;
+
+ if (MUX_EOFIFO(data))
+ break;
+
+ if (tty->flip.count >=3D TTY_FLIPBUF_SIZE)
+ continue;
+
+ *tty->flip.char_buf_ptr =3D data & 0xffu;
+ *tty->flip.flag_buf_ptr =3D TTY_NORMAL;
+ port->icount.rx++;
+
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+
+ tty_flip_buffer_push(tty);
+}
+
+static int mux_startup(struct uart_port *port)
+{
+ mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
+ return 0;
+}
+
+static void mux_shutdown(struct uart_port *port)
+{
+}
+
+static void
+mux_change_speed(struct uart_port *port, unsigned int cflag,
+ unsigned int iflag, unsigned int quot)
+{
+}
+
+static const char *mux_type(struct uart_port *port)
+{
+ return "Serial Mux";
+}
+
+static void mux_release_port(struct uart_port *port)
+{
+}
+
+static int mux_request_port(struct uart_port *port)
+{
+ return request_mem_region(port->mapbase, MUX_LINE_OFFSET, "Serial Mux")
+ !=3D NULL ? 0 : -EBUSY;
+}
+
+static void mux_config_port(struct uart_port *port, int flags)
+{
+ port->type =3D PORT_MUX;
+}
+
+/**
+ * mux_verify_port -=20
+ * @port: Ptr to the uart_port.
+ * @ser:=20
+ *
+ * Verify the new serial port information contained within serinfo is
+ * suitable for this port type.
+ */
+static int mux_verify_port(struct uart_port *port, struct serial_struct *s=
er)
+{
+ if(port->membase =3D=3D NULL)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * mux_drv_poll - Mux poll function. =20
+ * @unused: Unused variable
+ *
+ * This function periodically polls the Serial MUX to check for new data.
+ */
+static void mux_poll(unsigned long unused)
+{ =20
+ struct uart_port *port =3D &mux_ports[0];
+
+ mux_read(port);
+ mux_write(port);
+ mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
+}
+
+
+static struct uart_ops mux_pops =3D {
+ .tx_empty =3D mux_tx_empty,
+ .set_mctrl =3D mux_set_mctrl,
+ .get_mctrl =3D mux_get_mctrl,
+ .stop_tx =3D mux_stop_tx,
+ .start_tx =3D mux_start_tx,
+ .stop_rx =3D mux_stop_rx,
+ .enable_ms =3D mux_enable_ms,
+ .break_ctl =3D mux_break_ctl,
+ .startup =3D mux_startup,
+ .shutdown =3D mux_shutdown,
+ .change_speed =3D mux_change_speed,
+ .type =3D mux_type,
+ .release_port =3D mux_release_port,
+ .request_port =3D mux_request_port,
+ .config_port =3D mux_config_port,
+ .verify_port =3D mux_verify_port,
+};
+
+#if 0
+static void
+mux_console_write(struct console *co, const char *s, unsigned int count)
+{
+ printk("[%s] %s(): %d\n", __FILE__, __FUNCTION__, __LINE__);
+}
+
+static kdev_t mux_console_device(struct console *co)
+{
+ printk("[%s] %s(): %d\n", __FILE__, __FUNCTION__, __LINE__);
+ return mk_kdev(PDCCONS_MAJOR, 0 + co->index);
+}
+
+static void __init
+mux_console_get_options(struct uart_port *port, int *baud,=20
+ int *parity, int *bits)
+{
+ printk("[%s] %s(): %d\n", __FILE__, __FUNCTION__, __LINE__);
+}
+
+static int __init mux_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud =3D 9600;
+ int bits =3D 8;
+ int parity =3D 'n';
+ int flow =3D 'n';
+
+ printk("[%s] %s(): %d\n", __FILE__, __FUNCTION__, __LINE__);
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index >=3D MUX_NR)
+ co->index =3D 0;
+
+ port =3D &mux_ports[0];
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ mux_console_get_options(port, &baud, &parity, &bits);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console mux_console =3D {
+ .name =3D "ttyB",
+ .write =3D mux_console_write,
+ .device =3D mux_console_device,
+ .setup =3D mux_console_setup,
+ .flags =3D CON_PRINTBUFFER,
+ .index =3D -1,
+};
+
+void __init mux_console_init(void)
+{
+ printk("[%s] %s(): %d\n", __FILE__, __FUNCTION__, __LINE__);
+ register_console(&mux_console);
+}
+#endif
+
+static struct uart_driver mux_reg =3D {
+ .owner =3D THIS_MODULE,
+ .driver_name =3D "ttyB",
+#ifdef CONFIG_DEVFS_FS
+ .dev_name =3D "ttyB%d",
+#else
+ .dev_name =3D "ttyB",
+#endif
+ .major =3D PDCCONS_MAJOR,
+ .minor =3D 0,
+ .nr =3D MUX_NR,=20
+ .cons =3D NULL,
+};
+
+/**
+ * mux_probe - Determine if the Serial Mux should claim this device.
+ * @dev: The parisc device.
+ *
+ * Deterimine if the Serial Mux should claim this chip (return 0)
+ * or not (return 1).
+ */
+static int __init mux_probe(struct parisc_device *dev)
+{
+ int i, ret;
+ struct uart_port *port =3D &mux_ports[0];
+
+ init_timer(&mux_timer);
+ mux_timer.function =3D mux_poll;
+
+ printk(KERN_INFO "Serial mux driver Revision: 0.1\n");
+
+ ret =3D uart_register_driver(&mux_reg);
+ if(ret)
+ return ret;
+
+ for (i =3D 0; i < MUX_NR; i++) {
+ port =3D &mux_ports[i];
+
+ port->iobase =3D dev->hpa + MUX_OFFSET;
+ port->mapbase =3D dev->hpa + MUX_OFFSET;
+ port->membase =3D (void *)(dev->hpa + MUX_OFFSET);
+ port->iotype =3D SERIAL_IO_MEM;
+ port->type =3D PORT_MUX;
+ port->irq =3D 0;
+ port->uartclk =3D 0;
+ port->fifosize =3D MUX_FIFO_SIZE;
+ port->ops =3D &mux_pops;
+ port->flags =3D UPF_BOOT_AUTOCONF;
+ port->line =3D 0;
+
+ uart_add_one_port(&mux_reg, port);
+ }
+
+ return 0;
+}
+
+static struct parisc_device_id mux_tbl[] =3D {
+ { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, mux_tbl);
+
+static struct parisc_driver mux_driver =3D {
+ name: "Serial MUX driver",
+ id_table: mux_tbl,
+ probe: mux_probe,
+};
+
+/**
+ * mux_init - Serial MUX initalization procedure.
+ *
+ * Register the Serial MUX driver.
+ */
+static int __init mux_init(void)
+{
+ return register_parisc_driver(&mux_driver);
+}
+
+/**
+ * mux_exit - Serial MUX cleanup procedure.
+ *
+ * Unregister the Serial MUX driver from the tty layer.
+ */
+static void __exit mux_exit(void)
+{
+ int i;
+
+ for(i =3D 0; i < MUX_NR; i++) {
+ uart_remove_one_port(&mux_reg, &mux_ports[i]);
+ }
+
+ uart_unregister_driver(&mux_reg);
+}
+
+module_init(mux_init);
+module_exit(mux_exit);
+
+MODULE_AUTHOR("Ryan Bradetich");
+MODULE_DESCRIPTION("Serial MUX driver");
+MODULE_LICENSE("GPL");
Index: include/linux/serial_core.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/linux-2.5/include/linux/serial_core.h,v
retrieving revision 1.4
diff -u -p -r1.4 serial_core.h
--- include/linux/serial_core.h 21 Oct 2002 03:46:12 -0000 1.4
+++ include/linux/serial_core.h 5 Nov 2002 04:37:27 -0000
@@ -55,6 +55,9 @@
#define PORT_SUNZILOG 38
#define PORT_SUNSAB 39
=20
+/* Parisc type numbers. */
+#define PORT_MUX 40
+
#ifdef __KERNEL__
=20
#include <linux/config.h>
--=-3WXjfD0Fca6IFD7NCecJ--