1 /*
2  * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 /*
27  * This code is shared on BIOS and UEFI systems on x86 because
28  * we can access io ports on both platforms and the UEFI Serial IO protocol
29  * is not giving us reliable port order and we see issues with input.
30  */
31 #include <sys/cdefs.h>
32 
33 #include <stand.h>
34 #include <bootstrap.h>
35 #include <stdbool.h>
36 #include <machine/cpufunc.h>
37 #include <dev/ic/ns16550.h>
38 #include <dev/pci/pcireg.h>
39 #include "libi386.h"
40 
41 #define	COMC_TXWAIT	0x40000		/* transmit timeout */
42 #define	COMC_BPS(x)	(115200 / (x))	/* speed to DLAB divisor */
43 #define	COMC_DIV2BPS(x)	(115200 / (x))	/* DLAB divisor to speed */
44 
45 #ifndef	COMSPEED
46 #define	COMSPEED	9600
47 #endif
48 
49 #define	COM_NPORTS	4
50 #define	COM1_IOADDR	0x3f8
51 #define	COM2_IOADDR	0x2f8
52 #define	COM3_IOADDR	0x3e8
53 #define	COM4_IOADDR	0x2e8
54 
55 #define	STOP1		0x00
56 #define	STOP2		0x04
57 
58 #define	PARODD		0x00
59 #define	PAREN		0x08
60 #define	PAREVN		0x10
61 #define	PARMARK		0x20
62 
63 #define	BITS5		0x00	/* 5 bits per char */
64 #define	BITS6		0x01	/* 6 bits per char */
65 #define	BITS7		0x02	/* 7 bits per char */
66 #define	BITS8		0x03	/* 8 bits per char */
67 
68 struct serial {
69     int		speed;		/* baud rate */
70     uint8_t	lcr;		/* line control */
71     uint8_t	ignore_cd;	/* boolean */
72     uint8_t	rtsdtr_off;	/* boolean */
73     int		ioaddr;
74     uint32_t	locator;
75 };
76 
77 static void	comc_probe(struct console *);
78 static int	comc_init(struct console *, int);
79 static void	comc_putchar(struct console *, int);
80 static int	comc_getchar(struct console *);
81 int		comc_getspeed(int);
82 static int	comc_ischar(struct console *);
83 static int	comc_ioctl(struct console *, int, void *);
84 static uint32_t comc_parse_pcidev(const char *);
85 static int	comc_pcidev_set(struct env_var *, int, const void *);
86 static int	comc_pcidev_handle(struct console *, uint32_t);
87 static bool	comc_setup(struct console *);
88 static char	*comc_asprint_mode(struct serial *);
89 static int	comc_parse_mode(struct serial *, const char *);
90 static int	comc_mode_set(struct env_var *, int, const void *);
91 static int	comc_cd_set(struct env_var *, int, const void *);
92 static int	comc_rtsdtr_set(struct env_var *, int, const void *);
93 static void	comc_devinfo(struct console *);
94 
95 static void
comc_devinfo(struct console * cp)96 comc_devinfo(struct console *cp)
97 {
98 	struct serial *port = cp->c_private;
99 
100 	printf("\tport %#x", port->ioaddr);
101 }
102 
103 static bool
comc_port_is_present(int ioaddr)104 comc_port_is_present(int ioaddr)
105 {
106 	/*
107 	 * Write byte to scratch register and read it out.
108 	 */
109 #define	COMC_TEST	0xbb
110 	outb(ioaddr + com_scr, COMC_TEST);
111 	return (inb(ioaddr + com_scr) == COMC_TEST);
112 }
113 
114 /*
115  * Set up list of possible serial consoles.
116  * This function is run very early, so we do not expect to
117  * run out of memory, and on error, we can not print output.
118  */
119 void
comc_ini(void)120 comc_ini(void)
121 {
122 	uint_t n = 0, c;
123 	bool ports[COM_NPORTS];
124 	struct console **tmp;
125 	struct console *tty;
126 	struct serial *port;
127 
128 	/*
129 	 * Test the presence of 4 serial devices com1-com4
130 	 */
131 	ports[0] = comc_port_is_present(COM1_IOADDR);
132 	ports[1] = comc_port_is_present(COM2_IOADDR);
133 	ports[2] = comc_port_is_present(COM3_IOADDR);
134 	ports[3] = comc_port_is_present(COM4_IOADDR);
135 
136 	for (uint_t i = 0; i < COM_NPORTS; i++)
137 		if (ports[i])
138 			n++;
139 
140 	if (n == 0)	/* there are no serial ports */
141 		return;
142 
143 	c = cons_array_size();
144 	if (c == 0)
145 		n++;	/* For NULL pointer */
146 
147 	tmp = realloc(consoles, (c + n) * sizeof (*consoles));
148 	if (tmp == NULL)
149 		return;
150 	consoles = tmp;
151 	if (c > 0)
152 		c--;
153 
154 	for (uint_t i = 0; i < COM_NPORTS; i++) {
155 		if (!ports[i])
156 			continue;
157 		tty = malloc(sizeof (*tty));
158 		if (tty == NULL) {
159 			/* Out of memory?! can not continue */
160 			consoles[c] = tty;
161 			return;
162 		}
163 		if (asprintf(&tty->c_name, "tty%c", 'a' + i) < 0) {
164 			free(tty);
165 			consoles[c] = NULL;
166 			return;
167 		}
168 		if (asprintf(&tty->c_desc, "serial port %c", 'a' + i) < 0) {
169 			free(tty->c_name);
170 			free(tty);
171 			consoles[c] = NULL;
172 			return;
173 		}
174 		tty->c_flags = 0;
175 		tty->c_probe = comc_probe;
176 		tty->c_init = comc_init;
177 		tty->c_out = comc_putchar;
178 		tty->c_in = comc_getchar;
179 		tty->c_ready = comc_ischar;
180 		tty->c_ioctl = comc_ioctl;
181 		tty->c_devinfo = comc_devinfo;
182 		port = malloc(sizeof (*port));
183 		if (port == NULL) {
184 			free(tty->c_name);
185 			free(tty->c_desc);
186 			free(tty);
187 			consoles[c] = NULL;
188 			return;
189 		}
190 		port->speed = 0;	/* Leave this for comc_probe */
191 		switch (i) {
192 		case 0:
193 			port->ioaddr = COM1_IOADDR;
194 			break;
195 		case 1:
196 			port->ioaddr = COM2_IOADDR;
197 			break;
198 		case 2:
199 			port->ioaddr = COM3_IOADDR;
200 			break;
201 		case 3:
202 			port->ioaddr = COM4_IOADDR;
203 			break;
204 		}
205 		port->speed = comc_getspeed(port->ioaddr);
206 		port->lcr = BITS8;	/* 8,n,1 */
207 		port->ignore_cd = 1;	/* ignore cd */
208 		port->rtsdtr_off = 0;	/* rts-dtr is on */
209 
210 		tty->c_private = port;
211 		consoles[c++] = tty;
212 
213 		/* Reset terminal to initial normal settings with ESC [ 0 m */
214 		comc_putchar(tty, 0x1b);
215 		comc_putchar(tty, '[');
216 		comc_putchar(tty, '0');
217 		comc_putchar(tty, 'm');
218 		/* drain input from random data */
219 		while (comc_getchar(tty) != -1)
220 			;
221 	}
222 	consoles[c] = NULL;
223 }
224 
225 static void
comc_probe(struct console * cp)226 comc_probe(struct console *cp)
227 {
228 	struct serial *port;
229 	char name[20];
230 	char value[20];
231 	char *env;
232 
233 	port = cp->c_private;
234 	if (port->speed != 0)
235 		return;
236 
237 	port->speed = COMSPEED;
238 
239 	/*
240 	 * Assume that the speed was set by an earlier boot loader if
241 	 * comconsole is already the preferred console.
242 	 */
243 	snprintf(name, sizeof (name), "%s-mode", cp->c_name);
244 	env = getenv(name);
245 	if (env != NULL) {
246 		port->speed = comc_getspeed(port->ioaddr);
247 	}
248 	env = comc_asprint_mode(port);
249 
250 	if (env != NULL) {
251 		unsetenv(name);
252 		env_setenv(name, EV_VOLATILE, env, comc_mode_set, env_nounset);
253 		free(env);
254 	}
255 
256 	snprintf(name, sizeof (name), "%s-ignore-cd", cp->c_name);
257 	env = getenv(name);
258 	if (env != NULL) {
259 		if (strcmp(env, "true") == 0)
260 			port->ignore_cd = 1;
261 		else if (strcmp(env, "false") == 0)
262 			port->ignore_cd = 0;
263 	}
264 
265 	snprintf(value, sizeof (value), "%s",
266 	    port->ignore_cd? "true" : "false");
267 	unsetenv(name);
268 	env_setenv(name, EV_VOLATILE, value, comc_cd_set, env_nounset);
269 
270 	snprintf(name, sizeof (name), "%s-rts-dtr-off", cp->c_name);
271 	env = getenv(name);
272 	if (env != NULL) {
273 		if (strcmp(env, "true") == 0)
274 			port->rtsdtr_off = 1;
275 		else if (strcmp(env, "false") == 0)
276 			port->rtsdtr_off = 0;
277 	}
278 
279 	snprintf(value, sizeof (value), "%s",
280 	    port->rtsdtr_off? "true" : "false");
281 	unsetenv(name);
282 	env_setenv(name, EV_VOLATILE, value, comc_rtsdtr_set, env_nounset);
283 
284 	snprintf(name, sizeof (name), "%s-pcidev", cp->c_name);
285 	env = getenv(name);
286 	if (env != NULL) {
287 		port->locator = comc_parse_pcidev(env);
288 		if (port->locator != 0)
289 			comc_pcidev_handle(cp, port->locator);
290 	}
291 
292 	unsetenv(name);
293 	env_setenv(name, EV_VOLATILE, env, comc_pcidev_set, env_nounset);
294 
295 	cp->c_flags = 0;
296 	if (comc_setup(cp))
297 		cp->c_flags = C_PRESENTIN | C_PRESENTOUT;
298 }
299 
300 static int
comc_init(struct console * cp,int arg __attribute ((unused)))301 comc_init(struct console *cp, int arg __attribute((unused)))
302 {
303 
304 	if (comc_setup(cp))
305 		return (CMD_OK);
306 
307 	cp->c_flags = 0;
308 	return (CMD_ERROR);
309 }
310 
311 static void
comc_putchar(struct console * cp,int c)312 comc_putchar(struct console *cp, int c)
313 {
314 	int wait;
315 	struct serial *sp = cp->c_private;
316 
317 	for (wait = COMC_TXWAIT; wait > 0; wait--)
318 		if (inb(sp->ioaddr + com_lsr) & LSR_TXRDY) {
319 			outb(sp->ioaddr + com_data, (uchar_t)c);
320 			break;
321 		}
322 }
323 
324 static int
comc_getchar(struct console * cp)325 comc_getchar(struct console *cp)
326 {
327 	struct serial *sp = cp->c_private;
328 	return (comc_ischar(cp) ? inb(sp->ioaddr + com_data) : -1);
329 }
330 
331 static int
comc_ischar(struct console * cp)332 comc_ischar(struct console *cp)
333 {
334 	struct serial *sp = cp->c_private;
335 	return (inb(sp->ioaddr + com_lsr) & LSR_RXRDY);
336 }
337 
338 static int
comc_ioctl(struct console * cp __unused,int cmd __unused,void * data __unused)339 comc_ioctl(struct console *cp __unused, int cmd __unused, void *data __unused)
340 {
341 	return (ENOTTY);
342 }
343 
344 static char *
comc_asprint_mode(struct serial * sp)345 comc_asprint_mode(struct serial *sp)
346 {
347 	char par, *buf;
348 
349 	if (sp == NULL)
350 		return (NULL);
351 
352 	if ((sp->lcr & (PAREN|PAREVN)) == (PAREN|PAREVN))
353 		par = 'e';
354 	else if ((sp->lcr & PAREN) == PAREN)
355 		par = 'o';
356 	else
357 		par = 'n';
358 
359 	asprintf(&buf, "%d,%d,%c,%d,-", sp->speed,
360 	    (sp->lcr & BITS8) == BITS8? 8:7,
361 	    par, (sp->lcr & STOP2) == STOP2? 2:1);
362 	return (buf);
363 }
364 
365 static int
comc_parse_mode(struct serial * sp,const char * value)366 comc_parse_mode(struct serial *sp, const char *value)
367 {
368 	unsigned long n;
369 	int speed;
370 	int lcr;
371 	char *ep;
372 
373 	if (value == NULL || *value == '\0')
374 		return (CMD_ERROR);
375 
376 	errno = 0;
377 	n = strtoul(value, &ep, 10);
378 	if (errno != 0 || *ep != ',')
379 		return (CMD_ERROR);
380 	speed = n;
381 
382 	ep++;
383 	errno = 0;
384 	n = strtoul(ep, &ep, 10);
385 	if (errno != 0 || *ep != ',')
386 		return (CMD_ERROR);
387 
388 	switch (n) {
389 	case 7: lcr = BITS7;
390 		break;
391 	case 8: lcr = BITS8;
392 		break;
393 	default:
394 		return (CMD_ERROR);
395 	}
396 
397 	ep++;
398 	switch (*ep++) {
399 	case 'n':
400 		break;
401 	case 'e': lcr |= PAREN|PAREVN;
402 		break;
403 	case 'o': lcr |= PAREN|PARODD;
404 		break;
405 	default:
406 		return (CMD_ERROR);
407 	}
408 
409 	if (*ep == ',')
410 		ep++;
411 	else
412 		return (CMD_ERROR);
413 
414 	switch (*ep++) {
415 	case '1':
416 		break;
417 	case '2': lcr |= STOP2;
418 		break;
419 	default:
420 		return (CMD_ERROR);
421 	}
422 
423 	/* handshake is ignored, but we check syntax anyhow */
424 	if (*ep == ',')
425 		ep++;
426 	else
427 		return (CMD_ERROR);
428 
429 	switch (*ep++) {
430 	case '-':
431 	case 'h':
432 	case 's':
433 		break;
434 	default:
435 		return (CMD_ERROR);
436 	}
437 
438 	if (*ep != '\0')
439 		return (CMD_ERROR);
440 
441 	sp->speed = speed;
442 	sp->lcr = lcr;
443 	return (CMD_OK);
444 }
445 
446 static struct console *
get_console(const char * name)447 get_console(const char *name)
448 {
449 	char port[5];
450 
451 	(void) strlcpy(port, name, sizeof (port));
452 	for (uint_t i = 0; consoles[i] != NULL; i++) {
453 		if (strcmp(port, consoles[i]->c_name) == 0)
454 			return (consoles[i]);
455 	}
456 
457 	printf("No such port: %s\n", port);
458 	return (NULL);
459 }
460 
461 /*
462  * CMD_ERROR will cause set/setenv/setprop command to fail,
463  * when used in loader scripts (forth), this will cause processing
464  * of boot scripts to fail, rendering bootloading impossible.
465  * To prevent such unfortunate situation, we return CMD_OK when
466  * there is no such port, or there is invalid value in mode line.
467  */
468 static int
comc_mode_set(struct env_var * ev,int flags,const void * value)469 comc_mode_set(struct env_var *ev, int flags, const void *value)
470 {
471 	struct console *cp;
472 	char name[15];
473 
474 	if (value == NULL)
475 		return (CMD_ERROR);
476 
477 	if ((cp = get_console(ev->ev_name)) == NULL)
478 		return (CMD_OK);
479 
480 	/* Do not override serial setup from SPCR */
481 	snprintf(name, sizeof (name), "%s-spcr-mode", cp->c_name);
482 	if (getenv(name) == NULL) {
483 		if (comc_parse_mode(cp->c_private, value) == CMD_ERROR) {
484 			printf("%s: invalid mode: %s\n", ev->ev_name,
485 			    (char *)value);
486 			return (CMD_OK);
487 		}
488 		(void) comc_setup(cp);
489 		env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
490 	}
491 
492 	return (CMD_OK);
493 }
494 
495 /*
496  * CMD_ERROR will cause set/setenv/setprop command to fail,
497  * when used in loader scripts (forth), this will cause processing
498  * of boot scripts to fail, rendering bootloading impossible.
499  * To prevent such unfortunate situation, we return CMD_OK when
500  * there is no such port or invalid value was used.
501  */
502 static int
comc_cd_set(struct env_var * ev,int flags,const void * value)503 comc_cd_set(struct env_var *ev, int flags, const void *value)
504 {
505 	struct console *cp;
506 	struct serial *sp;
507 
508 	if (value == NULL)
509 		return (CMD_ERROR);
510 
511 	if ((cp = get_console(ev->ev_name)) == NULL)
512 		return (CMD_OK);
513 
514 	sp = cp->c_private;
515 	if (strcmp(value, "true") == 0) {
516 		sp->ignore_cd = 1;
517 	} else if (strcmp(value, "false") == 0) {
518 		sp->ignore_cd = 0;
519 	} else {
520 		printf("%s: invalid value: %s\n", ev->ev_name,
521 		    (char *)value);
522 		return (CMD_ERROR);
523 	}
524 
525 	(void) comc_setup(cp);
526 
527 	env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
528 
529 	return (CMD_OK);
530 }
531 
532 /*
533  * CMD_ERROR will cause set/setenv/setprop command to fail,
534  * when used in loader scripts (forth), this will cause processing
535  * of boot scripts to fail, rendering bootloading impossible.
536  * To prevent such unfortunate situation, we return CMD_OK when
537  * there is no such port, or invalid value was used.
538  */
539 static int
comc_rtsdtr_set(struct env_var * ev,int flags,const void * value)540 comc_rtsdtr_set(struct env_var *ev, int flags, const void *value)
541 {
542 	struct console *cp;
543 	struct serial *sp;
544 
545 	if (value == NULL)
546 		return (CMD_ERROR);
547 
548 	if ((cp = get_console(ev->ev_name)) == NULL)
549 		return (CMD_OK);
550 
551 	sp = cp->c_private;
552 	if (strcmp(value, "true") == 0) {
553 		sp->rtsdtr_off = 1;
554 	} else if (strcmp(value, "false") == 0) {
555 		sp->rtsdtr_off = 0;
556 	} else {
557 		printf("%s: invalid value: %s\n", ev->ev_name,
558 		    (char *)value);
559 		return (CMD_ERROR);
560 	}
561 
562 	(void) comc_setup(cp);
563 
564 	env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
565 
566 	return (CMD_OK);
567 }
568 
569 /*
570  * Input: bus:dev:func[:bar]. If bar is not specified, it is 0x10.
571  * Output: bar[24:16] bus[15:8] dev[7:3] func[2:0]
572  */
573 static uint32_t
comc_parse_pcidev(const char * string)574 comc_parse_pcidev(const char *string)
575 {
576 #ifdef EFI
577 	(void) string;
578 	return (0);
579 #else
580 	char *p, *p1;
581 	uint8_t bus, dev, func, bar;
582 	uint32_t locator;
583 	int pres;
584 
585 	errno = 0;
586 	pres = strtoul(string, &p, 10);
587 	if (errno != 0 || p == string || *p != ':' || pres < 0)
588 		return (0);
589 	bus = pres;
590 	p1 = ++p;
591 
592 	pres = strtoul(p1, &p, 10);
593 	if (errno != 0 || p == string || *p != ':' || pres < 0)
594 		return (0);
595 	dev = pres;
596 	p1 = ++p;
597 
598 	pres = strtoul(p1, &p, 10);
599 	if (errno != 0 || p == string || (*p != ':' && *p != '\0') || pres < 0)
600 		return (0);
601 	func = pres;
602 
603 	if (*p == ':') {
604 		p1 = ++p;
605 		pres = strtoul(p1, &p, 10);
606 		if (errno != 0 || p == string || *p != '\0' || pres <= 0)
607 			return (0);
608 		bar = pres;
609 	} else
610 		bar = 0x10;
611 
612 	locator = (bar << 16) | biospci_locator(bus, dev, func);
613 	return (locator);
614 #endif
615 }
616 
617 static int
comc_pcidev_handle(struct console * cp,uint32_t locator)618 comc_pcidev_handle(struct console *cp, uint32_t locator)
619 {
620 #ifdef EFI
621 	(void) cp;
622 	(void) locator;
623 	return (CMD_ERROR);
624 #else
625 	struct serial *sp = cp->c_private;
626 	uint32_t port;
627 
628 	if (biospci_read_config(locator & 0xffff,
629 	    (locator & 0xff0000) >> 16, 2, &port) == -1) {
630 		printf("Cannot read bar at 0x%x\n", locator);
631 		return (CMD_ERROR);
632 	}
633 	if (!PCI_BAR_IO(port)) {
634 		printf("Memory bar at 0x%x\n", locator);
635 		return (CMD_ERROR);
636 	}
637 	port &= PCIM_BAR_IO_BASE;
638 
639 	(void) comc_setup(cp);
640 
641 	sp->locator = locator;
642 
643 	return (CMD_OK);
644 #endif
645 }
646 
647 static int
comc_pcidev_set(struct env_var * ev,int flags,const void * value)648 comc_pcidev_set(struct env_var *ev, int flags, const void *value)
649 {
650 	struct console *cp;
651 	struct serial *sp;
652 	uint32_t locator;
653 	int error;
654 
655 	if ((cp = get_console(ev->ev_name)) == NULL)
656 		return (CMD_ERROR);
657 	sp = cp->c_private;
658 
659 	if (value == NULL || (locator = comc_parse_pcidev(value)) <= 0) {
660 		printf("Invalid pcidev\n");
661 		return (CMD_ERROR);
662 	}
663 	if ((cp->c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) != 0 &&
664 	    sp->locator != locator) {
665 		error = comc_pcidev_handle(cp, locator);
666 		if (error != CMD_OK)
667 			return (error);
668 	}
669 	env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
670 	return (CMD_OK);
671 }
672 
673 /*
674  * In case of error, we also reset ACTIVE flags, so the console
675  * framefork will try alternate consoles.
676  */
677 static bool
comc_setup(struct console * cp)678 comc_setup(struct console *cp)
679 {
680 	struct serial *sp = cp->c_private;
681 	static int TRY_COUNT = 1000000;
682 	int tries;
683 
684 	outb(sp->ioaddr + com_cfcr, CFCR_DLAB | sp->lcr);
685 	outb(sp->ioaddr + com_dlbl, COMC_BPS(sp->speed) & 0xff);
686 	outb(sp->ioaddr + com_dlbh, COMC_BPS(sp->speed) >> 8);
687 	outb(sp->ioaddr + com_cfcr, sp->lcr);
688 	outb(sp->ioaddr + com_mcr,
689 	    sp->rtsdtr_off? ~(MCR_RTS | MCR_DTR) : MCR_RTS | MCR_DTR);
690 
691 	tries = 0;
692 	do {
693 		inb(sp->ioaddr + com_data);
694 	} while (inb(sp->ioaddr + com_lsr) & LSR_RXRDY && ++tries < TRY_COUNT);
695 
696 	if (tries == TRY_COUNT)
697 		return (false);
698 	/* Mark this port usable. */
699 	cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
700 	return (true);
701 }
702 
703 int
comc_getspeed(int ioaddr)704 comc_getspeed(int ioaddr)
705 {
706 	uint_t	divisor;
707 	uchar_t	dlbh;
708 	uchar_t	dlbl;
709 	uchar_t	cfcr;
710 
711 	cfcr = inb(ioaddr + com_cfcr);
712 	outb(ioaddr + com_cfcr, CFCR_DLAB | cfcr);
713 
714 	dlbl = inb(ioaddr + com_dlbl);
715 	dlbh = inb(ioaddr + com_dlbh);
716 
717 	outb(ioaddr + com_cfcr, cfcr);
718 
719 	divisor = dlbh << 8 | dlbl;
720 
721 	/* XXX there should be more sanity checking. */
722 	if (divisor == 0)
723 		return (COMSPEED);
724 	return (COMC_DIV2BPS(divisor));
725 }
726