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