1*27d5dc18SMarcel Moolenaar /* 2*27d5dc18SMarcel Moolenaar * Copyright (c) 2003 Marcel Moolenaar 3*27d5dc18SMarcel Moolenaar * All rights reserved. 4*27d5dc18SMarcel Moolenaar * 5*27d5dc18SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 6*27d5dc18SMarcel Moolenaar * modification, are permitted provided that the following conditions 7*27d5dc18SMarcel Moolenaar * are met: 8*27d5dc18SMarcel Moolenaar * 9*27d5dc18SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 10*27d5dc18SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 11*27d5dc18SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 12*27d5dc18SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 13*27d5dc18SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 14*27d5dc18SMarcel Moolenaar * 15*27d5dc18SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16*27d5dc18SMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17*27d5dc18SMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18*27d5dc18SMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19*27d5dc18SMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20*27d5dc18SMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21*27d5dc18SMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22*27d5dc18SMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23*27d5dc18SMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24*27d5dc18SMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*27d5dc18SMarcel Moolenaar */ 26*27d5dc18SMarcel Moolenaar 27*27d5dc18SMarcel Moolenaar #include <sys/cdefs.h> 28*27d5dc18SMarcel Moolenaar __FBSDID("$FreeBSD$"); 29*27d5dc18SMarcel Moolenaar 30*27d5dc18SMarcel Moolenaar #ifndef KLD_MODULE 31*27d5dc18SMarcel Moolenaar #include "opt_comconsole.h" 32*27d5dc18SMarcel Moolenaar #include "opt_ddb.h" 33*27d5dc18SMarcel Moolenaar #endif 34*27d5dc18SMarcel Moolenaar 35*27d5dc18SMarcel Moolenaar #include <sys/param.h> 36*27d5dc18SMarcel Moolenaar #include <sys/systm.h> 37*27d5dc18SMarcel Moolenaar #include <sys/bus.h> 38*27d5dc18SMarcel Moolenaar #include <sys/conf.h> 39*27d5dc18SMarcel Moolenaar #include <sys/cons.h> 40*27d5dc18SMarcel Moolenaar #include <sys/fcntl.h> 41*27d5dc18SMarcel Moolenaar #include <sys/interrupt.h> 42*27d5dc18SMarcel Moolenaar #include <sys/kernel.h> 43*27d5dc18SMarcel Moolenaar #include <sys/malloc.h> 44*27d5dc18SMarcel Moolenaar #include <sys/queue.h> 45*27d5dc18SMarcel Moolenaar #include <sys/reboot.h> 46*27d5dc18SMarcel Moolenaar #include <machine/bus.h> 47*27d5dc18SMarcel Moolenaar #include <sys/rman.h> 48*27d5dc18SMarcel Moolenaar #include <sys/termios.h> 49*27d5dc18SMarcel Moolenaar #include <sys/tty.h> 50*27d5dc18SMarcel Moolenaar #include <machine/resource.h> 51*27d5dc18SMarcel Moolenaar #include <machine/stdarg.h> 52*27d5dc18SMarcel Moolenaar 53*27d5dc18SMarcel Moolenaar #include <ddb/ddb.h> 54*27d5dc18SMarcel Moolenaar 55*27d5dc18SMarcel Moolenaar #include <dev/uart/uart.h> 56*27d5dc18SMarcel Moolenaar #include <dev/uart/uart_bus.h> 57*27d5dc18SMarcel Moolenaar #include <dev/uart/uart_cpu.h> 58*27d5dc18SMarcel Moolenaar 59*27d5dc18SMarcel Moolenaar #include "uart_if.h" 60*27d5dc18SMarcel Moolenaar 61*27d5dc18SMarcel Moolenaar devclass_t uart_devclass; 62*27d5dc18SMarcel Moolenaar char uart_driver_name[] = "uart"; 63*27d5dc18SMarcel Moolenaar 64*27d5dc18SMarcel Moolenaar SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs = 65*27d5dc18SMarcel Moolenaar SLIST_HEAD_INITIALIZER(uart_sysdevs); 66*27d5dc18SMarcel Moolenaar 67*27d5dc18SMarcel Moolenaar MALLOC_DEFINE(M_UART, "UART", "UART driver"); 68*27d5dc18SMarcel Moolenaar 69*27d5dc18SMarcel Moolenaar void 70*27d5dc18SMarcel Moolenaar uart_add_sysdev(struct uart_devinfo *di) 71*27d5dc18SMarcel Moolenaar { 72*27d5dc18SMarcel Moolenaar SLIST_INSERT_HEAD(&uart_sysdevs, di, next); 73*27d5dc18SMarcel Moolenaar } 74*27d5dc18SMarcel Moolenaar 75*27d5dc18SMarcel Moolenaar /* 76*27d5dc18SMarcel Moolenaar * A break condition has been detected. We treat the break condition as 77*27d5dc18SMarcel Moolenaar * a special case that should not happen during normal operation. When 78*27d5dc18SMarcel Moolenaar * the break condition is to be passed to higher levels in the form of 79*27d5dc18SMarcel Moolenaar * a NUL character, we really want the break to be in the right place in 80*27d5dc18SMarcel Moolenaar * the input stream. The overhead to achieve that is not in relation to 81*27d5dc18SMarcel Moolenaar * the exceptional nature of the break condition, so we permit ourselves 82*27d5dc18SMarcel Moolenaar * to be sloppy. 83*27d5dc18SMarcel Moolenaar */ 84*27d5dc18SMarcel Moolenaar static void 85*27d5dc18SMarcel Moolenaar uart_intr_break(struct uart_softc *sc) 86*27d5dc18SMarcel Moolenaar { 87*27d5dc18SMarcel Moolenaar 88*27d5dc18SMarcel Moolenaar #if defined(DDB) && defined(BREAK_TO_DEBUGGER) 89*27d5dc18SMarcel Moolenaar if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { 90*27d5dc18SMarcel Moolenaar breakpoint(); 91*27d5dc18SMarcel Moolenaar return; 92*27d5dc18SMarcel Moolenaar } 93*27d5dc18SMarcel Moolenaar #endif 94*27d5dc18SMarcel Moolenaar if (sc->sc_opened) 95*27d5dc18SMarcel Moolenaar atomic_set_32(&sc->sc_ttypend, UART_IPEND_BREAK); 96*27d5dc18SMarcel Moolenaar } 97*27d5dc18SMarcel Moolenaar 98*27d5dc18SMarcel Moolenaar /* 99*27d5dc18SMarcel Moolenaar * Handle a receiver overrun situation. We lost at least 1 byte in the 100*27d5dc18SMarcel Moolenaar * input stream and it's our job to contain the situation. We grab as 101*27d5dc18SMarcel Moolenaar * much of the data we can, but otherwise flush the receiver FIFO to 102*27d5dc18SMarcel Moolenaar * create some breathing room. The net effect is that we avoid the 103*27d5dc18SMarcel Moolenaar * overrun condition to happen for the next X characters, where X is 104*27d5dc18SMarcel Moolenaar * related to the FIFO size at the cost of loosing data right away. 105*27d5dc18SMarcel Moolenaar * So, instead of having multiple overrun interrupts in close proximity 106*27d5dc18SMarcel Moolenaar * to each other and possibly pessimizing UART interrupt latency for 107*27d5dc18SMarcel Moolenaar * other UARTs in a multiport configuration, we create a longer segment 108*27d5dc18SMarcel Moolenaar * of missing characters by freeing up the FIFO. 109*27d5dc18SMarcel Moolenaar * Each overrun condition is marked in the input buffer by a token. The 110*27d5dc18SMarcel Moolenaar * token represents the loss of at least one, but possible more bytes in 111*27d5dc18SMarcel Moolenaar * the input stream. 112*27d5dc18SMarcel Moolenaar */ 113*27d5dc18SMarcel Moolenaar static void 114*27d5dc18SMarcel Moolenaar uart_intr_overrun(struct uart_softc *sc) 115*27d5dc18SMarcel Moolenaar { 116*27d5dc18SMarcel Moolenaar 117*27d5dc18SMarcel Moolenaar if (sc->sc_opened) { 118*27d5dc18SMarcel Moolenaar UART_RECEIVE(sc); 119*27d5dc18SMarcel Moolenaar if (uart_rx_put(sc, UART_STAT_OVERRUN)) 120*27d5dc18SMarcel Moolenaar sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 121*27d5dc18SMarcel Moolenaar atomic_set_32(&sc->sc_ttypend, UART_IPEND_RXREADY); 122*27d5dc18SMarcel Moolenaar } 123*27d5dc18SMarcel Moolenaar UART_FLUSH(sc, UART_FLUSH_RECEIVER); 124*27d5dc18SMarcel Moolenaar } 125*27d5dc18SMarcel Moolenaar 126*27d5dc18SMarcel Moolenaar /* 127*27d5dc18SMarcel Moolenaar * Received data ready. 128*27d5dc18SMarcel Moolenaar */ 129*27d5dc18SMarcel Moolenaar static void 130*27d5dc18SMarcel Moolenaar uart_intr_rxready(struct uart_softc *sc) 131*27d5dc18SMarcel Moolenaar { 132*27d5dc18SMarcel Moolenaar int rxp; 133*27d5dc18SMarcel Moolenaar 134*27d5dc18SMarcel Moolenaar rxp = sc->sc_rxput; 135*27d5dc18SMarcel Moolenaar UART_RECEIVE(sc); 136*27d5dc18SMarcel Moolenaar #if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER) 137*27d5dc18SMarcel Moolenaar if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { 138*27d5dc18SMarcel Moolenaar while (rxp != sc->sc_rxput) { 139*27d5dc18SMarcel Moolenaar if (db_alt_break(sc->sc_rxbuf[rxp++], &sc->sc_altbrk)) 140*27d5dc18SMarcel Moolenaar breakpoint(); 141*27d5dc18SMarcel Moolenaar if (rxp == sc->sc_rxbufsz) 142*27d5dc18SMarcel Moolenaar rxp = 0; 143*27d5dc18SMarcel Moolenaar } 144*27d5dc18SMarcel Moolenaar } 145*27d5dc18SMarcel Moolenaar #endif 146*27d5dc18SMarcel Moolenaar if (sc->sc_opened) 147*27d5dc18SMarcel Moolenaar atomic_set_32(&sc->sc_ttypend, UART_IPEND_RXREADY); 148*27d5dc18SMarcel Moolenaar else 149*27d5dc18SMarcel Moolenaar sc->sc_rxput = sc->sc_rxget; /* Ignore received data. */ 150*27d5dc18SMarcel Moolenaar } 151*27d5dc18SMarcel Moolenaar 152*27d5dc18SMarcel Moolenaar /* 153*27d5dc18SMarcel Moolenaar * Line or modem status change (OOB signalling). 154*27d5dc18SMarcel Moolenaar * We pass the signals to the software interrupt handler for further 155*27d5dc18SMarcel Moolenaar * processing. Note that we merge the delta bits, but set the state 156*27d5dc18SMarcel Moolenaar * bits. This is to avoid loosing state transitions due to having more 157*27d5dc18SMarcel Moolenaar * than 1 hardware interrupt between software interrupts. 158*27d5dc18SMarcel Moolenaar */ 159*27d5dc18SMarcel Moolenaar static void 160*27d5dc18SMarcel Moolenaar uart_intr_sigchg(struct uart_softc *sc) 161*27d5dc18SMarcel Moolenaar { 162*27d5dc18SMarcel Moolenaar int new, old, sig; 163*27d5dc18SMarcel Moolenaar 164*27d5dc18SMarcel Moolenaar sig = UART_GETSIG(sc); 165*27d5dc18SMarcel Moolenaar do { 166*27d5dc18SMarcel Moolenaar old = sc->sc_ttypend; 167*27d5dc18SMarcel Moolenaar new = old & ~UART_SIGMASK_STATE; 168*27d5dc18SMarcel Moolenaar new |= sig & UART_IPEND_SIGMASK; 169*27d5dc18SMarcel Moolenaar new |= UART_IPEND_SIGCHG; 170*27d5dc18SMarcel Moolenaar } while (!atomic_cmpset_32(&sc->sc_ttypend, old, new)); 171*27d5dc18SMarcel Moolenaar } 172*27d5dc18SMarcel Moolenaar 173*27d5dc18SMarcel Moolenaar /* 174*27d5dc18SMarcel Moolenaar * The transmitter can accept more data. 175*27d5dc18SMarcel Moolenaar */ 176*27d5dc18SMarcel Moolenaar static void 177*27d5dc18SMarcel Moolenaar uart_intr_txidle(struct uart_softc *sc) 178*27d5dc18SMarcel Moolenaar { 179*27d5dc18SMarcel Moolenaar if (sc->sc_txbusy) { 180*27d5dc18SMarcel Moolenaar sc->sc_txbusy = 0; 181*27d5dc18SMarcel Moolenaar atomic_set_32(&sc->sc_ttypend, UART_IPEND_TXIDLE); 182*27d5dc18SMarcel Moolenaar } 183*27d5dc18SMarcel Moolenaar } 184*27d5dc18SMarcel Moolenaar 185*27d5dc18SMarcel Moolenaar static void 186*27d5dc18SMarcel Moolenaar uart_intr(void *arg) 187*27d5dc18SMarcel Moolenaar { 188*27d5dc18SMarcel Moolenaar struct uart_softc *sc = arg; 189*27d5dc18SMarcel Moolenaar int ipend; 190*27d5dc18SMarcel Moolenaar 191*27d5dc18SMarcel Moolenaar if (sc->sc_leaving) 192*27d5dc18SMarcel Moolenaar return; 193*27d5dc18SMarcel Moolenaar 194*27d5dc18SMarcel Moolenaar ipend = UART_IPEND(sc); 195*27d5dc18SMarcel Moolenaar if (ipend & UART_IPEND_OVERRUN) 196*27d5dc18SMarcel Moolenaar uart_intr_overrun(sc); 197*27d5dc18SMarcel Moolenaar if (ipend & UART_IPEND_BREAK) 198*27d5dc18SMarcel Moolenaar uart_intr_break(sc); 199*27d5dc18SMarcel Moolenaar if (ipend & UART_IPEND_RXREADY) 200*27d5dc18SMarcel Moolenaar uart_intr_rxready(sc); 201*27d5dc18SMarcel Moolenaar if (ipend & UART_IPEND_SIGCHG) 202*27d5dc18SMarcel Moolenaar uart_intr_sigchg(sc); 203*27d5dc18SMarcel Moolenaar if (ipend & UART_IPEND_TXIDLE) 204*27d5dc18SMarcel Moolenaar uart_intr_txidle(sc); 205*27d5dc18SMarcel Moolenaar 206*27d5dc18SMarcel Moolenaar if (sc->sc_opened && sc->sc_ttypend != 0) 207*27d5dc18SMarcel Moolenaar swi_sched(sc->sc_softih, 0); 208*27d5dc18SMarcel Moolenaar } 209*27d5dc18SMarcel Moolenaar 210*27d5dc18SMarcel Moolenaar int 211*27d5dc18SMarcel Moolenaar uart_bus_probe(device_t dev, int regshft, int rclk, int rid) 212*27d5dc18SMarcel Moolenaar { 213*27d5dc18SMarcel Moolenaar struct uart_softc *sc; 214*27d5dc18SMarcel Moolenaar struct uart_devinfo *sysdev; 215*27d5dc18SMarcel Moolenaar int error; 216*27d5dc18SMarcel Moolenaar 217*27d5dc18SMarcel Moolenaar /* 218*27d5dc18SMarcel Moolenaar * Initialize the instance. Note that the instance (=softc) does 219*27d5dc18SMarcel Moolenaar * not necessarily match the hardware specific softc. We can't do 220*27d5dc18SMarcel Moolenaar * anything about it now, because we may not attach to the device. 221*27d5dc18SMarcel Moolenaar * Hardware drivers cannot use any of the class specific fields 222*27d5dc18SMarcel Moolenaar * while probing. 223*27d5dc18SMarcel Moolenaar */ 224*27d5dc18SMarcel Moolenaar sc = device_get_softc(dev); 225*27d5dc18SMarcel Moolenaar kobj_init((kobj_t)sc, (kobj_class_t)sc->sc_class); 226*27d5dc18SMarcel Moolenaar sc->sc_dev = dev; 227*27d5dc18SMarcel Moolenaar if (device_get_desc(dev) == NULL) 228*27d5dc18SMarcel Moolenaar device_set_desc(dev, sc->sc_class->name); 229*27d5dc18SMarcel Moolenaar 230*27d5dc18SMarcel Moolenaar /* 231*27d5dc18SMarcel Moolenaar * Allocate the register resource. We assume that all UARTs have 232*27d5dc18SMarcel Moolenaar * a single register window in either I/O port space or memory 233*27d5dc18SMarcel Moolenaar * mapped I/O space. Any UART that needs multiple windows will 234*27d5dc18SMarcel Moolenaar * consequently not be supported by this driver as-is. We try I/O 235*27d5dc18SMarcel Moolenaar * port space first because that's the common case. 236*27d5dc18SMarcel Moolenaar */ 237*27d5dc18SMarcel Moolenaar sc->sc_rrid = rid; 238*27d5dc18SMarcel Moolenaar sc->sc_rtype = SYS_RES_IOPORT; 239*27d5dc18SMarcel Moolenaar sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid, 240*27d5dc18SMarcel Moolenaar 0, ~0, sc->sc_class->uc_range, RF_ACTIVE); 241*27d5dc18SMarcel Moolenaar if (sc->sc_rres == NULL) { 242*27d5dc18SMarcel Moolenaar sc->sc_rrid = rid; 243*27d5dc18SMarcel Moolenaar sc->sc_rtype = SYS_RES_MEMORY; 244*27d5dc18SMarcel Moolenaar sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, 245*27d5dc18SMarcel Moolenaar &sc->sc_rrid, 0, ~0, sc->sc_class->uc_range, RF_ACTIVE); 246*27d5dc18SMarcel Moolenaar if (sc->sc_rres == NULL) 247*27d5dc18SMarcel Moolenaar return (ENXIO); 248*27d5dc18SMarcel Moolenaar } 249*27d5dc18SMarcel Moolenaar 250*27d5dc18SMarcel Moolenaar /* 251*27d5dc18SMarcel Moolenaar * Fill in the bus access structure and compare this device with 252*27d5dc18SMarcel Moolenaar * a possible console device and/or a debug port. We set the flags 253*27d5dc18SMarcel Moolenaar * in the softc so that the hardware dependent probe can adjust 254*27d5dc18SMarcel Moolenaar * accordingly. In general, you don't want to permanently disrupt 255*27d5dc18SMarcel Moolenaar * console I/O. 256*27d5dc18SMarcel Moolenaar */ 257*27d5dc18SMarcel Moolenaar sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres); 258*27d5dc18SMarcel Moolenaar sc->sc_bas.bst = rman_get_bustag(sc->sc_rres); 259*27d5dc18SMarcel Moolenaar sc->sc_bas.regshft = regshft; 260*27d5dc18SMarcel Moolenaar sc->sc_bas.rclk = (rclk == 0) ? sc->sc_class->uc_rclk : rclk; 261*27d5dc18SMarcel Moolenaar 262*27d5dc18SMarcel Moolenaar SLIST_FOREACH(sysdev, &uart_sysdevs, next) { 263*27d5dc18SMarcel Moolenaar if (uart_cpu_eqres(&sc->sc_bas, &sysdev->bas)) { 264*27d5dc18SMarcel Moolenaar /* XXX check if ops matches class. */ 265*27d5dc18SMarcel Moolenaar sc->sc_sysdev = sysdev; 266*27d5dc18SMarcel Moolenaar break; 267*27d5dc18SMarcel Moolenaar } 268*27d5dc18SMarcel Moolenaar } 269*27d5dc18SMarcel Moolenaar 270*27d5dc18SMarcel Moolenaar error = UART_PROBE(sc); 271*27d5dc18SMarcel Moolenaar bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres); 272*27d5dc18SMarcel Moolenaar return (error); 273*27d5dc18SMarcel Moolenaar } 274*27d5dc18SMarcel Moolenaar 275*27d5dc18SMarcel Moolenaar int 276*27d5dc18SMarcel Moolenaar uart_bus_attach(device_t dev) 277*27d5dc18SMarcel Moolenaar { 278*27d5dc18SMarcel Moolenaar struct uart_softc *sc, *sc0; 279*27d5dc18SMarcel Moolenaar const char *sep; 280*27d5dc18SMarcel Moolenaar int error; 281*27d5dc18SMarcel Moolenaar 282*27d5dc18SMarcel Moolenaar /* 283*27d5dc18SMarcel Moolenaar * The sc_class field defines the type of UART we're going to work 284*27d5dc18SMarcel Moolenaar * with and thus the size of the softc. Replace the generic softc 285*27d5dc18SMarcel Moolenaar * with one that matches the UART now that we're certain we handle 286*27d5dc18SMarcel Moolenaar * the device. 287*27d5dc18SMarcel Moolenaar */ 288*27d5dc18SMarcel Moolenaar sc0 = device_get_softc(dev); 289*27d5dc18SMarcel Moolenaar if (sc0->sc_class->size > sizeof(*sc)) { 290*27d5dc18SMarcel Moolenaar sc = malloc(sc0->sc_class->size, M_UART, M_WAITOK|M_ZERO); 291*27d5dc18SMarcel Moolenaar bcopy(sc0, sc, sizeof(*sc)); 292*27d5dc18SMarcel Moolenaar device_set_softc(dev, sc); 293*27d5dc18SMarcel Moolenaar } else 294*27d5dc18SMarcel Moolenaar sc = sc0; 295*27d5dc18SMarcel Moolenaar 296*27d5dc18SMarcel Moolenaar /* 297*27d5dc18SMarcel Moolenaar * Protect ourselves against interrupts while we're not completely 298*27d5dc18SMarcel Moolenaar * finished attaching and initializing. We don't expect interrupts 299*27d5dc18SMarcel Moolenaar * until after UART_ATTACH() though. 300*27d5dc18SMarcel Moolenaar */ 301*27d5dc18SMarcel Moolenaar sc->sc_leaving = 1; 302*27d5dc18SMarcel Moolenaar 303*27d5dc18SMarcel Moolenaar /* 304*27d5dc18SMarcel Moolenaar * Re-allocate. We expect that the softc contains the information 305*27d5dc18SMarcel Moolenaar * collected by uart_bus_probe() intact. 306*27d5dc18SMarcel Moolenaar */ 307*27d5dc18SMarcel Moolenaar sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid, 308*27d5dc18SMarcel Moolenaar 0, ~0, sc->sc_class->uc_range, RF_ACTIVE); 309*27d5dc18SMarcel Moolenaar if (sc->sc_rres == NULL) 310*27d5dc18SMarcel Moolenaar return (ENXIO); 311*27d5dc18SMarcel Moolenaar 312*27d5dc18SMarcel Moolenaar sc->sc_irid = 0; 313*27d5dc18SMarcel Moolenaar sc->sc_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_irid, 314*27d5dc18SMarcel Moolenaar 0, ~0, 1, RF_ACTIVE); 315*27d5dc18SMarcel Moolenaar if (sc->sc_ires != NULL) { 316*27d5dc18SMarcel Moolenaar error = BUS_SETUP_INTR(device_get_parent(dev), dev, 317*27d5dc18SMarcel Moolenaar sc->sc_ires, INTR_TYPE_TTY | INTR_FAST, uart_intr, 318*27d5dc18SMarcel Moolenaar sc, &sc->sc_icookie); 319*27d5dc18SMarcel Moolenaar if (error) 320*27d5dc18SMarcel Moolenaar error = BUS_SETUP_INTR(device_get_parent(dev), dev, 321*27d5dc18SMarcel Moolenaar sc->sc_ires, INTR_TYPE_TTY, uart_intr, sc, 322*27d5dc18SMarcel Moolenaar &sc->sc_icookie); 323*27d5dc18SMarcel Moolenaar else 324*27d5dc18SMarcel Moolenaar sc->sc_fastintr = 1; 325*27d5dc18SMarcel Moolenaar 326*27d5dc18SMarcel Moolenaar if (error) { 327*27d5dc18SMarcel Moolenaar device_printf(dev, "could not activate interrupt\n"); 328*27d5dc18SMarcel Moolenaar bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 329*27d5dc18SMarcel Moolenaar sc->sc_ires); 330*27d5dc18SMarcel Moolenaar sc->sc_ires = NULL; 331*27d5dc18SMarcel Moolenaar } 332*27d5dc18SMarcel Moolenaar } 333*27d5dc18SMarcel Moolenaar if (sc->sc_ires == NULL) { 334*27d5dc18SMarcel Moolenaar /* XXX no interrupt resource. Force polled mode. */ 335*27d5dc18SMarcel Moolenaar sc->sc_polled = 1; 336*27d5dc18SMarcel Moolenaar } 337*27d5dc18SMarcel Moolenaar 338*27d5dc18SMarcel Moolenaar sc->sc_rxbufsz = IBUFSIZ; 339*27d5dc18SMarcel Moolenaar sc->sc_rxbuf = malloc(sc->sc_rxbufsz * sizeof(*sc->sc_rxbuf), 340*27d5dc18SMarcel Moolenaar M_UART, M_WAITOK); 341*27d5dc18SMarcel Moolenaar sc->sc_txbuf = malloc(sc->sc_txfifosz * sizeof(*sc->sc_txbuf), 342*27d5dc18SMarcel Moolenaar M_UART, M_WAITOK); 343*27d5dc18SMarcel Moolenaar 344*27d5dc18SMarcel Moolenaar error = UART_ATTACH(sc); 345*27d5dc18SMarcel Moolenaar if (error) 346*27d5dc18SMarcel Moolenaar goto fail; 347*27d5dc18SMarcel Moolenaar 348*27d5dc18SMarcel Moolenaar if (sc->sc_hwiflow || sc->sc_hwoflow) { 349*27d5dc18SMarcel Moolenaar sep = ""; 350*27d5dc18SMarcel Moolenaar device_print_prettyname(dev); 351*27d5dc18SMarcel Moolenaar if (sc->sc_hwiflow) { 352*27d5dc18SMarcel Moolenaar printf("%sRTS iflow", sep); 353*27d5dc18SMarcel Moolenaar sep = ", "; 354*27d5dc18SMarcel Moolenaar } 355*27d5dc18SMarcel Moolenaar if (sc->sc_hwoflow) { 356*27d5dc18SMarcel Moolenaar printf("%sCTS oflow", sep); 357*27d5dc18SMarcel Moolenaar sep = ", "; 358*27d5dc18SMarcel Moolenaar } 359*27d5dc18SMarcel Moolenaar printf("\n"); 360*27d5dc18SMarcel Moolenaar } 361*27d5dc18SMarcel Moolenaar 362*27d5dc18SMarcel Moolenaar if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) { 363*27d5dc18SMarcel Moolenaar sep = ""; 364*27d5dc18SMarcel Moolenaar device_print_prettyname(dev); 365*27d5dc18SMarcel Moolenaar if (sc->sc_fastintr) { 366*27d5dc18SMarcel Moolenaar printf("%sfast interrupt", sep); 367*27d5dc18SMarcel Moolenaar sep = ", "; 368*27d5dc18SMarcel Moolenaar } 369*27d5dc18SMarcel Moolenaar if (sc->sc_polled) { 370*27d5dc18SMarcel Moolenaar printf("%spolled mode", sep); 371*27d5dc18SMarcel Moolenaar sep = ", "; 372*27d5dc18SMarcel Moolenaar } 373*27d5dc18SMarcel Moolenaar printf("\n"); 374*27d5dc18SMarcel Moolenaar } 375*27d5dc18SMarcel Moolenaar 376*27d5dc18SMarcel Moolenaar if (sc->sc_sysdev != NULL) { 377*27d5dc18SMarcel Moolenaar switch (sc->sc_sysdev->type) { 378*27d5dc18SMarcel Moolenaar case UART_DEV_CONSOLE: 379*27d5dc18SMarcel Moolenaar device_printf(dev, "console"); 380*27d5dc18SMarcel Moolenaar break; 381*27d5dc18SMarcel Moolenaar case UART_DEV_DBGPORT: 382*27d5dc18SMarcel Moolenaar device_printf(dev, "debug port"); 383*27d5dc18SMarcel Moolenaar break; 384*27d5dc18SMarcel Moolenaar case UART_DEV_KEYBOARD: 385*27d5dc18SMarcel Moolenaar device_printf(dev, "keyboard"); 386*27d5dc18SMarcel Moolenaar break; 387*27d5dc18SMarcel Moolenaar default: 388*27d5dc18SMarcel Moolenaar device_printf(dev, "unknown system device"); 389*27d5dc18SMarcel Moolenaar break; 390*27d5dc18SMarcel Moolenaar } 391*27d5dc18SMarcel Moolenaar printf(" (%d,%c,%d,%d)\n", sc->sc_sysdev->baudrate, 392*27d5dc18SMarcel Moolenaar "noems"[sc->sc_sysdev->parity], sc->sc_sysdev->databits, 393*27d5dc18SMarcel Moolenaar sc->sc_sysdev->stopbits); 394*27d5dc18SMarcel Moolenaar } 395*27d5dc18SMarcel Moolenaar 396*27d5dc18SMarcel Moolenaar error = (sc->sc_sysdev != NULL && sc->sc_sysdev->attach != NULL) 397*27d5dc18SMarcel Moolenaar ? (*sc->sc_sysdev->attach)(sc) : uart_tty_attach(sc); 398*27d5dc18SMarcel Moolenaar if (error) 399*27d5dc18SMarcel Moolenaar goto fail; 400*27d5dc18SMarcel Moolenaar 401*27d5dc18SMarcel Moolenaar sc->sc_leaving = 0; 402*27d5dc18SMarcel Moolenaar uart_intr(sc); 403*27d5dc18SMarcel Moolenaar return (0); 404*27d5dc18SMarcel Moolenaar 405*27d5dc18SMarcel Moolenaar fail: 406*27d5dc18SMarcel Moolenaar free(sc->sc_txbuf, M_UART); 407*27d5dc18SMarcel Moolenaar free(sc->sc_rxbuf, M_UART); 408*27d5dc18SMarcel Moolenaar 409*27d5dc18SMarcel Moolenaar if (sc->sc_ires != NULL) { 410*27d5dc18SMarcel Moolenaar bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie); 411*27d5dc18SMarcel Moolenaar bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 412*27d5dc18SMarcel Moolenaar sc->sc_ires); 413*27d5dc18SMarcel Moolenaar } 414*27d5dc18SMarcel Moolenaar bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres); 415*27d5dc18SMarcel Moolenaar 416*27d5dc18SMarcel Moolenaar return (error); 417*27d5dc18SMarcel Moolenaar } 418*27d5dc18SMarcel Moolenaar 419*27d5dc18SMarcel Moolenaar int 420*27d5dc18SMarcel Moolenaar uart_bus_detach(device_t dev) 421*27d5dc18SMarcel Moolenaar { 422*27d5dc18SMarcel Moolenaar struct uart_softc *sc; 423*27d5dc18SMarcel Moolenaar 424*27d5dc18SMarcel Moolenaar sc = device_get_softc(dev); 425*27d5dc18SMarcel Moolenaar 426*27d5dc18SMarcel Moolenaar sc->sc_leaving = 1; 427*27d5dc18SMarcel Moolenaar 428*27d5dc18SMarcel Moolenaar UART_DETACH(sc); 429*27d5dc18SMarcel Moolenaar 430*27d5dc18SMarcel Moolenaar if (sc->sc_sysdev != NULL && sc->sc_sysdev->detach != NULL) 431*27d5dc18SMarcel Moolenaar (*sc->sc_sysdev->detach)(sc); 432*27d5dc18SMarcel Moolenaar else 433*27d5dc18SMarcel Moolenaar uart_tty_detach(sc); 434*27d5dc18SMarcel Moolenaar 435*27d5dc18SMarcel Moolenaar free(sc->sc_txbuf, M_UART); 436*27d5dc18SMarcel Moolenaar free(sc->sc_rxbuf, M_UART); 437*27d5dc18SMarcel Moolenaar 438*27d5dc18SMarcel Moolenaar if (sc->sc_ires != NULL) { 439*27d5dc18SMarcel Moolenaar bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie); 440*27d5dc18SMarcel Moolenaar bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 441*27d5dc18SMarcel Moolenaar sc->sc_ires); 442*27d5dc18SMarcel Moolenaar } 443*27d5dc18SMarcel Moolenaar bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres); 444*27d5dc18SMarcel Moolenaar 445*27d5dc18SMarcel Moolenaar if (sc->sc_class->size > sizeof(*sc)) { 446*27d5dc18SMarcel Moolenaar device_set_softc(dev, NULL); 447*27d5dc18SMarcel Moolenaar free(sc, M_UART); 448*27d5dc18SMarcel Moolenaar } else 449*27d5dc18SMarcel Moolenaar device_set_softc(dev, NULL); 450*27d5dc18SMarcel Moolenaar 451*27d5dc18SMarcel Moolenaar return (0); 452*27d5dc18SMarcel Moolenaar } 453