1 /*-
2 * Copyright (c) 2004 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33
34 #include <machine/bus.h>
35 #include <machine/vmparam.h>
36
37 #include <dev/uart/uart.h>
38 #include <dev/uart/uart_cpu.h>
39
40 #define UART_TAG_BR 0
41 #define UART_TAG_CH 1
42 #define UART_TAG_DB 2
43 #define UART_TAG_DT 3
44 #define UART_TAG_IO 4
45 #define UART_TAG_MM 5
46 #define UART_TAG_PA 6
47 #define UART_TAG_RS 7
48 #define UART_TAG_SB 8
49 #define UART_TAG_XO 9
50
51 static bus_addr_t
52 uart_parse_addr(__const char **p)
53 {
54 return (strtoul(*p, (char**)(uintptr_t)p, 0));
55 }
56
57 static long
58 uart_parse_long(__const char **p)
59 {
60 return (strtol(*p, (char**)(uintptr_t)p, 0));
61 }
62
63 static int
64 uart_parse_parity(__const char **p)
65 {
66 if (!strncmp(*p, "even", 4)) {
67 *p += 4;
68 return UART_PARITY_EVEN;
69 }
70 if (!strncmp(*p, "mark", 4)) {
71 *p += 4;
72 return UART_PARITY_MARK;
73 }
74 if (!strncmp(*p, "none", 4)) {
75 *p += 4;
76 return UART_PARITY_NONE;
77 }
78 if (!strncmp(*p, "odd", 3)) {
79 *p += 3;
80 return UART_PARITY_ODD;
81 }
82 if (!strncmp(*p, "space", 5)) {
83 *p += 5;
84 return UART_PARITY_SPACE;
85 }
86 return (-1);
87 }
88
89 static int
90 uart_parse_tag(__const char **p)
91 {
92 int tag;
93
94 if ((*p)[0] == 'b' && (*p)[1] == 'r') {
95 tag = UART_TAG_BR;
96 goto out;
97 }
98 if ((*p)[0] == 'c' && (*p)[1] == 'h') {
99 tag = UART_TAG_CH;
100 goto out;
101 }
102 if ((*p)[0] == 'd' && (*p)[1] == 'b') {
103 tag = UART_TAG_DB;
104 goto out;
105 }
106 if ((*p)[0] == 'd' && (*p)[1] == 't') {
107 tag = UART_TAG_DT;
108 goto out;
109 }
110 if ((*p)[0] == 'i' && (*p)[1] == 'o') {
111 tag = UART_TAG_IO;
112 goto out;
113 }
114 if ((*p)[0] == 'm' && (*p)[1] == 'm') {
115 tag = UART_TAG_MM;
116 goto out;
117 }
118 if ((*p)[0] == 'p' && (*p)[1] == 'a') {
119 tag = UART_TAG_PA;
120 goto out;
121 }
122 if ((*p)[0] == 'r' && (*p)[1] == 's') {
123 tag = UART_TAG_RS;
124 goto out;
125 }
126 if ((*p)[0] == 's' && (*p)[1] == 'b') {
127 tag = UART_TAG_SB;
128 goto out;
129 }
130 if ((*p)[0] == 'x' && (*p)[1] == 'o') {
131 tag = UART_TAG_XO;
132 goto out;
133 }
134 return (-1);
135
136 out:
137 *p += 2;
138 if ((*p)[0] != ':')
139 return (-1);
140 (*p)++;
141 return (tag);
142 }
143
144 /*
145 * Parse a device specification. The specification is a list of attributes
146 * seperated by commas. Each attribute is a tag-value pair with the tag and
147 * value seperated by a colon. Supported tags are:
148 *
149 * br = Baudrate
150 * ch = Channel
151 * db = Data bits
152 * dt = Device type
153 * io = I/O port address
154 * mm = Memory mapped I/O address
155 * pa = Parity
156 * rs = Register shift
157 * sb = Stopbits
158 * xo = Device clock (xtal oscillator)
159 *
160 * The io and mm tags are mutually exclusive.
161 */
162
163 int
164 uart_getenv(int devtype, struct uart_devinfo *di)
165 {
166 __const char *spec;
167 bus_addr_t addr = ~0U;
168
169 /*
170 * Check the environment variables "hw.uart.console" and
171 * "hw.uart.dbgport". These variables, when present, specify
172 * which UART port is to be used as serial console or debug
173 * port (resp).
174 */
175 if (devtype == UART_DEV_CONSOLE)
176 spec = getenv("hw.uart.console");
177 else if (devtype == UART_DEV_DBGPORT)
178 spec = getenv("hw.uart.dbgport");
179 else
180 spec = NULL;
181 if (spec == NULL)
182 return (ENXIO);
183
184 /* Set defaults. */
185 di->ops = uart_ns8250_ops;
186 di->bas.chan = 0;
187 di->bas.regshft = 0;
188 di->bas.rclk = 0;
189 di->baudrate = 0;
190 di->databits = 8;
191 di->stopbits = 1;
192 di->parity = UART_PARITY_NONE;
193
194 /* Parse the attributes. */
195 while (1) {
196 switch (uart_parse_tag(&spec)) {
197 case UART_TAG_BR:
198 di->baudrate = uart_parse_long(&spec);
199 break;
200 case UART_TAG_CH:
201 di->bas.chan = uart_parse_long(&spec);
202 break;
203 case UART_TAG_DB:
204 di->databits = uart_parse_long(&spec);
205 break;
206 case UART_TAG_DT:
207 return (EINVAL); /* XXX not yet implemented. */
208 break;
209 case UART_TAG_IO:
210 di->bas.bst = uart_bus_space_io;
211 addr = uart_parse_addr(&spec);
212 break;
213 case UART_TAG_MM:
214 di->bas.bst = uart_bus_space_mem;
215 addr = uart_parse_addr(&spec);
216 break;
217 case UART_TAG_PA:
218 di->parity = uart_parse_parity(&spec);
219 break;
220 case UART_TAG_RS:
221 di->bas.regshft = uart_parse_long(&spec);
222 break;
223 case UART_TAG_SB:
224 di->stopbits = uart_parse_long(&spec);
225 break;
226 case UART_TAG_XO:
227 di->bas.rclk = uart_parse_long(&spec);
228 break;
229 default:
230 return (EINVAL);
231 }
232 if (*spec == '\0')
233 break;
234 if (*spec != ',')
235 return (EINVAL);
236 spec++;
237 }
238
239 /*
240 * If we still have an invalid address, the specification must be
241 * missing an I/O port or memory address. We don't like that.
242 */
243 if (addr == ~0U)
244 return (EINVAL);
245
246 /*
247 * Accept only the well-known baudrates. Any invalid baudrate
248 * is silently replaced with a 0-valued baudrate. The 0 baudrate
249 * has special meaning. It means that we're not supposed to
250 * program the baudrate and simply communicate with whatever
251 * speed the hardware is currently programmed for.
252 */
253 if (di->baudrate >= 19200) {
254 if (di->baudrate % 19200)
255 di->baudrate = 0;
256 } else if (di->baudrate >= 1200) {
257 if (di->baudrate % 1200)
258 di->baudrate = 0;
259 } else if (di->baudrate > 0) {
260 if (di->baudrate % 75)
261 di->baudrate = 0;
262 } else
263 di->baudrate = 0;
264
265 /* XXX the size of the mapping depends on the UART class. */
266 if (bus_space_map(di->bas.bst, addr, 8, 0, &di->bas.bsh) != 0)
267 return (EINVAL);
268 return (0);
269 }
Cache object: cf1e4c3e9bac3ce45e1d670d743acba2
|