bvm_console.c revision 225598
1221905Sgrehan/*- 2221905Sgrehan * Copyright (c) 2011 NetApp, Inc. 3221905Sgrehan * All rights reserved. 4221905Sgrehan * 5221905Sgrehan * Redistribution and use in source and binary forms, with or without 6221905Sgrehan * modification, are permitted provided that the following conditions 7221905Sgrehan * are met: 8221905Sgrehan * 1. Redistributions of source code must retain the above copyright 9221905Sgrehan * notice, this list of conditions and the following disclaimer. 10221905Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 11221905Sgrehan * notice, this list of conditions and the following disclaimer in the 12221905Sgrehan * documentation and/or other materials provided with the distribution. 13221905Sgrehan * 14221905Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15221905Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16221905Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17221905Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18221905Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19221905Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20221905Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21221905Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22221905Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23221905Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24221905Sgrehan * SUCH DAMAGE. 25221905Sgrehan * 26221905Sgrehan * $FreeBSD$ 27221905Sgrehan */ 28221905Sgrehan 29221905Sgrehan#include <sys/cdefs.h> 30221905Sgrehan__FBSDID("$FreeBSD$"); 31221905Sgrehan 32221905Sgrehan#include <sys/param.h> 33221905Sgrehan#include <sys/kernel.h> 34221905Sgrehan#include <sys/systm.h> 35221905Sgrehan#include <sys/types.h> 36221905Sgrehan#include <sys/cons.h> 37221905Sgrehan#include <sys/tty.h> 38221905Sgrehan#include <sys/reboot.h> 39221905Sgrehan#include <sys/bus.h> 40221905Sgrehan 41221905Sgrehan#include <sys/kdb.h> 42221905Sgrehan#include <ddb/ddb.h> 43221905Sgrehan 44221905Sgrehan#ifndef BVMCONS_POLL_HZ 45221905Sgrehan#define BVMCONS_POLL_HZ 4 46221905Sgrehan#endif 47221905Sgrehan#define BVMBURSTLEN 16 /* max number of bytes to write in one chunk */ 48221905Sgrehan 49221905Sgrehanstatic tsw_open_t bvm_tty_open; 50221905Sgrehanstatic tsw_close_t bvm_tty_close; 51221905Sgrehanstatic tsw_outwakeup_t bvm_tty_outwakeup; 52221905Sgrehan 53221905Sgrehanstatic struct ttydevsw bvm_ttydevsw = { 54221905Sgrehan .tsw_flags = TF_NOPREFIX, 55221905Sgrehan .tsw_open = bvm_tty_open, 56221905Sgrehan .tsw_close = bvm_tty_close, 57221905Sgrehan .tsw_outwakeup = bvm_tty_outwakeup, 58221905Sgrehan}; 59221905Sgrehan 60221905Sgrehanstatic int polltime; 61221905Sgrehanstatic struct callout_handle bvm_timeouthandle 62221905Sgrehan = CALLOUT_HANDLE_INITIALIZER(&bvm_timeouthandle); 63221905Sgrehan 64225598Sgrehan#if defined(KDB) 65221905Sgrehanstatic int alt_break_state; 66221905Sgrehan#endif 67221905Sgrehan 68221905Sgrehan#define BVM_CONS_PORT 0x220 69221905Sgrehanstatic int bvm_cons_port = BVM_CONS_PORT; 70221905Sgrehan 71222105Sgrehan#define BVM_CONS_SIG ('b' << 8 | 'v') 72222105Sgrehan 73221905Sgrehanstatic void bvm_timeout(void *); 74221905Sgrehan 75221905Sgrehanstatic cn_probe_t bvm_cnprobe; 76221905Sgrehanstatic cn_init_t bvm_cninit; 77221905Sgrehanstatic cn_term_t bvm_cnterm; 78221905Sgrehanstatic cn_getc_t bvm_cngetc; 79221905Sgrehanstatic cn_putc_t bvm_cnputc; 80221905Sgrehan 81221905SgrehanCONSOLE_DRIVER(bvm); 82221905Sgrehan 83221905Sgrehanstatic int 84221905Sgrehanbvm_rcons(u_char *ch) 85221905Sgrehan{ 86221905Sgrehan int c; 87221905Sgrehan 88221905Sgrehan c = inl(bvm_cons_port); 89221905Sgrehan if (c != -1) { 90221905Sgrehan *ch = (u_char)c; 91221905Sgrehan return (0); 92221905Sgrehan } else 93221905Sgrehan return (-1); 94221905Sgrehan} 95221905Sgrehan 96221905Sgrehanstatic void 97221905Sgrehanbvm_wcons(u_char ch) 98221905Sgrehan{ 99221905Sgrehan 100221905Sgrehan outl(bvm_cons_port, ch); 101221905Sgrehan} 102221905Sgrehan 103221905Sgrehanstatic void 104221905Sgrehancn_drvinit(void *unused) 105221905Sgrehan{ 106221905Sgrehan struct tty *tp; 107221905Sgrehan 108221905Sgrehan if (bvm_consdev.cn_pri != CN_DEAD && 109221905Sgrehan bvm_consdev.cn_name[0] != '\0') { 110221905Sgrehan tp = tty_alloc(&bvm_ttydevsw, NULL); 111221905Sgrehan tty_makedev(tp, NULL, "bvmcons"); 112221905Sgrehan } 113221905Sgrehan} 114221905Sgrehan 115221905Sgrehanstatic int 116221905Sgrehanbvm_tty_open(struct tty *tp) 117221905Sgrehan{ 118221905Sgrehan polltime = hz / BVMCONS_POLL_HZ; 119221905Sgrehan if (polltime < 1) 120221905Sgrehan polltime = 1; 121221905Sgrehan bvm_timeouthandle = timeout(bvm_timeout, tp, polltime); 122221905Sgrehan 123221905Sgrehan return (0); 124221905Sgrehan} 125221905Sgrehan 126221905Sgrehanstatic void 127221905Sgrehanbvm_tty_close(struct tty *tp) 128221905Sgrehan{ 129221905Sgrehan 130221905Sgrehan /* XXX Should be replaced with callout_stop(9) */ 131221905Sgrehan untimeout(bvm_timeout, tp, bvm_timeouthandle); 132221905Sgrehan} 133221905Sgrehan 134221905Sgrehanstatic void 135221905Sgrehanbvm_tty_outwakeup(struct tty *tp) 136221905Sgrehan{ 137221905Sgrehan int len, written; 138221905Sgrehan u_char buf[BVMBURSTLEN]; 139221905Sgrehan 140221905Sgrehan for (;;) { 141221905Sgrehan len = ttydisc_getc(tp, buf, sizeof(buf)); 142221905Sgrehan if (len == 0) 143221905Sgrehan break; 144221905Sgrehan 145221905Sgrehan written = 0; 146221905Sgrehan while (written < len) 147221905Sgrehan bvm_wcons(buf[written++]); 148221905Sgrehan } 149221905Sgrehan} 150221905Sgrehan 151221905Sgrehanstatic void 152221905Sgrehanbvm_timeout(void *v) 153221905Sgrehan{ 154221905Sgrehan struct tty *tp; 155221905Sgrehan int c; 156221905Sgrehan 157221905Sgrehan tp = (struct tty *)v; 158221905Sgrehan 159221905Sgrehan tty_lock(tp); 160221905Sgrehan while ((c = bvm_cngetc(NULL)) != -1) 161221905Sgrehan ttydisc_rint(tp, c, 0); 162221905Sgrehan ttydisc_rint_done(tp); 163221905Sgrehan tty_unlock(tp); 164221905Sgrehan 165221905Sgrehan bvm_timeouthandle = timeout(bvm_timeout, tp, polltime); 166221905Sgrehan} 167221905Sgrehan 168221905Sgrehanstatic void 169221905Sgrehanbvm_cnprobe(struct consdev *cp) 170221905Sgrehan{ 171221905Sgrehan int disabled, port; 172221905Sgrehan 173221905Sgrehan disabled = 0; 174222105Sgrehan cp->cn_pri = CN_DEAD; 175222105Sgrehan 176221905Sgrehan resource_int_value("bvmconsole", 0, "disabled", &disabled); 177222105Sgrehan if (!disabled) { 178222105Sgrehan if (resource_int_value("bvmconsole", 0, "port", &port) == 0) 179222105Sgrehan bvm_cons_port = port; 180221905Sgrehan 181222105Sgrehan if (inw(bvm_cons_port) == BVM_CONS_SIG) 182222105Sgrehan cp->cn_pri = CN_REMOTE; 183222105Sgrehan } 184221905Sgrehan} 185221905Sgrehan 186221905Sgrehanstatic void 187221905Sgrehanbvm_cninit(struct consdev *cp) 188221905Sgrehan{ 189221905Sgrehan int i; 190221905Sgrehan const char *bootmsg = "Using bvm console.\n"; 191221905Sgrehan 192221905Sgrehan if (boothowto & RB_VERBOSE) { 193221905Sgrehan for (i = 0; i < strlen(bootmsg); i++) 194221905Sgrehan bvm_cnputc(cp, bootmsg[i]); 195221905Sgrehan } 196221905Sgrehan 197221905Sgrehan strcpy(cp->cn_name, "bvmcons"); 198221905Sgrehan} 199221905Sgrehan 200221905Sgrehanstatic void 201221905Sgrehanbvm_cnterm(struct consdev *cp) 202221905Sgrehan{ 203221905Sgrehan 204221905Sgrehan} 205221905Sgrehan 206221905Sgrehanstatic int 207221905Sgrehanbvm_cngetc(struct consdev *cp) 208221905Sgrehan{ 209221905Sgrehan unsigned char ch; 210221905Sgrehan 211221905Sgrehan if (bvm_rcons(&ch) == 0) { 212225598Sgrehan#if defined(KDB) 213225598Sgrehan kdb_alt_break(ch, &alt_break_state); 214221905Sgrehan#endif 215221905Sgrehan return (ch); 216221905Sgrehan } 217221905Sgrehan 218221905Sgrehan return (-1); 219221905Sgrehan} 220221905Sgrehan 221221905Sgrehanstatic void 222221905Sgrehanbvm_cnputc(struct consdev *cp, int c) 223221905Sgrehan{ 224221905Sgrehan 225221905Sgrehan bvm_wcons(c); 226221905Sgrehan} 227221905Sgrehan 228221905SgrehanSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL); 229