1 /* $NetBSD: arcbios_tty.c,v 1.13 2006/05/15 20:47:22 yamt 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.13 2006/05/15 20:47:22 yamt Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/user.h> 35 #include <sys/uio.h> 36 #include <sys/systm.h> 37 #include <sys/callout.h> 38 #include <sys/kernel.h> 39 #include <sys/conf.h> 40 #include <sys/proc.h> 41 #include <sys/tty.h> 42 #include <sys/termios.h> 43 #include <sys/kauth.h> 44 45 #include <dev/cons.h> 46 47 #include <dev/arcbios/arcbios.h> 48 #include <dev/arcbios/arcbiosvar.h> 49 50 struct callout arcbios_tty_ch = CALLOUT_INITIALIZER; 51 52 static struct tty *arcbios_tty[1]; 53 54 void arcbios_tty_start(struct tty *); 55 void arcbios_tty_poll(void *); 56 int arcbios_tty_param(struct tty *, struct termios *); 57 58 dev_type_open(arcbios_ttyopen); 59 dev_type_close(arcbios_ttyclose); 60 dev_type_read(arcbios_ttyread); 61 dev_type_write(arcbios_ttywrite); 62 dev_type_ioctl(arcbios_ttyioctl); 63 dev_type_stop(arcbios_ttystop); 64 dev_type_tty(arcbios_ttytty); 65 dev_type_poll(arcbios_ttypoll); 66 67 const struct cdevsw arcbios_cdevsw = { 68 arcbios_ttyopen, arcbios_ttyclose, arcbios_ttyread, arcbios_ttywrite, 69 arcbios_ttyioctl, arcbios_ttystop, arcbios_ttytty, arcbios_ttypoll, 70 nommap, ttykqfilter, D_TTY, 71 }; 72 73 int 74 arcbios_ttyopen(dev_t dev, int flag, int mode, struct lwp *l) 75 { 76 int unit = minor(dev); 77 struct tty *tp; 78 int s, error = 0, setuptimeout = 0; 79 80 if (unit != 0) 81 return (ENODEV); 82 83 s = spltty(); 84 85 if (arcbios_tty[unit] == NULL) { 86 tp = arcbios_tty[unit] = ttymalloc(); 87 tty_attach(tp); 88 } else 89 tp = arcbios_tty[unit]; 90 91 tp->t_oproc = arcbios_tty_start; 92 tp->t_param = arcbios_tty_param; 93 tp->t_dev = dev; 94 if ((tp->t_state & TS_ISOPEN) == 0) { 95 tp->t_state |= TS_CARR_ON; 96 ttychars(tp); 97 tp->t_iflag = TTYDEF_IFLAG; 98 tp->t_oflag = TTYDEF_OFLAG; 99 tp->t_cflag = TTYDEF_CFLAG | CLOCAL; 100 tp->t_lflag = TTYDEF_LFLAG; 101 tp->t_ispeed = tp->t_ospeed = 9600; 102 ttsetwater(tp); 103 104 setuptimeout = 1; 105 } else if (tp->t_state & TS_XCLUDE && 106 kauth_authorize_generic(l->l_proc->p_cred, KAUTH_GENERIC_ISSUSER, 107 &l->l_proc->p_acflag) != 0) { 108 splx(s); 109 return (EBUSY); 110 } 111 112 splx(s); 113 114 error = (*tp->t_linesw->l_open)(dev, tp); 115 if (error == 0 && setuptimeout) 116 callout_reset(&arcbios_tty_ch, 1, arcbios_tty_poll, tp); 117 118 return (error); 119 } 120 121 int 122 arcbios_ttyclose(dev_t dev, int flag, int mode, struct lwp *l) 123 { 124 int unit = minor(dev); 125 struct tty *tp = arcbios_tty[unit]; 126 127 callout_stop(&arcbios_tty_ch); 128 (*tp->t_linesw->l_close)(tp, flag); 129 ttyclose(tp); 130 return (0); 131 } 132 133 int 134 arcbios_ttyread(dev_t dev, struct uio *uio, int flag) 135 { 136 struct tty *tp = arcbios_tty[minor(dev)]; 137 138 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 139 } 140 141 int 142 arcbios_ttywrite(dev_t dev, struct uio *uio, int flag) 143 { 144 struct tty *tp = arcbios_tty[minor(dev)]; 145 146 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 147 } 148 149 int 150 arcbios_ttypoll(dev_t dev, int events, struct lwp *l) 151 { 152 struct tty *tp = arcbios_tty[minor(dev)]; 153 154 return ((*tp->t_linesw->l_poll)(tp, events, l)); 155 } 156 157 int 158 arcbios_ttyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l) 159 { 160 int unit = minor(dev); 161 struct tty *tp = arcbios_tty[unit]; 162 int error; 163 164 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 165 if (error != EPASSTHROUGH) 166 return (error); 167 return (ttioctl(tp, cmd, data, flag, l)); 168 } 169 170 int 171 arcbios_tty_param(struct tty *tp, struct termios *t) 172 { 173 174 return (0); 175 } 176 177 void 178 arcbios_tty_start(struct tty *tp) 179 { 180 u_long count; 181 int s; 182 183 s = spltty(); 184 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) 185 goto out; 186 if (tp->t_outq.c_cc <= tp->t_lowat) { 187 if (tp->t_state & TS_ASLEEP) { 188 tp->t_state &= ~TS_ASLEEP; 189 wakeup((caddr_t)&tp->t_outq); 190 } 191 selwakeup(&tp->t_wsel); 192 } 193 tp->t_state |= TS_BUSY; 194 while (tp->t_outq.c_cc != 0) { 195 (*ARCBIOS->Write)(ARCBIOS_STDOUT, tp->t_outq.c_cf, 196 ndqb(&tp->t_outq, 0), &count); 197 ndflush(&tp->t_outq, count); 198 } 199 tp->t_state &= ~TS_BUSY; 200 out: 201 splx(s); 202 } 203 204 void 205 arcbios_ttystop(struct tty *tp, int flag) 206 { 207 int s; 208 209 s = spltty(); 210 if (tp->t_state & TS_BUSY) 211 if ((tp->t_state & TS_TTSTOP) == 0) 212 tp->t_state |= TS_FLUSH; 213 splx(s); 214 } 215 216 static int 217 arcbios_tty_getchar(int *cp) 218 { 219 char c; 220 int32_t q; 221 u_long count; 222 223 q = ARCBIOS->GetReadStatus(ARCBIOS_STDIN); 224 225 if (q == 0) { 226 ARCBIOS->Read(ARCBIOS_STDIN, &c, 1, &count); 227 *cp = c; 228 229 return 1; 230 } 231 232 return 0; 233 } 234 235 void 236 arcbios_tty_poll(void *v) 237 { 238 struct tty *tp = v; 239 int c, l_r; 240 241 while (arcbios_tty_getchar(&c)) { 242 if (tp->t_state & TS_ISOPEN) 243 l_r = (*tp->t_linesw->l_rint)(c, tp); 244 } 245 callout_reset(&arcbios_tty_ch, 1, arcbios_tty_poll, tp); 246 } 247 248 struct tty * 249 arcbios_ttytty(dev_t dev) 250 { 251 252 if (minor(dev) != 0) 253 panic("arcbios_ttytty: bogus"); 254 255 return (arcbios_tty[0]); 256 } 257