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: releng/10.2/sys/dev/bvm/bvm_console.c 245678 2013-01-20 03:42:49Z neel $ 27221905Sgrehan */ 28221905Sgrehan 29221905Sgrehan#include <sys/cdefs.h> 30221905Sgrehan__FBSDID("$FreeBSD: releng/10.2/sys/dev/bvm/bvm_console.c 245678 2013-01-20 03:42:49Z neel $"); 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; 80229507Ssbrunostatic cn_grab_t bvm_cngrab; 81229507Ssbrunostatic cn_ungrab_t bvm_cnungrab; 82221905Sgrehan 83221905SgrehanCONSOLE_DRIVER(bvm); 84221905Sgrehan 85221905Sgrehanstatic int 86221905Sgrehanbvm_rcons(u_char *ch) 87221905Sgrehan{ 88221905Sgrehan int c; 89221905Sgrehan 90221905Sgrehan c = inl(bvm_cons_port); 91221905Sgrehan if (c != -1) { 92221905Sgrehan *ch = (u_char)c; 93221905Sgrehan return (0); 94221905Sgrehan } else 95221905Sgrehan return (-1); 96221905Sgrehan} 97221905Sgrehan 98221905Sgrehanstatic void 99221905Sgrehanbvm_wcons(u_char ch) 100221905Sgrehan{ 101221905Sgrehan 102221905Sgrehan outl(bvm_cons_port, ch); 103221905Sgrehan} 104221905Sgrehan 105221905Sgrehanstatic void 106221905Sgrehancn_drvinit(void *unused) 107221905Sgrehan{ 108221905Sgrehan struct tty *tp; 109221905Sgrehan 110221905Sgrehan if (bvm_consdev.cn_pri != CN_DEAD && 111221905Sgrehan bvm_consdev.cn_name[0] != '\0') { 112221905Sgrehan tp = tty_alloc(&bvm_ttydevsw, NULL); 113221905Sgrehan tty_makedev(tp, NULL, "bvmcons"); 114221905Sgrehan } 115221905Sgrehan} 116221905Sgrehan 117221905Sgrehanstatic int 118221905Sgrehanbvm_tty_open(struct tty *tp) 119221905Sgrehan{ 120221905Sgrehan polltime = hz / BVMCONS_POLL_HZ; 121221905Sgrehan if (polltime < 1) 122221905Sgrehan polltime = 1; 123221905Sgrehan bvm_timeouthandle = timeout(bvm_timeout, tp, polltime); 124221905Sgrehan 125221905Sgrehan return (0); 126221905Sgrehan} 127221905Sgrehan 128221905Sgrehanstatic void 129221905Sgrehanbvm_tty_close(struct tty *tp) 130221905Sgrehan{ 131221905Sgrehan 132221905Sgrehan /* XXX Should be replaced with callout_stop(9) */ 133221905Sgrehan untimeout(bvm_timeout, tp, bvm_timeouthandle); 134221905Sgrehan} 135221905Sgrehan 136221905Sgrehanstatic void 137221905Sgrehanbvm_tty_outwakeup(struct tty *tp) 138221905Sgrehan{ 139221905Sgrehan int len, written; 140221905Sgrehan u_char buf[BVMBURSTLEN]; 141221905Sgrehan 142221905Sgrehan for (;;) { 143221905Sgrehan len = ttydisc_getc(tp, buf, sizeof(buf)); 144221905Sgrehan if (len == 0) 145221905Sgrehan break; 146221905Sgrehan 147221905Sgrehan written = 0; 148221905Sgrehan while (written < len) 149221905Sgrehan bvm_wcons(buf[written++]); 150221905Sgrehan } 151221905Sgrehan} 152221905Sgrehan 153221905Sgrehanstatic void 154221905Sgrehanbvm_timeout(void *v) 155221905Sgrehan{ 156221905Sgrehan struct tty *tp; 157221905Sgrehan int c; 158221905Sgrehan 159221905Sgrehan tp = (struct tty *)v; 160221905Sgrehan 161221905Sgrehan tty_lock(tp); 162221905Sgrehan while ((c = bvm_cngetc(NULL)) != -1) 163221905Sgrehan ttydisc_rint(tp, c, 0); 164221905Sgrehan ttydisc_rint_done(tp); 165221905Sgrehan tty_unlock(tp); 166221905Sgrehan 167221905Sgrehan bvm_timeouthandle = timeout(bvm_timeout, tp, polltime); 168221905Sgrehan} 169221905Sgrehan 170221905Sgrehanstatic void 171221905Sgrehanbvm_cnprobe(struct consdev *cp) 172221905Sgrehan{ 173221905Sgrehan int disabled, port; 174221905Sgrehan 175221905Sgrehan disabled = 0; 176222105Sgrehan cp->cn_pri = CN_DEAD; 177222105Sgrehan 178221905Sgrehan resource_int_value("bvmconsole", 0, "disabled", &disabled); 179222105Sgrehan if (!disabled) { 180222105Sgrehan if (resource_int_value("bvmconsole", 0, "port", &port) == 0) 181222105Sgrehan bvm_cons_port = port; 182221905Sgrehan 183222105Sgrehan if (inw(bvm_cons_port) == BVM_CONS_SIG) 184222105Sgrehan cp->cn_pri = CN_REMOTE; 185222105Sgrehan } 186221905Sgrehan} 187221905Sgrehan 188221905Sgrehanstatic void 189221905Sgrehanbvm_cninit(struct consdev *cp) 190221905Sgrehan{ 191221905Sgrehan int i; 192221905Sgrehan const char *bootmsg = "Using bvm console.\n"; 193221905Sgrehan 194221905Sgrehan if (boothowto & RB_VERBOSE) { 195221905Sgrehan for (i = 0; i < strlen(bootmsg); i++) 196221905Sgrehan bvm_cnputc(cp, bootmsg[i]); 197221905Sgrehan } 198221905Sgrehan 199221905Sgrehan strcpy(cp->cn_name, "bvmcons"); 200221905Sgrehan} 201221905Sgrehan 202221905Sgrehanstatic void 203221905Sgrehanbvm_cnterm(struct consdev *cp) 204221905Sgrehan{ 205221905Sgrehan 206221905Sgrehan} 207221905Sgrehan 208221905Sgrehanstatic int 209221905Sgrehanbvm_cngetc(struct consdev *cp) 210221905Sgrehan{ 211221905Sgrehan unsigned char ch; 212221905Sgrehan 213221905Sgrehan if (bvm_rcons(&ch) == 0) { 214225598Sgrehan#if defined(KDB) 215225598Sgrehan kdb_alt_break(ch, &alt_break_state); 216221905Sgrehan#endif 217221905Sgrehan return (ch); 218221905Sgrehan } 219221905Sgrehan 220221905Sgrehan return (-1); 221221905Sgrehan} 222221905Sgrehan 223221905Sgrehanstatic void 224221905Sgrehanbvm_cnputc(struct consdev *cp, int c) 225221905Sgrehan{ 226221905Sgrehan 227221905Sgrehan bvm_wcons(c); 228221905Sgrehan} 229221905Sgrehan 230229507Ssbrunostatic void 231229507Ssbrunobvm_cngrab(struct consdev *cp) 232229507Ssbruno{ 233229507Ssbruno} 234229507Ssbruno 235229507Ssbrunostatic void 236229507Ssbrunobvm_cnungrab(struct consdev *cp) 237229507Ssbruno{ 238229507Ssbruno} 239229507Ssbruno 240221905SgrehanSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL); 241