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