1 /* $NetBSD: arcbios_tty.c,v 1.24 2014/03/16 05:20:26 dholland Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 5 * All rights reserved. 6 * 7 * Author: Chris G. Demetriou 8 * 9 * Permission to use, copy, modify and distribute this software and 10 * its documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: arcbios_tty.c,v 1.24 2014/03/16 05:20:26 dholland Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/uio.h> 35 #include <sys/systm.h> 36 #include <sys/callout.h> 37 #include <sys/kernel.h> 38 #include <sys/conf.h> 39 #include <sys/proc.h> 40 #include <sys/tty.h> 41 #include <sys/termios.h> 42 #include <sys/kauth.h> 43 44 #include <dev/cons.h> 45 46 #include <dev/arcbios/arcbios.h> 47 #include <dev/arcbios/arcbiosvar.h> 48 49 callout_t arcbios_tty_ch; 50 bool arcbios_ch_init; 51 static struct tty *arcbios_tty[1]; 52 53 void arcbios_tty_start(struct tty *); 54 void arcbios_tty_poll(void *); 55 int arcbios_tty_param(struct tty *, struct termios *); 56 57 dev_type_open(arcbios_ttyopen); 58 dev_type_close(arcbios_ttyclose); 59 dev_type_read(arcbios_ttyread); 60 dev_type_write(arcbios_ttywrite); 61 dev_type_ioctl(arcbios_ttyioctl); 62 dev_type_stop(arcbios_ttystop); 63 dev_type_tty(arcbios_ttytty); 64 dev_type_poll(arcbios_ttypoll); 65 66 const struct cdevsw arcbios_cdevsw = { 67 .d_open = arcbios_ttyopen, 68 .d_close = arcbios_ttyclose, 69 .d_read = arcbios_ttyread, 70 .d_write = arcbios_ttywrite, 71 .d_ioctl = arcbios_ttyioctl, 72 .d_stop = arcbios_ttystop, 73 .d_tty = arcbios_ttytty, 74 .d_poll = arcbios_ttypoll, 75 .d_mmap = nommap, 76 .d_kqfilter = ttykqfilter, 77 .d_flag = D_TTY, 78 }; 79 80 int 81 arcbios_ttyopen(dev_t dev, int flag, int mode, struct lwp *l) 82 { 83 int unit = minor(dev); 84 struct tty *tp; 85 int s, error = 0, setuptimeout = 0; 86 87 if (!arcbios_ch_init) { 88 arcbios_ch_init = true; 89 callout_init(&arcbios_tty_ch, 0); 90 } 91 92 if (unit != 0) 93 return (ENODEV); 94 95 s = spltty(); 96 97 if (arcbios_tty[unit] == NULL) { 98 tp = arcbios_tty[unit] = tty_alloc(); 99 tty_attach(tp); 100 } else 101 tp = arcbios_tty[unit]; 102 103 tp->t_oproc = arcbios_tty_start; 104 tp->t_param = arcbios_tty_param; 105 tp->t_dev = dev; 106 107 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) { 108 splx(s); 109 return (EBUSY); 110 } 111 112 if ((tp->t_state & TS_ISOPEN) == 0) { 113 tp->t_state |= TS_CARR_ON; 114 ttychars(tp); 115 tp->t_iflag = TTYDEF_IFLAG; 116 tp->t_oflag = TTYDEF_OFLAG; 117 tp->t_cflag = TTYDEF_CFLAG | CLOCAL; 118 tp->t_lflag = TTYDEF_LFLAG; 119 tp->t_ispeed = tp->t_ospeed = 9600; 120 ttsetwater(tp); 121 122 setuptimeout = 1; 123 } 124 125 splx(s); 126 127 error = (*tp->t_linesw->l_open)(dev, tp); 128 if (error == 0 && setuptimeout) 129 callout_reset(&arcbios_tty_ch, 1, arcbios_tty_poll, tp); 130 131 return (error); 132 } 133 134 int 135 arcbios_ttyclose(dev_t dev, int flag, int mode, struct lwp *l) 136 { 137 int unit = minor(dev); 138 struct tty *tp = arcbios_tty[unit]; 139 140 callout_stop(&arcbios_tty_ch); 141 (*tp->t_linesw->l_close)(tp, flag); 142 ttyclose(tp); 143 return (0); 144 } 145 146 int 147 arcbios_ttyread(dev_t dev, struct uio *uio, int flag) 148 { 149 struct tty *tp = arcbios_tty[minor(dev)]; 150 151 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 152 } 153 154 int 155 arcbios_ttywrite(dev_t dev, struct uio *uio, int flag) 156 { 157 struct tty *tp = arcbios_tty[minor(dev)]; 158 159 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 160 } 161 162 int 163 arcbios_ttypoll(dev_t dev, int events, struct lwp *l) 164 { 165 struct tty *tp = arcbios_tty[minor(dev)]; 166 167 return ((*tp->t_linesw->l_poll)(tp, events, l)); 168 } 169 170 int 171 arcbios_ttyioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 172 { 173 int unit = minor(dev); 174 struct tty *tp = arcbios_tty[unit]; 175 int error; 176 177 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 178 if (error != EPASSTHROUGH) 179 return (error); 180 return (ttioctl(tp, cmd, data, flag, l)); 181 } 182 183 int 184 arcbios_tty_param(struct tty *tp, struct termios *t) 185 { 186 187 return (0); 188 } 189 190 void 191 arcbios_tty_start(struct tty *tp) 192 { 193 u_long count; 194 int s; 195 196 s = spltty(); 197 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) 198 goto out; 199 ttypull(tp); 200 tp->t_state |= TS_BUSY; 201 while (tp->t_outq.c_cc != 0) { 202 arcbios_Write(ARCBIOS_STDOUT, tp->t_outq.c_cf, 203 ndqb(&tp->t_outq, 0), &count); 204 ndflush(&tp->t_outq, count); 205 } 206 tp->t_state &= ~TS_BUSY; 207 out: 208 splx(s); 209 } 210 211 void 212 arcbios_ttystop(struct tty *tp, int flag) 213 { 214 int s; 215 216 s = spltty(); 217 if (tp->t_state & TS_BUSY) 218 if ((tp->t_state & TS_TTSTOP) == 0) 219 tp->t_state |= TS_FLUSH; 220 splx(s); 221 } 222 223 static int 224 arcbios_tty_getchar(int *cp) 225 { 226 char c; 227 int32_t q; 228 u_long count; 229 230 q = arcbios_GetReadStatus(ARCBIOS_STDIN); 231 232 if (q == 0) { 233 arcbios_Read(ARCBIOS_STDIN, &c, 1, &count); 234 *cp = c; 235 236 return 1; 237 } 238 239 return 0; 240 } 241 242 void 243 arcbios_tty_poll(void *v) 244 { 245 struct tty *tp = v; 246 int c; 247 248 while (arcbios_tty_getchar(&c)) { 249 if (tp->t_state & TS_ISOPEN) 250 (void)(*tp->t_linesw->l_rint)(c, tp); 251 } 252 callout_reset(&arcbios_tty_ch, 1, arcbios_tty_poll, tp); 253 } 254 255 struct tty * 256 arcbios_ttytty(dev_t dev) 257 { 258 259 if (minor(dev) != 0) 260 panic("arcbios_ttytty: bogus"); 261 262 return (arcbios_tty[0]); 263 } 264