1 /* $NetBSD: arcbios_tty.c,v 1.25 2014/07/25 08:10:36 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.25 2014/07/25 08:10:36 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_discard = nodiscard, 78 .d_flag = D_TTY, 79 }; 80 81 int 82 arcbios_ttyopen(dev_t dev, int flag, int mode, struct lwp *l) 83 { 84 int unit = minor(dev); 85 struct tty *tp; 86 int s, error = 0, setuptimeout = 0; 87 88 if (!arcbios_ch_init) { 89 arcbios_ch_init = true; 90 callout_init(&arcbios_tty_ch, 0); 91 } 92 93 if (unit != 0) 94 return (ENODEV); 95 96 s = spltty(); 97 98 if (arcbios_tty[unit] == NULL) { 99 tp = arcbios_tty[unit] = tty_alloc(); 100 tty_attach(tp); 101 } else 102 tp = arcbios_tty[unit]; 103 104 tp->t_oproc = arcbios_tty_start; 105 tp->t_param = arcbios_tty_param; 106 tp->t_dev = dev; 107 108 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) { 109 splx(s); 110 return (EBUSY); 111 } 112 113 if ((tp->t_state & TS_ISOPEN) == 0) { 114 tp->t_state |= TS_CARR_ON; 115 ttychars(tp); 116 tp->t_iflag = TTYDEF_IFLAG; 117 tp->t_oflag = TTYDEF_OFLAG; 118 tp->t_cflag = TTYDEF_CFLAG | CLOCAL; 119 tp->t_lflag = TTYDEF_LFLAG; 120 tp->t_ispeed = tp->t_ospeed = 9600; 121 ttsetwater(tp); 122 123 setuptimeout = 1; 124 } 125 126 splx(s); 127 128 error = (*tp->t_linesw->l_open)(dev, tp); 129 if (error == 0 && setuptimeout) 130 callout_reset(&arcbios_tty_ch, 1, arcbios_tty_poll, tp); 131 132 return (error); 133 } 134 135 int 136 arcbios_ttyclose(dev_t dev, int flag, int mode, struct lwp *l) 137 { 138 int unit = minor(dev); 139 struct tty *tp = arcbios_tty[unit]; 140 141 callout_stop(&arcbios_tty_ch); 142 (*tp->t_linesw->l_close)(tp, flag); 143 ttyclose(tp); 144 return (0); 145 } 146 147 int 148 arcbios_ttyread(dev_t dev, struct uio *uio, int flag) 149 { 150 struct tty *tp = arcbios_tty[minor(dev)]; 151 152 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 153 } 154 155 int 156 arcbios_ttywrite(dev_t dev, struct uio *uio, int flag) 157 { 158 struct tty *tp = arcbios_tty[minor(dev)]; 159 160 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 161 } 162 163 int 164 arcbios_ttypoll(dev_t dev, int events, struct lwp *l) 165 { 166 struct tty *tp = arcbios_tty[minor(dev)]; 167 168 return ((*tp->t_linesw->l_poll)(tp, events, l)); 169 } 170 171 int 172 arcbios_ttyioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 173 { 174 int unit = minor(dev); 175 struct tty *tp = arcbios_tty[unit]; 176 int error; 177 178 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 179 if (error != EPASSTHROUGH) 180 return (error); 181 return (ttioctl(tp, cmd, data, flag, l)); 182 } 183 184 int 185 arcbios_tty_param(struct tty *tp, struct termios *t) 186 { 187 188 return (0); 189 } 190 191 void 192 arcbios_tty_start(struct tty *tp) 193 { 194 u_long count; 195 int s; 196 197 s = spltty(); 198 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) 199 goto out; 200 ttypull(tp); 201 tp->t_state |= TS_BUSY; 202 while (tp->t_outq.c_cc != 0) { 203 arcbios_Write(ARCBIOS_STDOUT, tp->t_outq.c_cf, 204 ndqb(&tp->t_outq, 0), &count); 205 ndflush(&tp->t_outq, count); 206 } 207 tp->t_state &= ~TS_BUSY; 208 out: 209 splx(s); 210 } 211 212 void 213 arcbios_ttystop(struct tty *tp, int flag) 214 { 215 int s; 216 217 s = spltty(); 218 if (tp->t_state & TS_BUSY) 219 if ((tp->t_state & TS_TTSTOP) == 0) 220 tp->t_state |= TS_FLUSH; 221 splx(s); 222 } 223 224 static int 225 arcbios_tty_getchar(int *cp) 226 { 227 char c; 228 int32_t q; 229 u_long count; 230 231 q = arcbios_GetReadStatus(ARCBIOS_STDIN); 232 233 if (q == 0) { 234 arcbios_Read(ARCBIOS_STDIN, &c, 1, &count); 235 *cp = c; 236 237 return 1; 238 } 239 240 return 0; 241 } 242 243 void 244 arcbios_tty_poll(void *v) 245 { 246 struct tty *tp = v; 247 int c; 248 249 while (arcbios_tty_getchar(&c)) { 250 if (tp->t_state & TS_ISOPEN) 251 (void)(*tp->t_linesw->l_rint)(c, tp); 252 } 253 callout_reset(&arcbios_tty_ch, 1, arcbios_tty_poll, tp); 254 } 255 256 struct tty * 257 arcbios_ttytty(dev_t dev) 258 { 259 260 if (minor(dev) != 0) 261 panic("arcbios_ttytty: bogus"); 262 263 return (arcbios_tty[0]); 264 } 265