From 652996fac1ceb4ab6b36c7263e526d580d81d304 Mon Sep 17 00:00:00 2001 From: kettenis Date: Fri, 6 Aug 2010 21:04:14 +0000 Subject: [PATCH] Initial stab at making com@puc suspend and resume properly. Works fine for using cu(1) between two OpenBSD machines. Probably doesn't work for serial consoles but we don't support those on puc(4) anyway. ok deraadt@ --- sys/dev/ic/com.c | 106 +++++++++++++++++++++++++++++++++++++++++- sys/dev/ic/comvar.h | 3 +- sys/dev/pci/puc.c | 4 +- sys/dev/puc/com_puc.c | 28 +++++++++-- 4 files changed, 132 insertions(+), 9 deletions(-) diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c index de71a6408e5..0cf3a35bf83 100644 --- a/sys/dev/ic/com.c +++ b/sys/dev/ic/com.c @@ -1,4 +1,4 @@ -/* $OpenBSD: com.c,v 1.142 2010/07/02 17:27:01 nicm Exp $ */ +/* $OpenBSD: com.c,v 1.143 2010/08/06 21:04:14 kettenis Exp $ */ /* $NetBSD: com.c,v 1.82.4.1 1996/06/02 09:08:00 mrg Exp $ */ /* @@ -566,6 +566,110 @@ compwroff(struct com_softc *sc) } } +void +com_resume(struct com_softc *sc) +{ + struct tty *tp = sc->sc_tty; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int ospeed; + + if (!tp || !ISSET(tp->t_state, TS_ISOPEN)) + return; + + /* + * Wake up the sleepy heads. + */ + switch (sc->sc_uarttype) { + case COM_UART_ST16650: + case COM_UART_ST16650V2: + bus_space_write_1(iot, ioh, com_lcr, LCR_EFR); + bus_space_write_1(iot, ioh, com_efr, EFR_ECB); + bus_space_write_1(iot, ioh, com_ier, 0); + bus_space_write_1(iot, ioh, com_efr, 0); + bus_space_write_1(iot, ioh, com_lcr, 0); + break; + case COM_UART_TI16750: + bus_space_write_1(iot, ioh, com_ier, 0); + break; + case COM_UART_PXA2X0: + bus_space_write_1(iot, ioh, com_ier, IER_EUART); + break; + } + + ospeed = comspeed(sc->sc_frequency, tp->t_ospeed); + + if (ospeed != 0) { + bus_space_write_1(iot, ioh, com_lcr, sc->sc_lcr | LCR_DLAB); + bus_space_write_1(iot, ioh, com_dlbl, ospeed); + bus_space_write_1(iot, ioh, com_dlbh, ospeed >> 8); + bus_space_write_1(iot, ioh, com_lcr, sc->sc_lcr); + } else { + bus_space_write_1(iot, ioh, com_lcr, sc->sc_lcr); + } + + if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) { + u_int8_t fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST; + u_int8_t lcr; + + if (tp->t_ispeed <= 1200) + fifo |= FIFO_TRIGGER_1; + else if (tp->t_ispeed <= 38400) + fifo |= FIFO_TRIGGER_4; + else + fifo |= FIFO_TRIGGER_8; + if (sc->sc_uarttype == COM_UART_TI16750) { + fifo |= FIFO_ENABLE_64BYTE; + lcr = bus_space_read_1(iot, ioh, com_lcr); + bus_space_write_1(iot, ioh, com_lcr, + lcr | LCR_DLAB); + } + + /* + * (Re)enable and drain FIFOs. + * + * Certain SMC chips cause problems if the FIFOs are + * enabled while input is ready. Turn off the FIFO + * if necessary to clear the input. Test the input + * ready bit after enabling the FIFOs to handle races + * between enabling and fresh input. + * + * Set the FIFO threshold based on the receive speed. + */ + for (;;) { + bus_space_write_1(iot, ioh, com_fifo, 0); + delay(100); + (void) bus_space_read_1(iot, ioh, com_data); + bus_space_write_1(iot, ioh, com_fifo, fifo | + FIFO_RCV_RST | FIFO_XMT_RST); + delay(100); + if(!ISSET(bus_space_read_1(iot, ioh, + com_lsr), LSR_RXRDY)) + break; + } + if (sc->sc_uarttype == COM_UART_TI16750) + bus_space_write_1(iot, ioh, com_lcr, lcr); + } + + /* Flush any pending I/O. */ + while (ISSET(bus_space_read_1(iot, ioh, com_lsr), LSR_RXRDY)) + (void) bus_space_read_1(iot, ioh, com_data); + + /* You turn me on, baby! */ + bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr); + bus_space_write_1(iot, ioh, com_ier, sc->sc_ier); + +#ifdef COM_PXA2X0 + if (sc->sc_uarttype == COM_UART_PXA2X0 && + ISSET(sc->sc_hwflags, COM_HW_SIR)) { + bus_space_write_1(iot, ioh, com_isr, ISR_RECV); +#ifdef __zaurus__ + scoop_set_irled(1); +#endif + } +#endif +} + void com_raisedtr(void *arg) { diff --git a/sys/dev/ic/comvar.h b/sys/dev/ic/comvar.h index d6c015584ed..3e80241e9f2 100644 --- a/sys/dev/ic/comvar.h +++ b/sys/dev/ic/comvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: comvar.h,v 1.49 2010/08/01 23:55:38 yasuoka Exp $ */ +/* $OpenBSD: comvar.h,v 1.50 2010/08/06 21:04:14 kettenis Exp $ */ /* $NetBSD: comvar.h,v 1.5 1996/05/05 19:50:47 christos Exp $ */ /* @@ -138,6 +138,7 @@ int comstop(struct tty *, int); int comintr(void *); int com_detach(struct device *, int); int com_activate(struct device *, int); +void com_resume(struct com_softc *); void comdiag(void *); int comspeed(long, long); diff --git a/sys/dev/pci/puc.c b/sys/dev/pci/puc.c index 9ec1af4d59d..fb1c14f0d8f 100644 --- a/sys/dev/pci/puc.c +++ b/sys/dev/pci/puc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: puc.c,v 1.17 2010/07/22 17:16:10 pirofti Exp $ */ +/* $OpenBSD: puc.c,v 1.18 2010/08/06 21:04:14 kettenis Exp $ */ /* $NetBSD: puc.c,v 1.3 1999/02/06 06:29:54 cgd Exp $ */ /* @@ -79,7 +79,7 @@ void *puc_pci_intr_establish(struct puc_attach_args *, int, struct cfattach puc_pci_ca = { sizeof(struct puc_pci_softc), puc_pci_match, - puc_pci_attach, puc_pci_detach + puc_pci_attach, puc_pci_detach, config_activate_children }; struct cfdriver puc_cd = { diff --git a/sys/dev/puc/com_puc.c b/sys/dev/puc/com_puc.c index 84ba7d16c98..8069f2197e4 100644 --- a/sys/dev/puc/com_puc.c +++ b/sys/dev/puc/com_puc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: com_puc.c,v 1.17 2010/06/26 23:24:45 guenther Exp $ */ +/* $OpenBSD: com_puc.c,v 1.18 2010/08/06 21:07:27 kettenis Exp $ */ /* * Copyright (c) 1997 - 1999, Jason Downs. All rights reserved. @@ -54,12 +54,14 @@ #define com_lcr com_cfcr -int com_puc_match(struct device *, void *, void *); -void com_puc_attach(struct device *, struct device *, void *); -int com_puc_detach(struct device *, int ); +int com_puc_match(struct device *, void *, void *); +void com_puc_attach(struct device *, struct device *, void *); +int com_puc_detach(struct device *, int); +int com_puc_activate(struct device *, int); struct cfattach com_puc_ca = { - sizeof(struct com_softc), com_puc_match, com_puc_attach, com_puc_detach + sizeof(struct com_softc), com_puc_match, + com_puc_attach, com_puc_detach, com_puc_activate }; int @@ -118,3 +120,19 @@ com_puc_detach(struct device *self, int flags) { return com_detach(self, flags); } + +int +com_puc_activate(struct device *self, int act) +{ + struct com_softc *sc = (struct com_softc *)self; + + switch (act) { + case DVACT_SUSPEND: + break; + case DVACT_RESUME: + com_resume(sc); + break; + } + + return (0); +} -- 2.20.1