1 /*- 2 * Copyright (c) 2011 NetApp, Inc. 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 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/kernel.h> 34 #include <sys/systm.h> 35 #include <sys/types.h> 36 #include <sys/cons.h> 37 #include <sys/tty.h> 38 #include <sys/reboot.h> 39 #include <sys/bus.h> 40 41 #include <sys/kdb.h> 42 #include <ddb/ddb.h> 43 44 #ifndef BVMCONS_POLL_HZ 45 #define BVMCONS_POLL_HZ 4 46 #endif 47 #define BVMBURSTLEN 16 /* max number of bytes to write in one chunk */ 48 49 static tsw_open_t bvm_tty_open; 50 static tsw_close_t bvm_tty_close; 51 static tsw_outwakeup_t bvm_tty_outwakeup; 52 53 static struct ttydevsw bvm_ttydevsw = { 54 .tsw_flags = TF_NOPREFIX, 55 .tsw_open = bvm_tty_open, 56 .tsw_close = bvm_tty_close, 57 .tsw_outwakeup = bvm_tty_outwakeup, 58 }; 59 60 static int polltime; 61 static struct callout bvm_timer; 62 63 #if defined(KDB) 64 static int alt_break_state; 65 #endif 66 67 #define BVM_CONS_PORT 0x220 68 static int bvm_cons_port = BVM_CONS_PORT; 69 70 #define BVM_CONS_SIG ('b' << 8 | 'v') 71 72 static void bvm_timeout(void *); 73 74 static cn_probe_t bvm_cnprobe; 75 static cn_init_t bvm_cninit; 76 static cn_term_t bvm_cnterm; 77 static cn_getc_t bvm_cngetc; 78 static cn_putc_t bvm_cnputc; 79 static cn_grab_t bvm_cngrab; 80 static cn_ungrab_t bvm_cnungrab; 81 82 CONSOLE_DRIVER(bvm); 83 84 static int 85 bvm_rcons(u_char *ch) 86 { 87 int c; 88 89 c = inl(bvm_cons_port); 90 if (c != -1) { 91 *ch = (u_char)c; 92 return (0); 93 } else 94 return (-1); 95 } 96 97 static void 98 bvm_wcons(u_char ch) 99 { 100 101 outl(bvm_cons_port, ch); 102 } 103 104 static void 105 cn_drvinit(void *unused) 106 { 107 struct tty *tp; 108 109 if (bvm_consdev.cn_pri != CN_DEAD) { 110 tp = tty_alloc(&bvm_ttydevsw, NULL); 111 callout_init_mtx(&bvm_timer, tty_getlock(tp), 0); 112 tty_makedev(tp, NULL, "bvmcons"); 113 } 114 } 115 116 static int 117 bvm_tty_open(struct tty *tp) 118 { 119 polltime = hz / BVMCONS_POLL_HZ; 120 if (polltime < 1) 121 polltime = 1; 122 callout_reset(&bvm_timer, polltime, bvm_timeout, tp); 123 124 return (0); 125 } 126 127 static void 128 bvm_tty_close(struct tty *tp) 129 { 130 131 tty_lock_assert(tp, MA_OWNED); 132 callout_stop(&bvm_timer); 133 } 134 135 static void 136 bvm_tty_outwakeup(struct tty *tp) 137 { 138 int len, written; 139 u_char buf[BVMBURSTLEN]; 140 141 for (;;) { 142 len = ttydisc_getc(tp, buf, sizeof(buf)); 143 if (len == 0) 144 break; 145 146 written = 0; 147 while (written < len) 148 bvm_wcons(buf[written++]); 149 } 150 } 151 152 static void 153 bvm_timeout(void *v) 154 { 155 struct tty *tp; 156 int c; 157 158 tp = (struct tty *)v; 159 160 tty_lock_assert(tp, MA_OWNED); 161 while ((c = bvm_cngetc(NULL)) != -1) 162 ttydisc_rint(tp, c, 0); 163 ttydisc_rint_done(tp); 164 165 callout_reset(&bvm_timer, polltime, bvm_timeout, tp); 166 } 167 168 static void 169 bvm_cnprobe(struct consdev *cp) 170 { 171 int disabled, port; 172 173 disabled = 0; 174 cp->cn_pri = CN_DEAD; 175 strcpy(cp->cn_name, "bvmcons"); 176 177 resource_int_value("bvmconsole", 0, "disabled", &disabled); 178 if (!disabled) { 179 if (resource_int_value("bvmconsole", 0, "port", &port) == 0) 180 bvm_cons_port = port; 181 182 if (inw(bvm_cons_port) == BVM_CONS_SIG) 183 cp->cn_pri = CN_REMOTE; 184 } 185 } 186 187 static void 188 bvm_cninit(struct consdev *cp) 189 { 190 int i; 191 const char *bootmsg = "Using bvm console.\n"; 192 193 if (boothowto & RB_VERBOSE) { 194 for (i = 0; i < strlen(bootmsg); i++) 195 bvm_cnputc(cp, bootmsg[i]); 196 } 197 } 198 199 static void 200 bvm_cnterm(struct consdev *cp) 201 { 202 203 } 204 205 static int 206 bvm_cngetc(struct consdev *cp) 207 { 208 unsigned char ch; 209 210 if (bvm_rcons(&ch) == 0) { 211 #if defined(KDB) 212 kdb_alt_break(ch, &alt_break_state); 213 #endif 214 return (ch); 215 } 216 217 return (-1); 218 } 219 220 static void 221 bvm_cnputc(struct consdev *cp, int c) 222 { 223 224 bvm_wcons(c); 225 } 226 227 static void 228 bvm_cngrab(struct consdev *cp) 229 { 230 } 231 232 static void 233 bvm_cnungrab(struct consdev *cp) 234 { 235 } 236 237 SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL); 238