uart_core.c revision 234194
1139749Simp/*- 2119815Smarcel * Copyright (c) 2003 Marcel Moolenaar 3119815Smarcel * All rights reserved. 4119815Smarcel * 5119815Smarcel * Redistribution and use in source and binary forms, with or without 6119815Smarcel * modification, are permitted provided that the following conditions 7119815Smarcel * are met: 8119815Smarcel * 9119815Smarcel * 1. Redistributions of source code must retain the above copyright 10119815Smarcel * notice, this list of conditions and the following disclaimer. 11119815Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12119815Smarcel * notice, this list of conditions and the following disclaimer in the 13119815Smarcel * documentation and/or other materials provided with the distribution. 14119815Smarcel * 15119815Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16119815Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17119815Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18119815Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19119815Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20119815Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21119815Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22119815Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23119815Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24119815Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25119815Smarcel */ 26119815Smarcel 27119815Smarcel#include <sys/cdefs.h> 28119815Smarcel__FBSDID("$FreeBSD: head/sys/dev/uart/uart_core.c 234194 2012-04-12 18:46:48Z grehan $"); 29119815Smarcel 30119815Smarcel#include <sys/param.h> 31119815Smarcel#include <sys/systm.h> 32119815Smarcel#include <sys/bus.h> 33119815Smarcel#include <sys/conf.h> 34119815Smarcel#include <sys/cons.h> 35119815Smarcel#include <sys/fcntl.h> 36119815Smarcel#include <sys/interrupt.h> 37131921Smarcel#include <sys/kdb.h> 38119815Smarcel#include <sys/kernel.h> 39119815Smarcel#include <sys/malloc.h> 40119815Smarcel#include <sys/queue.h> 41119815Smarcel#include <sys/reboot.h> 42119815Smarcel#include <machine/bus.h> 43119815Smarcel#include <sys/rman.h> 44119815Smarcel#include <machine/resource.h> 45119815Smarcel#include <machine/stdarg.h> 46119815Smarcel 47119815Smarcel#include <dev/uart/uart.h> 48119815Smarcel#include <dev/uart/uart_bus.h> 49119815Smarcel#include <dev/uart/uart_cpu.h> 50119815Smarcel 51119815Smarcel#include "uart_if.h" 52119815Smarcel 53119815Smarceldevclass_t uart_devclass; 54119815Smarcelchar uart_driver_name[] = "uart"; 55119815Smarcel 56119815SmarcelSLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs = 57119815Smarcel SLIST_HEAD_INITIALIZER(uart_sysdevs); 58119815Smarcel 59227293Sedstatic MALLOC_DEFINE(M_UART, "UART", "UART driver"); 60119815Smarcel 61234194Sgrehan#ifndef UART_POLL_FREQ 62234194Sgrehan#define UART_POLL_FREQ 50 63234194Sgrehan#endif 64234194Sgrehanstatic int uart_poll_freq = UART_POLL_FREQ; 65234194SgrehanTUNABLE_INT("debug.uart_poll_freq", &uart_poll_freq); 66234194Sgrehan 67119815Smarcelvoid 68119815Smarceluart_add_sysdev(struct uart_devinfo *di) 69119815Smarcel{ 70119815Smarcel SLIST_INSERT_HEAD(&uart_sysdevs, di, next); 71119815Smarcel} 72119815Smarcel 73168281Smarcelconst char * 74168281Smarceluart_getname(struct uart_class *uc) 75168281Smarcel{ 76168281Smarcel return ((uc != NULL) ? uc->name : NULL); 77168281Smarcel} 78168281Smarcel 79168281Smarcelstruct uart_ops * 80168281Smarceluart_getops(struct uart_class *uc) 81168281Smarcel{ 82168281Smarcel return ((uc != NULL) ? uc->uc_ops : NULL); 83168281Smarcel} 84168281Smarcel 85168281Smarcelint 86168281Smarceluart_getrange(struct uart_class *uc) 87168281Smarcel{ 88168281Smarcel return ((uc != NULL) ? uc->uc_range : 0); 89168281Smarcel} 90168281Smarcel 91119815Smarcel/* 92157300Smarcel * Schedule a soft interrupt. We do this on the 0 to !0 transition 93157300Smarcel * of the TTY pending interrupt status. 94157300Smarcel */ 95197721Smarcelvoid 96157300Smarceluart_sched_softih(struct uart_softc *sc, uint32_t ipend) 97157300Smarcel{ 98157300Smarcel uint32_t new, old; 99157300Smarcel 100157300Smarcel do { 101157300Smarcel old = sc->sc_ttypend; 102157300Smarcel new = old | ipend; 103157300Smarcel } while (!atomic_cmpset_32(&sc->sc_ttypend, old, new)); 104157300Smarcel 105157300Smarcel if ((old & SER_INT_MASK) == 0) 106157300Smarcel swi_sched(sc->sc_softih, 0); 107157300Smarcel} 108157300Smarcel 109157300Smarcel/* 110119815Smarcel * A break condition has been detected. We treat the break condition as 111119815Smarcel * a special case that should not happen during normal operation. When 112119815Smarcel * the break condition is to be passed to higher levels in the form of 113119815Smarcel * a NUL character, we really want the break to be in the right place in 114119815Smarcel * the input stream. The overhead to achieve that is not in relation to 115119815Smarcel * the exceptional nature of the break condition, so we permit ourselves 116119815Smarcel * to be sloppy. 117119815Smarcel */ 118157300Smarcelstatic __inline int 119157300Smarceluart_intr_break(void *arg) 120119815Smarcel{ 121157300Smarcel struct uart_softc *sc = arg; 122119815Smarcel 123225203Srwatson#if defined(KDB) 124119815Smarcel if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { 125225203Srwatson if (kdb_break()) 126225203Srwatson return (0); 127119815Smarcel } 128119815Smarcel#endif 129119815Smarcel if (sc->sc_opened) 130157300Smarcel uart_sched_softih(sc, SER_INT_BREAK); 131157300Smarcel return (0); 132119815Smarcel} 133119815Smarcel 134119815Smarcel/* 135119815Smarcel * Handle a receiver overrun situation. We lost at least 1 byte in the 136119815Smarcel * input stream and it's our job to contain the situation. We grab as 137119815Smarcel * much of the data we can, but otherwise flush the receiver FIFO to 138119815Smarcel * create some breathing room. The net effect is that we avoid the 139119815Smarcel * overrun condition to happen for the next X characters, where X is 140119815Smarcel * related to the FIFO size at the cost of loosing data right away. 141119815Smarcel * So, instead of having multiple overrun interrupts in close proximity 142119815Smarcel * to each other and possibly pessimizing UART interrupt latency for 143119815Smarcel * other UARTs in a multiport configuration, we create a longer segment 144119815Smarcel * of missing characters by freeing up the FIFO. 145119815Smarcel * Each overrun condition is marked in the input buffer by a token. The 146119815Smarcel * token represents the loss of at least one, but possible more bytes in 147119815Smarcel * the input stream. 148119815Smarcel */ 149157300Smarcelstatic __inline int 150157300Smarceluart_intr_overrun(void *arg) 151119815Smarcel{ 152157300Smarcel struct uart_softc *sc = arg; 153119815Smarcel 154119815Smarcel if (sc->sc_opened) { 155119815Smarcel UART_RECEIVE(sc); 156119815Smarcel if (uart_rx_put(sc, UART_STAT_OVERRUN)) 157119815Smarcel sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 158157300Smarcel uart_sched_softih(sc, SER_INT_RXREADY); 159119815Smarcel } 160119815Smarcel UART_FLUSH(sc, UART_FLUSH_RECEIVER); 161157300Smarcel return (0); 162119815Smarcel} 163119815Smarcel 164119815Smarcel/* 165119815Smarcel * Received data ready. 166119815Smarcel */ 167157300Smarcelstatic __inline int 168157300Smarceluart_intr_rxready(void *arg) 169119815Smarcel{ 170157300Smarcel struct uart_softc *sc = arg; 171119815Smarcel int rxp; 172119815Smarcel 173119815Smarcel rxp = sc->sc_rxput; 174119815Smarcel UART_RECEIVE(sc); 175225203Srwatson#if defined(KDB) 176119815Smarcel if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { 177119815Smarcel while (rxp != sc->sc_rxput) { 178225203Srwatson kdb_alt_break(sc->sc_rxbuf[rxp++], &sc->sc_altbrk); 179119815Smarcel if (rxp == sc->sc_rxbufsz) 180119815Smarcel rxp = 0; 181119815Smarcel } 182119815Smarcel } 183119815Smarcel#endif 184119815Smarcel if (sc->sc_opened) 185157300Smarcel uart_sched_softih(sc, SER_INT_RXREADY); 186119815Smarcel else 187119815Smarcel sc->sc_rxput = sc->sc_rxget; /* Ignore received data. */ 188157300Smarcel return (1); 189119815Smarcel} 190119815Smarcel 191119815Smarcel/* 192119815Smarcel * Line or modem status change (OOB signalling). 193119815Smarcel * We pass the signals to the software interrupt handler for further 194119815Smarcel * processing. Note that we merge the delta bits, but set the state 195119815Smarcel * bits. This is to avoid loosing state transitions due to having more 196119815Smarcel * than 1 hardware interrupt between software interrupts. 197119815Smarcel */ 198157300Smarcelstatic __inline int 199157300Smarceluart_intr_sigchg(void *arg) 200119815Smarcel{ 201157300Smarcel struct uart_softc *sc = arg; 202119815Smarcel int new, old, sig; 203119815Smarcel 204119815Smarcel sig = UART_GETSIG(sc); 205119996Smarcel 206119996Smarcel if (sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) { 207119996Smarcel if (sig & UART_SIG_DPPS) { 208119996Smarcel pps_capture(&sc->sc_pps); 209119996Smarcel pps_event(&sc->sc_pps, (sig & UART_SIG_PPS) ? 210119996Smarcel PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); 211119996Smarcel } 212119996Smarcel } 213119996Smarcel 214157300Smarcel /* 215157300Smarcel * Keep track of signal changes, even when the device is not 216157300Smarcel * opened. This allows us to inform upper layers about a 217157300Smarcel * possible loss of DCD and thus the existence of a (possibly) 218157300Smarcel * different connection when we have DCD back, during the time 219157300Smarcel * that the device was closed. 220157300Smarcel */ 221119815Smarcel do { 222119815Smarcel old = sc->sc_ttypend; 223155973Smarcel new = old & ~SER_MASK_STATE; 224155971Smarcel new |= sig & SER_INT_SIGMASK; 225119815Smarcel } while (!atomic_cmpset_32(&sc->sc_ttypend, old, new)); 226157300Smarcel 227157300Smarcel if (sc->sc_opened) 228157300Smarcel uart_sched_softih(sc, SER_INT_SIGCHG); 229157300Smarcel return (1); 230119815Smarcel} 231119815Smarcel 232119815Smarcel/* 233119815Smarcel * The transmitter can accept more data. 234119815Smarcel */ 235157300Smarcelstatic __inline int 236157300Smarceluart_intr_txidle(void *arg) 237119815Smarcel{ 238157300Smarcel struct uart_softc *sc = arg; 239157300Smarcel 240119815Smarcel if (sc->sc_txbusy) { 241119815Smarcel sc->sc_txbusy = 0; 242157300Smarcel uart_sched_softih(sc, SER_INT_TXIDLE); 243119815Smarcel } 244157300Smarcel return (0); 245119815Smarcel} 246119815Smarcel 247166901Spisostatic int 248119815Smarceluart_intr(void *arg) 249119815Smarcel{ 250119815Smarcel struct uart_softc *sc = arg; 251166901Spiso int flag = 0, ipend; 252119815Smarcel 253157300Smarcel while (!sc->sc_leaving && (ipend = UART_IPEND(sc)) != 0) { 254166901Spiso flag = 1; 255155971Smarcel if (ipend & SER_INT_OVERRUN) 256120146Smarcel uart_intr_overrun(sc); 257155971Smarcel if (ipend & SER_INT_BREAK) 258120146Smarcel uart_intr_break(sc); 259155971Smarcel if (ipend & SER_INT_RXREADY) 260120146Smarcel uart_intr_rxready(sc); 261155971Smarcel if (ipend & SER_INT_SIGCHG) 262120146Smarcel uart_intr_sigchg(sc); 263155971Smarcel if (ipend & SER_INT_TXIDLE) 264166901Spiso uart_intr_txidle(sc); 265157300Smarcel } 266234194Sgrehan 267234194Sgrehan if (sc->sc_polled) { 268234194Sgrehan callout_reset(&sc->sc_timer, hz / uart_poll_freq, 269234194Sgrehan (timeout_t *)uart_intr, sc); 270234194Sgrehan } 271234194Sgrehan 272166901Spiso return((flag)?FILTER_HANDLED:FILTER_STRAY); 273157300Smarcel} 274119815Smarcel 275157300Smarcelserdev_intr_t * 276157300Smarceluart_bus_ihand(device_t dev, int ipend) 277157300Smarcel{ 278157300Smarcel 279157300Smarcel switch (ipend) { 280157300Smarcel case SER_INT_BREAK: 281157300Smarcel return (uart_intr_break); 282157300Smarcel case SER_INT_OVERRUN: 283157300Smarcel return (uart_intr_overrun); 284157300Smarcel case SER_INT_RXREADY: 285157300Smarcel return (uart_intr_rxready); 286157300Smarcel case SER_INT_SIGCHG: 287157300Smarcel return (uart_intr_sigchg); 288157300Smarcel case SER_INT_TXIDLE: 289157300Smarcel return (uart_intr_txidle); 290157300Smarcel } 291157300Smarcel return (NULL); 292119815Smarcel} 293119815Smarcel 294119815Smarcelint 295158119Smarceluart_bus_ipend(device_t dev) 296158119Smarcel{ 297158119Smarcel struct uart_softc *sc; 298158119Smarcel 299158119Smarcel sc = device_get_softc(dev); 300158119Smarcel return (UART_IPEND(sc)); 301158119Smarcel} 302158119Smarcel 303158119Smarcelint 304157300Smarceluart_bus_sysdev(device_t dev) 305157300Smarcel{ 306157300Smarcel struct uart_softc *sc; 307157300Smarcel 308157300Smarcel sc = device_get_softc(dev); 309157300Smarcel return ((sc->sc_sysdev != NULL) ? 1 : 0); 310157300Smarcel} 311157300Smarcel 312157300Smarcelint 313120452Smarceluart_bus_probe(device_t dev, int regshft, int rclk, int rid, int chan) 314119815Smarcel{ 315119815Smarcel struct uart_softc *sc; 316119815Smarcel struct uart_devinfo *sysdev; 317119815Smarcel int error; 318119815Smarcel 319168281Smarcel sc = device_get_softc(dev); 320168281Smarcel 321119815Smarcel /* 322168281Smarcel * All uart_class references are weak. Check that the needed 323168281Smarcel * class has been compiled-in. Fail if not. 324168281Smarcel */ 325168281Smarcel if (sc->sc_class == NULL) 326168281Smarcel return (ENXIO); 327168281Smarcel 328168281Smarcel /* 329119815Smarcel * Initialize the instance. Note that the instance (=softc) does 330119815Smarcel * not necessarily match the hardware specific softc. We can't do 331119815Smarcel * anything about it now, because we may not attach to the device. 332119815Smarcel * Hardware drivers cannot use any of the class specific fields 333119815Smarcel * while probing. 334119815Smarcel */ 335119815Smarcel kobj_init((kobj_t)sc, (kobj_class_t)sc->sc_class); 336119815Smarcel sc->sc_dev = dev; 337119815Smarcel if (device_get_desc(dev) == NULL) 338168281Smarcel device_set_desc(dev, uart_getname(sc->sc_class)); 339119815Smarcel 340119815Smarcel /* 341119815Smarcel * Allocate the register resource. We assume that all UARTs have 342119815Smarcel * a single register window in either I/O port space or memory 343119815Smarcel * mapped I/O space. Any UART that needs multiple windows will 344119815Smarcel * consequently not be supported by this driver as-is. We try I/O 345119815Smarcel * port space first because that's the common case. 346119815Smarcel */ 347119815Smarcel sc->sc_rrid = rid; 348119815Smarcel sc->sc_rtype = SYS_RES_IOPORT; 349119815Smarcel sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid, 350168281Smarcel 0, ~0, uart_getrange(sc->sc_class), RF_ACTIVE); 351119815Smarcel if (sc->sc_rres == NULL) { 352119815Smarcel sc->sc_rrid = rid; 353119815Smarcel sc->sc_rtype = SYS_RES_MEMORY; 354119815Smarcel sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, 355168281Smarcel &sc->sc_rrid, 0, ~0, uart_getrange(sc->sc_class), 356168281Smarcel RF_ACTIVE); 357119815Smarcel if (sc->sc_rres == NULL) 358119815Smarcel return (ENXIO); 359119815Smarcel } 360119815Smarcel 361119815Smarcel /* 362119815Smarcel * Fill in the bus access structure and compare this device with 363119815Smarcel * a possible console device and/or a debug port. We set the flags 364119815Smarcel * in the softc so that the hardware dependent probe can adjust 365119815Smarcel * accordingly. In general, you don't want to permanently disrupt 366119815Smarcel * console I/O. 367119815Smarcel */ 368119815Smarcel sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres); 369119815Smarcel sc->sc_bas.bst = rman_get_bustag(sc->sc_rres); 370120452Smarcel sc->sc_bas.chan = chan; 371119815Smarcel sc->sc_bas.regshft = regshft; 372119815Smarcel sc->sc_bas.rclk = (rclk == 0) ? sc->sc_class->uc_rclk : rclk; 373119815Smarcel 374119815Smarcel SLIST_FOREACH(sysdev, &uart_sysdevs, next) { 375120452Smarcel if (chan == sysdev->bas.chan && 376120452Smarcel uart_cpu_eqres(&sc->sc_bas, &sysdev->bas)) { 377119815Smarcel /* XXX check if ops matches class. */ 378119815Smarcel sc->sc_sysdev = sysdev; 379167999Smarcel sysdev->bas.rclk = sc->sc_bas.rclk; 380119815Smarcel } 381119815Smarcel } 382119815Smarcel 383119815Smarcel error = UART_PROBE(sc); 384119815Smarcel bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres); 385151792Smarcel return ((error) ? error : BUS_PROBE_DEFAULT); 386119815Smarcel} 387119815Smarcel 388119815Smarcelint 389119815Smarceluart_bus_attach(device_t dev) 390119815Smarcel{ 391119815Smarcel struct uart_softc *sc, *sc0; 392119815Smarcel const char *sep; 393119815Smarcel int error; 394119815Smarcel 395119815Smarcel /* 396119815Smarcel * The sc_class field defines the type of UART we're going to work 397119815Smarcel * with and thus the size of the softc. Replace the generic softc 398119815Smarcel * with one that matches the UART now that we're certain we handle 399119815Smarcel * the device. 400119815Smarcel */ 401119815Smarcel sc0 = device_get_softc(dev); 402119815Smarcel if (sc0->sc_class->size > sizeof(*sc)) { 403119815Smarcel sc = malloc(sc0->sc_class->size, M_UART, M_WAITOK|M_ZERO); 404119815Smarcel bcopy(sc0, sc, sizeof(*sc)); 405119815Smarcel device_set_softc(dev, sc); 406119815Smarcel } else 407119815Smarcel sc = sc0; 408119815Smarcel 409119815Smarcel /* 410119815Smarcel * Protect ourselves against interrupts while we're not completely 411119815Smarcel * finished attaching and initializing. We don't expect interrupts 412119815Smarcel * until after UART_ATTACH() though. 413119815Smarcel */ 414119815Smarcel sc->sc_leaving = 1; 415119815Smarcel 416157300Smarcel mtx_init(&sc->sc_hwmtx_s, "uart_hwmtx", NULL, MTX_SPIN); 417157300Smarcel if (sc->sc_hwmtx == NULL) 418157300Smarcel sc->sc_hwmtx = &sc->sc_hwmtx_s; 419120143Smarcel 420119815Smarcel /* 421119815Smarcel * Re-allocate. We expect that the softc contains the information 422119815Smarcel * collected by uart_bus_probe() intact. 423119815Smarcel */ 424119815Smarcel sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid, 425168281Smarcel 0, ~0, uart_getrange(sc->sc_class), RF_ACTIVE); 426143025Smarius if (sc->sc_rres == NULL) { 427157300Smarcel mtx_destroy(&sc->sc_hwmtx_s); 428119815Smarcel return (ENXIO); 429143025Smarius } 430120380Snyan sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres); 431120380Snyan sc->sc_bas.bst = rman_get_bustag(sc->sc_rres); 432120380Snyan 433119815Smarcel sc->sc_irid = 0; 434127135Snjl sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, 435143025Smarius RF_ACTIVE | RF_SHAREABLE); 436119815Smarcel if (sc->sc_ires != NULL) { 437155921Sjhb error = bus_setup_intr(dev, 438166901Spiso sc->sc_ires, INTR_TYPE_TTY, 439166901Spiso uart_intr, NULL, sc, &sc->sc_icookie); 440119815Smarcel if (error) 441155921Sjhb error = bus_setup_intr(dev, 442128909Smarcel sc->sc_ires, INTR_TYPE_TTY | INTR_MPSAFE, 443166901Spiso NULL, (driver_intr_t *)uart_intr, sc, &sc->sc_icookie); 444119815Smarcel else 445119815Smarcel sc->sc_fastintr = 1; 446119815Smarcel 447119815Smarcel if (error) { 448119815Smarcel device_printf(dev, "could not activate interrupt\n"); 449119815Smarcel bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 450119815Smarcel sc->sc_ires); 451119815Smarcel sc->sc_ires = NULL; 452119815Smarcel } 453119815Smarcel } 454119815Smarcel if (sc->sc_ires == NULL) { 455234194Sgrehan /* No interrupt resource. Force polled mode. */ 456119815Smarcel sc->sc_polled = 1; 457234194Sgrehan callout_init(&sc->sc_timer, 1); 458119815Smarcel } 459119815Smarcel 460181905Sed sc->sc_rxbufsz = 384; 461119815Smarcel sc->sc_rxbuf = malloc(sc->sc_rxbufsz * sizeof(*sc->sc_rxbuf), 462119815Smarcel M_UART, M_WAITOK); 463119815Smarcel sc->sc_txbuf = malloc(sc->sc_txfifosz * sizeof(*sc->sc_txbuf), 464119815Smarcel M_UART, M_WAITOK); 465119815Smarcel 466119815Smarcel error = UART_ATTACH(sc); 467119815Smarcel if (error) 468119815Smarcel goto fail; 469119815Smarcel 470119815Smarcel if (sc->sc_hwiflow || sc->sc_hwoflow) { 471119815Smarcel sep = ""; 472119815Smarcel device_print_prettyname(dev); 473119815Smarcel if (sc->sc_hwiflow) { 474119815Smarcel printf("%sRTS iflow", sep); 475119815Smarcel sep = ", "; 476119815Smarcel } 477119815Smarcel if (sc->sc_hwoflow) { 478119815Smarcel printf("%sCTS oflow", sep); 479119815Smarcel sep = ", "; 480119815Smarcel } 481119815Smarcel printf("\n"); 482119815Smarcel } 483119815Smarcel 484119815Smarcel if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) { 485119815Smarcel sep = ""; 486119815Smarcel device_print_prettyname(dev); 487119815Smarcel if (sc->sc_fastintr) { 488119815Smarcel printf("%sfast interrupt", sep); 489119815Smarcel sep = ", "; 490119815Smarcel } 491119815Smarcel if (sc->sc_polled) { 492119815Smarcel printf("%spolled mode", sep); 493119815Smarcel sep = ", "; 494119815Smarcel } 495119815Smarcel printf("\n"); 496119815Smarcel } 497119815Smarcel 498119815Smarcel if (sc->sc_sysdev != NULL) { 499137706Smarcel if (sc->sc_sysdev->baudrate == 0) { 500137706Smarcel if (UART_IOCTL(sc, UART_IOCTL_BAUD, 501137706Smarcel (intptr_t)&sc->sc_sysdev->baudrate) != 0) 502137706Smarcel sc->sc_sysdev->baudrate = -1; 503137706Smarcel } 504119815Smarcel switch (sc->sc_sysdev->type) { 505119815Smarcel case UART_DEV_CONSOLE: 506119815Smarcel device_printf(dev, "console"); 507119815Smarcel break; 508119815Smarcel case UART_DEV_DBGPORT: 509119815Smarcel device_printf(dev, "debug port"); 510119815Smarcel break; 511119815Smarcel case UART_DEV_KEYBOARD: 512119815Smarcel device_printf(dev, "keyboard"); 513119815Smarcel break; 514119815Smarcel default: 515119815Smarcel device_printf(dev, "unknown system device"); 516119815Smarcel break; 517119815Smarcel } 518119815Smarcel printf(" (%d,%c,%d,%d)\n", sc->sc_sysdev->baudrate, 519119815Smarcel "noems"[sc->sc_sysdev->parity], sc->sc_sysdev->databits, 520119815Smarcel sc->sc_sysdev->stopbits); 521119815Smarcel } 522119815Smarcel 523119996Smarcel sc->sc_pps.ppscap = PPS_CAPTUREBOTH; 524119996Smarcel pps_init(&sc->sc_pps); 525119996Smarcel 526119815Smarcel error = (sc->sc_sysdev != NULL && sc->sc_sysdev->attach != NULL) 527119815Smarcel ? (*sc->sc_sysdev->attach)(sc) : uart_tty_attach(sc); 528119815Smarcel if (error) 529119815Smarcel goto fail; 530119815Smarcel 531157300Smarcel if (sc->sc_sysdev != NULL) 532157300Smarcel sc->sc_sysdev->hwmtx = sc->sc_hwmtx; 533157300Smarcel 534119815Smarcel sc->sc_leaving = 0; 535119815Smarcel uart_intr(sc); 536119815Smarcel return (0); 537119815Smarcel 538119815Smarcel fail: 539119815Smarcel free(sc->sc_txbuf, M_UART); 540119815Smarcel free(sc->sc_rxbuf, M_UART); 541119815Smarcel 542119815Smarcel if (sc->sc_ires != NULL) { 543119815Smarcel bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie); 544119815Smarcel bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 545119815Smarcel sc->sc_ires); 546119815Smarcel } 547119815Smarcel bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres); 548119815Smarcel 549157300Smarcel mtx_destroy(&sc->sc_hwmtx_s); 550143025Smarius 551119815Smarcel return (error); 552119815Smarcel} 553119815Smarcel 554119815Smarcelint 555119815Smarceluart_bus_detach(device_t dev) 556119815Smarcel{ 557119815Smarcel struct uart_softc *sc; 558119815Smarcel 559119815Smarcel sc = device_get_softc(dev); 560119815Smarcel 561119815Smarcel sc->sc_leaving = 1; 562119815Smarcel 563157300Smarcel if (sc->sc_sysdev != NULL) 564157300Smarcel sc->sc_sysdev->hwmtx = NULL; 565157300Smarcel 566119815Smarcel UART_DETACH(sc); 567119815Smarcel 568119815Smarcel if (sc->sc_sysdev != NULL && sc->sc_sysdev->detach != NULL) 569119815Smarcel (*sc->sc_sysdev->detach)(sc); 570119815Smarcel else 571119815Smarcel uart_tty_detach(sc); 572119815Smarcel 573119815Smarcel free(sc->sc_txbuf, M_UART); 574119815Smarcel free(sc->sc_rxbuf, M_UART); 575119815Smarcel 576119815Smarcel if (sc->sc_ires != NULL) { 577119815Smarcel bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie); 578119815Smarcel bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 579119815Smarcel sc->sc_ires); 580119815Smarcel } 581119815Smarcel bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres); 582119815Smarcel 583157300Smarcel mtx_destroy(&sc->sc_hwmtx_s); 584143025Smarius 585119815Smarcel if (sc->sc_class->size > sizeof(*sc)) { 586119815Smarcel device_set_softc(dev, NULL); 587119815Smarcel free(sc, M_UART); 588119815Smarcel } else 589119815Smarcel device_set_softc(dev, NULL); 590119815Smarcel 591119815Smarcel return (0); 592119815Smarcel} 593