cfe_console.c revision 203001
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 2007 Bruce M. Simpson.
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes *
141590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241590Srgrimes * SUCH DAMAGE.
251590Srgrimes */
261590Srgrimes
271590Srgrimes#include <sys/cdefs.h>
281590Srgrimes__FBSDID("$FreeBSD: head/sys/dev/cfe/cfe_console.c 203001 2010-01-26 03:42:34Z neel $");
291590Srgrimes
301590Srgrimes#include "opt_comconsole.h"
311590Srgrimes
321590Srgrimes#include <sys/param.h>
331590Srgrimes#include <sys/kdb.h>
3474769Smikeh#include <sys/kernel.h>
3574769Smikeh#include <sys/priv.h>
361590Srgrimes#include <sys/systm.h>
371590Srgrimes#include <sys/types.h>
381590Srgrimes#include <sys/conf.h>
391590Srgrimes#include <sys/cons.h>
401590Srgrimes#include <sys/consio.h>
411590Srgrimes#include <sys/tty.h>
421590Srgrimes
431590Srgrimes#include <dev/cfe/cfe_api.h>
441590Srgrimes#include <dev/cfe/cfe_error.h>
451590Srgrimes
461590Srgrimes#include <ddb/ddb.h>
471590Srgrimes
481590Srgrimes#ifndef	CFECONS_POLL_HZ
491590Srgrimes#define	CFECONS_POLL_HZ	4
501590Srgrimes#endif
511590Srgrimes#define CFEBURSTLEN	128	/* max number of bytes to write in one chunk */
521590Srgrimes
531590Srgrimesstatic tsw_open_t cfe_tty_open;
541590Srgrimesstatic tsw_close_t cfe_tty_close;
551590Srgrimesstatic tsw_outwakeup_t cfe_tty_outwakeup;
561590Srgrimes
571590Srgrimesstatic struct ttydevsw cfe_ttydevsw = {
581590Srgrimes	.tsw_flags	= TF_NOPREFIX,
591590Srgrimes	.tsw_open	= cfe_tty_open,
601590Srgrimes	.tsw_close	= cfe_tty_close,
611590Srgrimes	.tsw_outwakeup	= cfe_tty_outwakeup,
621590Srgrimes};
631590Srgrimes
641590Srgrimesstatic int			conhandle = -1;
651590Srgrimes/* XXX does cfe have to poll? */
661590Srgrimesstatic int			polltime;
671590Srgrimesstatic struct callout_handle	cfe_timeouthandle
681590Srgrimes    = CALLOUT_HANDLE_INITIALIZER(&cfe_timeouthandle);
691590Srgrimes
701590Srgrimes#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
711590Srgrimesstatic int			alt_break_state;
721590Srgrimes#endif
731590Srgrimes
741590Srgrimesstatic void	cfe_timeout(void *);
751590Srgrimes
761590Srgrimesstatic cn_probe_t	cfe_cnprobe;
771590Srgrimesstatic cn_init_t	cfe_cninit;
781590Srgrimesstatic cn_term_t	cfe_cnterm;
791590Srgrimesstatic cn_getc_t	cfe_cngetc;
801590Srgrimesstatic cn_putc_t	cfe_cnputc;
8132189Sjoerg
8232189SjoergCONSOLE_DRIVER(cfe);
831590Srgrimes
841590Srgrimesstatic void
851590Srgrimescn_drvinit(void *unused)
861590Srgrimes{
871590Srgrimes	struct tty *tp;
881590Srgrimes
8974769Smikeh	if (cfe_consdev.cn_pri != CN_DEAD &&
901590Srgrimes	    cfe_consdev.cn_name[0] != '\0') {
911590Srgrimes		tp = tty_alloc(&cfe_ttydevsw, NULL);
921590Srgrimes		tty_makedev(tp, NULL, "cfecons");
931590Srgrimes	}
941590Srgrimes}
951590Srgrimes
961590Srgrimesstatic int
971590Srgrimescfe_tty_open(struct tty *tp)
981590Srgrimes{
991590Srgrimes	polltime = hz / CFECONS_POLL_HZ;
1001590Srgrimes	if (polltime < 1)
1011590Srgrimes		polltime = 1;
1021590Srgrimes	cfe_timeouthandle = timeout(cfe_timeout, tp, polltime);
1031590Srgrimes
1041590Srgrimes	return (0);
1051590Srgrimes}
1061590Srgrimes
1071590Srgrimesstatic void
1081590Srgrimescfe_tty_close(struct tty *tp)
1091590Srgrimes{
1101590Srgrimes
1111590Srgrimes	/* XXX Should be replaced with callout_stop(9) */
1121590Srgrimes	untimeout(cfe_timeout, tp, cfe_timeouthandle);
1131590Srgrimes}
1141590Srgrimes
1151590Srgrimesstatic void
1161590Srgrimescfe_tty_outwakeup(struct tty *tp)
1171590Srgrimes{
1181590Srgrimes	int len, written, rc;
1191590Srgrimes	u_char buf[CFEBURSTLEN];
1201590Srgrimes
1211590Srgrimes	for (;;) {
1221590Srgrimes		len = ttydisc_getc(tp, buf, sizeof buf);
12374769Smikeh		if (len == 0)
1241590Srgrimes			break;
1251590Srgrimes
1261590Srgrimes		written = 0;
1271590Srgrimes		while (written < len) {
12874769Smikeh			rc = cfe_write(conhandle, &buf[written], len - written);
1291590Srgrimes			if (rc < 0)
1301590Srgrimes				break;
1311590Srgrimes			written += rc;
13274769Smikeh		}
1331590Srgrimes	}
1341590Srgrimes}
1351590Srgrimes
1361590Srgrimesstatic void
1371590Srgrimescfe_timeout(void *v)
1381590Srgrimes{
1391590Srgrimes	struct	tty *tp;
1401590Srgrimes	int 	c;
1411590Srgrimes
1421590Srgrimes	tp = (struct tty *)v;
1431590Srgrimes
1441590Srgrimes	tty_lock(tp);
1451590Srgrimes	while ((c = cfe_cngetc(NULL)) != -1)
1461590Srgrimes		ttydisc_rint(tp, c, 0);
1471590Srgrimes	ttydisc_rint_done(tp);
1481590Srgrimes	tty_unlock(tp);
1491590Srgrimes
1501590Srgrimes	cfe_timeouthandle = timeout(cfe_timeout, tp, polltime);
1511590Srgrimes}
1521590Srgrimes
1531590Srgrimesstatic void
1541590Srgrimescfe_cnprobe(struct consdev *cp)
1551590Srgrimes{
1561590Srgrimes
15774769Smikeh	conhandle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
1581590Srgrimes	if (conhandle < 0) {
1591590Srgrimes		cp->cn_pri = CN_DEAD;
1601590Srgrimes		return;
1611590Srgrimes	}
1621590Srgrimes
1631590Srgrimes	/* XXX */
16432189Sjoerg	if (bootverbose) {
1651590Srgrimes		char *bootmsg = "Using CFE firmware console.\n";
1661590Srgrimes		int i;
1671590Srgrimes
1681590Srgrimes		for (i = 0; i < strlen(bootmsg); i++)
1691590Srgrimes			cfe_cnputc(cp, bootmsg[i]);
1701590Srgrimes	}
1711590Srgrimes
1721590Srgrimes	cp->cn_pri = CN_LOW;
1731590Srgrimes}
1741590Srgrimes
1751590Srgrimesstatic void
1761590Srgrimescfe_cninit(struct consdev *cp)
1771590Srgrimes{
1781590Srgrimes
1791590Srgrimes	strcpy(cp->cn_name, "cfecons");
1801590Srgrimes}
1811590Srgrimes
1821590Srgrimesstatic void
1831590Srgrimescfe_cnterm(struct consdev *cp)
1841590Srgrimes{
1851590Srgrimes
1861590Srgrimes}
1871590Srgrimes
1881590Srgrimesstatic int
1891590Srgrimescfe_cngetc(struct consdev *cp)
1901590Srgrimes{
1911590Srgrimes	unsigned char ch;
1921590Srgrimes
1931590Srgrimes	if (cfe_read(conhandle, &ch, 1) == 1) {
1941590Srgrimes#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
1951590Srgrimes		int kdb_brk;
1961590Srgrimes
1971590Srgrimes		if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) {
1981590Srgrimes			switch (kdb_brk) {
1991590Srgrimes			case KDB_REQ_DEBUGGER:
2001590Srgrimes				kdb_enter(KDB_WHY_BREAK,
2011590Srgrimes				    "Break sequence on console");
2021590Srgrimes				break;
2031590Srgrimes			case KDB_REQ_PANIC:
2041590Srgrimes				kdb_panic("Panic sequence on console");
2051590Srgrimes				break;
2061590Srgrimes			case KDB_REQ_REBOOT:
2071590Srgrimes				kdb_reboot();
2081590Srgrimes				break;
2091590Srgrimes
2101590Srgrimes			}
2111590Srgrimes		}
2121590Srgrimes#endif
2131590Srgrimes		return (ch);
21474769Smikeh	}
2151590Srgrimes
2161590Srgrimes	return (-1);
2171590Srgrimes}
2181590Srgrimes
2191590Srgrimesstatic void
2201590Srgrimescfe_cnputc(struct consdev *cp, int c)
2211590Srgrimes{
2221590Srgrimes	char cbuf;
2231590Srgrimes
2241590Srgrimes	if (c == '\n')
2251590Srgrimes		cfe_cnputc(cp, '\r');
2261590Srgrimes
2271590Srgrimes	cbuf = c;
2281590Srgrimes	while (cfe_write(conhandle, &cbuf, 1) == 0)
2291590Srgrimes		continue;
2301590Srgrimes}
2311590Srgrimes
2321590SrgrimesSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL);
2331590Srgrimes