Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/amlogic UART TTY support.



details:   https://anonhg.NetBSD.org/src/rev/83fe1a2fd618
branches:  trunk
changeset: 336446:83fe1a2fd618
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sun Mar 01 23:39:28 2015 +0000

description:
UART TTY support.

diffstat:

 sys/arch/arm/amlogic/amlogic_com.c    |  330 ++++++++++++++++++++++++++++++++-
 sys/arch/arm/amlogic/amlogic_comreg.h |   14 +-
 2 files changed, 330 insertions(+), 14 deletions(-)

diffs (truncated from 435 to 300 lines):

diff -r 9f2e0214f8c0 -r 83fe1a2fd618 sys/arch/arm/amlogic/amlogic_com.c
--- a/sys/arch/arm/amlogic/amlogic_com.c        Sun Mar 01 21:00:40 2015 +0000
+++ b/sys/arch/arm/amlogic/amlogic_com.c        Sun Mar 01 23:39:28 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: amlogic_com.c,v 1.2 2015/02/27 17:35:08 jmcneill Exp $ */
+/* $NetBSD: amlogic_com.c,v 1.3 2015/03/01 23:39:28 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -33,15 +33,22 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: amlogic_com.c,v 1.2 2015/02/27 17:35:08 jmcneill Exp $");
+__KERNEL_RCSID(1, "$NetBSD: amlogic_com.c,v 1.3 2015/03/01 23:39:28 jmcneill Exp $");
+
+#define AMLOGIC_COM_INTRPOLL
+#define AMLOGIC_COM_INTRPOLL_RATE      10
 
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/device.h>
+#include <sys/conf.h>
 #include <sys/intr.h>
 #include <sys/systm.h>
 #include <sys/time.h>
 #include <sys/termios.h>
+#include <sys/kauth.h>
+#include <sys/lwp.h>
+#include <sys/tty.h>
 
 #include <dev/cons.h>
 
@@ -50,32 +57,80 @@
 #include <arm/amlogic/amlogic_comreg.h>
 #include <arm/amlogic/amlogic_comvar.h>
 
-static int amlogic_com_match(device_t, cfdata_t, void *);
-static void amlogic_com_attach(device_t, device_t, void *);
+static int     amlogic_com_match(device_t, cfdata_t, void *);
+static void    amlogic_com_attach(device_t, device_t, void *);
+
+static int     amlogic_com_intr(void *);
+
+#ifdef AMLOGIC_COM_INTRPOLL
+static void    amlogic_com_intrpoll(void *);
+#endif
+
+static int     amlogic_com_cngetc(dev_t);
+static void    amlogic_com_cnputc(dev_t, int);
+static void    amlogic_com_cnpollc(dev_t, int);
+
+static void    amlogic_com_start(struct tty *);
+static int     amlogic_com_param(struct tty *, struct termios *);
+
+extern struct cfdriver amlogiccom_cd;
 
 struct amlogic_com_softc {
        device_t sc_dev;
        bus_space_tag_t sc_bst;
        bus_space_handle_t sc_bsh;
+       void *sc_ih;
+
+       struct tty *sc_tty;
 
        int sc_ospeed;
        tcflag_t sc_cflag;
+
+       u_char sc_buf[1024];
+
+#ifdef AMLOGIC_COM_INTRPOLL
+       callout_t sc_intrpoll_ch;
+#endif
 };
 
 static struct amlogic_com_softc amlogic_com_cnsc;
 
 static struct cnm_state amlogic_com_cnm_state;
 
-static int     amlogic_com_cngetc(dev_t);
-static void    amlogic_com_cnputc(dev_t, int);
-static void    amlogic_com_cnpollc(dev_t, int);
-
 struct consdev amlogic_com_consdev = {
        .cn_getc = amlogic_com_cngetc,
        .cn_putc = amlogic_com_cnputc,
        .cn_pollc = amlogic_com_cnpollc,
+       .cn_dev = NODEV,
+       .cn_pri = CN_NORMAL,
 };
 
+static dev_type_open(amlogic_com_open);
+static dev_type_open(amlogic_com_close);
+static dev_type_read(amlogic_com_read);
+static dev_type_write(amlogic_com_write);
+static dev_type_ioctl(amlogic_com_ioctl);
+static dev_type_tty(amlogic_com_tty);
+static dev_type_poll(amlogic_com_poll);
+static dev_type_stop(amlogic_com_stop);
+
+const struct cdevsw amlogiccom_cdevsw = {
+       .d_open = amlogic_com_open,
+       .d_close = amlogic_com_close,
+       .d_read = amlogic_com_read,
+       .d_write = amlogic_com_write,
+       .d_ioctl = amlogic_com_ioctl,
+       .d_stop = amlogic_com_stop,
+       .d_tty = amlogic_com_tty,
+       .d_poll = amlogic_com_poll,
+       .d_mmap = nommap,
+       .d_kqfilter = ttykqfilter,
+       .d_discard = nodiscard,
+       .d_flag = D_TTY
+};
+
+static int amlogic_com_cmajor = -1;
+
 CFATTACH_DECL_NEW(amlogic_com, sizeof(struct amlogic_com_softc),
        amlogic_com_match, amlogic_com_attach, NULL, NULL);
 
@@ -92,17 +147,82 @@
        struct amlogicio_attach_args * const aio = aux;
        const struct amlogic_locators * const loc = &aio->aio_loc;
        const bus_addr_t iobase = AMLOGIC_CORE_BASE + loc->loc_offset;
+       struct tty *tp;
+       int major, minor;
+       uint32_t misc, control;
 
        sc->sc_dev = self;
        sc->sc_bst = aio->aio_core_bst;
-       sc->sc_bsh = aio->aio_bsh;
+       bus_space_subregion(aio->aio_core_bst, aio->aio_bsh,
+           loc->loc_offset, loc->loc_size, &sc->sc_bsh);
+
+#ifdef AMLOGIC_COM_INTRPOLL
+       callout_init(&sc->sc_intrpoll_ch, CALLOUT_MPSAFE);
+       callout_setfunc(&sc->sc_intrpoll_ch, amlogic_com_intrpoll, sc);
+#else
+       sc->sc_ih = intr_establish(loc->loc_intr, IPL_SERIAL,
+           IST_EDGE | IST_MPSAFE, amlogic_com_intr, sc);
+       if (sc->sc_ih == NULL) {
+               aprint_error(": failed to establish interrupt %d\n",
+                   loc->loc_intr);
+               return;
+       }
+#endif
+
+       if (amlogic_com_cmajor == -1) {
+               /* allocate a major number */
+               int bmajor = -1, cmajor = -1;
+               int error = devsw_attach("amlogiccom", NULL, &bmajor,
+                   &amlogiccom_cdevsw, &cmajor);
+               if (error) {
+                       aprint_error(": couldn't allocate major number\n");
+                       return;
+               }
+               amlogic_com_cmajor = cmajor;
+       }
+
+       major = cdevsw_lookup_major(&amlogiccom_cdevsw);
+       minor = device_unit(self);
+
+       tp = sc->sc_tty = tty_alloc();
+       tp->t_oproc = amlogic_com_start;
+       tp->t_param = amlogic_com_param;
+       tp->t_dev = makedev(major, minor);
+       tp->t_sc = sc;
+       tty_attach(tp);
 
        aprint_naive("\n");
        if (amlogic_com_is_console(iobase)) {
-               aprint_normal(": (console)\n");
-       } else {
-               aprint_normal("\n");
+               cn_tab->cn_dev = tp->t_dev;
+               aprint_normal(": console");
        }
+       aprint_normal("\n");
+
+#ifdef AMLOGIC_COM_INTRPOLL
+       aprint_normal_dev(self, "polling\n");
+#else
+       aprint_normal_dev(self, "interrupting at irq %d\n", loc->loc_intr);
+#endif
+
+       misc = bus_space_read_4(sc->sc_bst, sc->sc_bsh, UART_MISC_REG);
+       misc &= ~UART_MISC_TX_IRQ_CNT;
+       misc |= __SHIFTIN(0, UART_MISC_TX_IRQ_CNT);
+       misc &= ~UART_MISC_RX_IRQ_CNT;
+       misc |= __SHIFTIN(1, UART_MISC_RX_IRQ_CNT);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, UART_MISC_REG, misc);
+
+       control = bus_space_read_4(sc->sc_bst, sc->sc_bsh, UART_CONTROL_REG);
+       control &= ~UART_CONTROL_TX_INT_EN;
+#ifdef AMLOGIC_COM_INTRPOLL
+       control &= ~UART_CONTROL_RX_INT_EN;
+#else
+       control |= UART_CONTROL_RX_INT_EN;
+#endif
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, UART_CONTROL_REG, control);
+
+#ifdef AMLOGIC_COM_INTRPOLL
+       callout_schedule(&sc->sc_intrpoll_ch, AMLOGIC_COM_INTRPOLL_RATE);
+#endif
 }
 
 static int
@@ -145,7 +265,7 @@
 
        s = splserial();
 
-       while ((bus_space_read_4(bst, bsh, UART_STATUS_REG) & UART_STATUS_TX_EMPTY) == 0)
+       while ((bus_space_read_4(bst, bsh, UART_STATUS_REG) & UART_STATUS_TX_FULL) != 0)
                ;
 
        bus_space_write_4(bst, bsh, UART_WFIFO_REG, c);
@@ -182,3 +302,187 @@
 {
        return iobase == CONSADDR;
 }
+
+static int
+amlogic_com_open(dev_t dev, int flag, int mode, lwp_t *l)
+{
+       struct amlogic_com_softc *sc =
+           device_lookup_private(&amlogiccom_cd, minor(dev));
+       struct tty *tp = sc->sc_tty;
+
+       if (kauth_authorize_device_tty(l->l_cred,
+           KAUTH_DEVICE_TTY_OPEN, tp) != 0) {
+               return EBUSY;
+       }
+
+       if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
+               tp->t_dev = dev;
+               ttychars(tp);
+               tp->t_iflag = TTYDEF_IFLAG;
+               tp->t_oflag = TTYDEF_OFLAG;
+               tp->t_cflag = TTYDEF_CFLAG;
+               tp->t_lflag = TTYDEF_LFLAG;
+               tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+               ttsetwater(tp);
+       }
+       tp->t_state |= TS_CARR_ON;
+
+       return tp->t_linesw->l_open(dev, tp);
+}
+
+static int
+amlogic_com_close(dev_t dev, int flag, int mode, lwp_t *l)
+{
+       struct amlogic_com_softc *sc =
+           device_lookup_private(&amlogiccom_cd, minor(dev));
+       struct tty *tp = sc->sc_tty;
+
+       tp->t_linesw->l_close(tp, flag);
+       ttyclose(tp);
+
+       return 0;
+}
+
+static int
+amlogic_com_read(dev_t dev, struct uio *uio, int flag)
+{
+       struct amlogic_com_softc *sc =
+           device_lookup_private(&amlogiccom_cd, minor(dev));
+       struct tty *tp = sc->sc_tty;
+
+       return tp->t_linesw->l_read(tp, uio, flag);
+}
+
+static int
+amlogic_com_write(dev_t dev, struct uio *uio, int flag)
+{
+       struct amlogic_com_softc *sc =
+           device_lookup_private(&amlogiccom_cd, minor(dev));
+       struct tty *tp = sc->sc_tty;
+
+       return tp->t_linesw->l_write(tp, uio, flag);
+}
+
+static int
+amlogic_com_poll(dev_t dev, int events, lwp_t *l)
+{
+       struct amlogic_com_softc *sc =
+           device_lookup_private(&amlogiccom_cd, minor(dev));
+       struct tty *tp = sc->sc_tty;
+
+       return tp->t_linesw->l_poll(tp, events, l);
+}
+
+static int
+amlogic_com_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
+{
+       struct amlogic_com_softc *sc =
+           device_lookup_private(&amlogiccom_cd, minor(dev));
+       struct tty *tp = sc->sc_tty;
+       int error;
+
+       error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, l);



Home | Main Index | Thread Index | Old Index