uart_subr.c revision 168281
1139749Simp/*- 2127215Smarcel * Copyright (c) 2004 Marcel Moolenaar 3127215Smarcel * All rights reserved. 4127215Smarcel * 5127215Smarcel * Redistribution and use in source and binary forms, with or without 6127215Smarcel * modification, are permitted provided that the following conditions 7127215Smarcel * are met: 8127215Smarcel * 9127215Smarcel * 1. Redistributions of source code must retain the above copyright 10127215Smarcel * notice, this list of conditions and the following disclaimer. 11127215Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12127215Smarcel * notice, this list of conditions and the following disclaimer in the 13127215Smarcel * documentation and/or other materials provided with the distribution. 14127215Smarcel * 15127215Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16127215Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17127215Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18127215Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19127215Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20127215Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21127215Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22127215Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23127215Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24127215Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25127215Smarcel */ 26127215Smarcel 27127215Smarcel#include <sys/cdefs.h> 28127215Smarcel__FBSDID("$FreeBSD: head/sys/dev/uart/uart_subr.c 168281 2007-04-02 22:00:22Z marcel $"); 29127215Smarcel 30127215Smarcel#include <sys/param.h> 31127215Smarcel#include <sys/systm.h> 32127215Smarcel#include <sys/bus.h> 33127215Smarcel 34127215Smarcel#include <machine/bus.h> 35127215Smarcel#include <machine/vmparam.h> 36127215Smarcel 37127215Smarcel#include <dev/uart/uart.h> 38127215Smarcel#include <dev/uart/uart_cpu.h> 39127215Smarcel 40127215Smarcel#define UART_TAG_BR 0 41127215Smarcel#define UART_TAG_CH 1 42127215Smarcel#define UART_TAG_DB 2 43127215Smarcel#define UART_TAG_DT 3 44127215Smarcel#define UART_TAG_IO 4 45127215Smarcel#define UART_TAG_MM 5 46127215Smarcel#define UART_TAG_PA 6 47127215Smarcel#define UART_TAG_RS 7 48127215Smarcel#define UART_TAG_SB 8 49127215Smarcel#define UART_TAG_XO 9 50127215Smarcel 51168281Smarcelstatic struct uart_class *uart_classes[] = { 52168281Smarcel &uart_ns8250_class, 53168281Smarcel &uart_sab82532_class, 54168281Smarcel &uart_z8530_class, 55168281Smarcel}; 56168281Smarcelstatic size_t uart_nclasses = sizeof(uart_classes) / sizeof(uart_classes[0]); 57168281Smarcel 58127215Smarcelstatic bus_addr_t 59127215Smarceluart_parse_addr(__const char **p) 60127215Smarcel{ 61127215Smarcel return (strtoul(*p, (char**)(uintptr_t)p, 0)); 62127215Smarcel} 63127215Smarcel 64168281Smarcelstatic struct uart_class * 65168281Smarceluart_parse_class(struct uart_class *class, __const char **p) 66168281Smarcel{ 67168281Smarcel struct uart_class *uc; 68168281Smarcel const char *nm; 69168281Smarcel size_t len; 70168281Smarcel u_int i; 71168281Smarcel 72168281Smarcel for (i = 0; i < uart_nclasses; i++) { 73168281Smarcel uc = uart_classes[i]; 74168281Smarcel nm = uart_getname(uc); 75168281Smarcel if (nm == NULL || *nm == '\0') 76168281Smarcel continue; 77168281Smarcel len = strlen(nm); 78168281Smarcel if (strncmp(nm, *p, len) == 0) { 79168281Smarcel *p += len; 80168281Smarcel return (uc); 81168281Smarcel } 82168281Smarcel } 83168281Smarcel return (class); 84168281Smarcel} 85168281Smarcel 86127215Smarcelstatic long 87127215Smarceluart_parse_long(__const char **p) 88127215Smarcel{ 89127215Smarcel return (strtol(*p, (char**)(uintptr_t)p, 0)); 90127215Smarcel} 91127215Smarcel 92127215Smarcelstatic int 93127215Smarceluart_parse_parity(__const char **p) 94127215Smarcel{ 95127215Smarcel if (!strncmp(*p, "even", 4)) { 96127215Smarcel *p += 4; 97127215Smarcel return UART_PARITY_EVEN; 98127215Smarcel } 99127215Smarcel if (!strncmp(*p, "mark", 4)) { 100127215Smarcel *p += 4; 101127215Smarcel return UART_PARITY_MARK; 102127215Smarcel } 103127215Smarcel if (!strncmp(*p, "none", 4)) { 104127215Smarcel *p += 4; 105127215Smarcel return UART_PARITY_NONE; 106127215Smarcel } 107127215Smarcel if (!strncmp(*p, "odd", 3)) { 108127215Smarcel *p += 3; 109127215Smarcel return UART_PARITY_ODD; 110127215Smarcel } 111127215Smarcel if (!strncmp(*p, "space", 5)) { 112127215Smarcel *p += 5; 113127215Smarcel return UART_PARITY_SPACE; 114127215Smarcel } 115127215Smarcel return (-1); 116127215Smarcel} 117127215Smarcel 118127215Smarcelstatic int 119127215Smarceluart_parse_tag(__const char **p) 120127215Smarcel{ 121127215Smarcel int tag; 122127215Smarcel 123127215Smarcel if ((*p)[0] == 'b' && (*p)[1] == 'r') { 124127215Smarcel tag = UART_TAG_BR; 125127215Smarcel goto out; 126127215Smarcel } 127127215Smarcel if ((*p)[0] == 'c' && (*p)[1] == 'h') { 128127215Smarcel tag = UART_TAG_CH; 129127215Smarcel goto out; 130127215Smarcel } 131127215Smarcel if ((*p)[0] == 'd' && (*p)[1] == 'b') { 132127215Smarcel tag = UART_TAG_DB; 133127215Smarcel goto out; 134127215Smarcel } 135127215Smarcel if ((*p)[0] == 'd' && (*p)[1] == 't') { 136127215Smarcel tag = UART_TAG_DT; 137127215Smarcel goto out; 138127215Smarcel } 139127215Smarcel if ((*p)[0] == 'i' && (*p)[1] == 'o') { 140127215Smarcel tag = UART_TAG_IO; 141127215Smarcel goto out; 142127215Smarcel } 143127215Smarcel if ((*p)[0] == 'm' && (*p)[1] == 'm') { 144127215Smarcel tag = UART_TAG_MM; 145127215Smarcel goto out; 146127215Smarcel } 147127215Smarcel if ((*p)[0] == 'p' && (*p)[1] == 'a') { 148127215Smarcel tag = UART_TAG_PA; 149127215Smarcel goto out; 150127215Smarcel } 151127215Smarcel if ((*p)[0] == 'r' && (*p)[1] == 's') { 152127215Smarcel tag = UART_TAG_RS; 153127215Smarcel goto out; 154127215Smarcel } 155127215Smarcel if ((*p)[0] == 's' && (*p)[1] == 'b') { 156127215Smarcel tag = UART_TAG_SB; 157127215Smarcel goto out; 158127215Smarcel } 159127215Smarcel if ((*p)[0] == 'x' && (*p)[1] == 'o') { 160127215Smarcel tag = UART_TAG_XO; 161127215Smarcel goto out; 162127215Smarcel } 163127215Smarcel return (-1); 164127215Smarcel 165127215Smarcelout: 166127215Smarcel *p += 2; 167127215Smarcel if ((*p)[0] != ':') 168127215Smarcel return (-1); 169127215Smarcel (*p)++; 170127215Smarcel return (tag); 171127215Smarcel} 172127215Smarcel 173127215Smarcel/* 174127215Smarcel * Parse a device specification. The specification is a list of attributes 175127215Smarcel * seperated by commas. Each attribute is a tag-value pair with the tag and 176127215Smarcel * value seperated by a colon. Supported tags are: 177127215Smarcel * 178127215Smarcel * br = Baudrate 179127215Smarcel * ch = Channel 180127215Smarcel * db = Data bits 181127215Smarcel * dt = Device type 182127215Smarcel * io = I/O port address 183127215Smarcel * mm = Memory mapped I/O address 184127215Smarcel * pa = Parity 185127215Smarcel * rs = Register shift 186127215Smarcel * sb = Stopbits 187127215Smarcel * xo = Device clock (xtal oscillator) 188127215Smarcel * 189127215Smarcel * The io and mm tags are mutually exclusive. 190127215Smarcel */ 191127215Smarcel 192127215Smarcelint 193168281Smarceluart_getenv(int devtype, struct uart_devinfo *di, struct uart_class *class) 194127215Smarcel{ 195127215Smarcel __const char *spec; 196127215Smarcel bus_addr_t addr = ~0U; 197168281Smarcel int error; 198127215Smarcel 199127215Smarcel /* 200168281Smarcel * All uart_class references are weak. Make sure the default 201168281Smarcel * device class has been compiled-in. 202168281Smarcel */ 203168281Smarcel if (class == NULL) 204168281Smarcel return (ENXIO); 205168281Smarcel 206168281Smarcel /* 207127215Smarcel * Check the environment variables "hw.uart.console" and 208127215Smarcel * "hw.uart.dbgport". These variables, when present, specify 209127215Smarcel * which UART port is to be used as serial console or debug 210127215Smarcel * port (resp). 211127215Smarcel */ 212127215Smarcel if (devtype == UART_DEV_CONSOLE) 213127215Smarcel spec = getenv("hw.uart.console"); 214127215Smarcel else if (devtype == UART_DEV_DBGPORT) 215127215Smarcel spec = getenv("hw.uart.dbgport"); 216127215Smarcel else 217127226Smarcel spec = NULL; 218127226Smarcel if (spec == NULL) 219127215Smarcel return (ENXIO); 220127215Smarcel 221127215Smarcel /* Set defaults. */ 222127215Smarcel di->bas.chan = 0; 223127215Smarcel di->bas.regshft = 0; 224127215Smarcel di->bas.rclk = 0; 225127215Smarcel di->baudrate = 0; 226127215Smarcel di->databits = 8; 227127215Smarcel di->stopbits = 1; 228127215Smarcel di->parity = UART_PARITY_NONE; 229127215Smarcel 230127215Smarcel /* Parse the attributes. */ 231127215Smarcel while (1) { 232127215Smarcel switch (uart_parse_tag(&spec)) { 233127215Smarcel case UART_TAG_BR: 234127215Smarcel di->baudrate = uart_parse_long(&spec); 235127215Smarcel break; 236127215Smarcel case UART_TAG_CH: 237127215Smarcel di->bas.chan = uart_parse_long(&spec); 238127215Smarcel break; 239127215Smarcel case UART_TAG_DB: 240127215Smarcel di->databits = uart_parse_long(&spec); 241127215Smarcel break; 242127215Smarcel case UART_TAG_DT: 243168281Smarcel class = uart_parse_class(class, &spec); 244127215Smarcel break; 245127215Smarcel case UART_TAG_IO: 246127215Smarcel di->bas.bst = uart_bus_space_io; 247127215Smarcel addr = uart_parse_addr(&spec); 248127215Smarcel break; 249127215Smarcel case UART_TAG_MM: 250127215Smarcel di->bas.bst = uart_bus_space_mem; 251127215Smarcel addr = uart_parse_addr(&spec); 252127215Smarcel break; 253127215Smarcel case UART_TAG_PA: 254127215Smarcel di->parity = uart_parse_parity(&spec); 255127215Smarcel break; 256127215Smarcel case UART_TAG_RS: 257127215Smarcel di->bas.regshft = uart_parse_long(&spec); 258127215Smarcel break; 259127215Smarcel case UART_TAG_SB: 260127215Smarcel di->stopbits = uart_parse_long(&spec); 261127215Smarcel break; 262127215Smarcel case UART_TAG_XO: 263127215Smarcel di->bas.rclk = uart_parse_long(&spec); 264127215Smarcel break; 265127215Smarcel default: 266127215Smarcel return (EINVAL); 267127215Smarcel } 268127215Smarcel if (*spec == '\0') 269127215Smarcel break; 270127215Smarcel if (*spec != ',') 271127215Smarcel return (EINVAL); 272127215Smarcel spec++; 273127215Smarcel } 274127215Smarcel 275127215Smarcel /* 276127215Smarcel * If we still have an invalid address, the specification must be 277127215Smarcel * missing an I/O port or memory address. We don't like that. 278127215Smarcel */ 279127215Smarcel if (addr == ~0U) 280127215Smarcel return (EINVAL); 281137704Smarcel 282137704Smarcel /* 283137704Smarcel * Accept only the well-known baudrates. Any invalid baudrate 284137704Smarcel * is silently replaced with a 0-valued baudrate. The 0 baudrate 285137704Smarcel * has special meaning. It means that we're not supposed to 286137704Smarcel * program the baudrate and simply communicate with whatever 287137704Smarcel * speed the hardware is currently programmed for. 288137704Smarcel */ 289137704Smarcel if (di->baudrate >= 19200) { 290137704Smarcel if (di->baudrate % 19200) 291137704Smarcel di->baudrate = 0; 292137704Smarcel } else if (di->baudrate >= 1200) { 293137704Smarcel if (di->baudrate % 1200) 294137704Smarcel di->baudrate = 0; 295137704Smarcel } else if (di->baudrate > 0) { 296137704Smarcel if (di->baudrate % 75) 297137704Smarcel di->baudrate = 0; 298137704Smarcel } else 299137704Smarcel di->baudrate = 0; 300137704Smarcel 301168281Smarcel /* Set the ops and create a bus space handle. */ 302168281Smarcel di->ops = uart_getops(class); 303168281Smarcel error = bus_space_map(di->bas.bst, addr, uart_getrange(class), 0, 304168281Smarcel &di->bas.bsh); 305168281Smarcel return (error); 306127215Smarcel} 307