1 1.86 riastrad /* $NetBSD: ser.c,v 1.86 2022/10/26 23:38:06 riastradh Exp $ */ 2 1.23 cgd 3 1.1 mw /* 4 1.1 mw * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 5 1.1 mw * All rights reserved. 6 1.1 mw * 7 1.1 mw * Redistribution and use in source and binary forms, with or without 8 1.1 mw * modification, are permitted provided that the following conditions 9 1.1 mw * are met: 10 1.1 mw * 1. Redistributions of source code must retain the above copyright 11 1.1 mw * notice, this list of conditions and the following disclaimer. 12 1.1 mw * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 mw * notice, this list of conditions and the following disclaimer in the 14 1.1 mw * documentation and/or other materials provided with the distribution. 15 1.69 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 mw * may be used to endorse or promote products derived from this software 17 1.1 mw * without specific prior written permission. 18 1.1 mw * 19 1.1 mw * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 mw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 mw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 mw * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 mw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 mw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 mw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 mw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 mw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 mw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 mw * SUCH DAMAGE. 30 1.1 mw * 31 1.4 mw * @(#)ser.c 7.12 (Berkeley) 6/27/91 32 1.15 chopps */ 33 1.15 chopps /* 34 1.32 is * XXX This file needs major cleanup it will never service more than one 35 1.15 chopps * XXX unit. 36 1.1 mw */ 37 1.57 lukem 38 1.58 aymeric #include "opt_amigacons.h" 39 1.66 aymeric #include "opt_ddb.h" 40 1.57 lukem #include "opt_kgdb.h" 41 1.61 aymeric 42 1.61 aymeric #include <sys/cdefs.h> 43 1.86 riastrad __KERNEL_RCSID(0, "$NetBSD: ser.c,v 1.86 2022/10/26 23:38:06 riastradh Exp $"); 44 1.1 mw 45 1.10 chopps #include <sys/param.h> 46 1.10 chopps #include <sys/systm.h> 47 1.10 chopps #include <sys/ioctl.h> 48 1.15 chopps #include <sys/device.h> 49 1.10 chopps #include <sys/tty.h> 50 1.10 chopps #include <sys/proc.h> 51 1.10 chopps #include <sys/file.h> 52 1.10 chopps #include <sys/uio.h> 53 1.10 chopps #include <sys/kernel.h> 54 1.10 chopps #include <sys/syslog.h> 55 1.13 chopps #include <sys/queue.h> 56 1.63 gehenna #include <sys/conf.h> 57 1.72 elad #include <sys/kauth.h> 58 1.15 chopps #include <machine/cpu.h> 59 1.15 chopps #include <amiga/amiga/device.h> 60 1.10 chopps #include <amiga/dev/serreg.h> 61 1.10 chopps #include <amiga/amiga/custom.h> 62 1.10 chopps #include <amiga/amiga/cia.h> 63 1.10 chopps #include <amiga/amiga/cc.h> 64 1.1 mw 65 1.14 chopps #include <dev/cons.h> 66 1.14 chopps 67 1.86 riastrad #include <ddb/db_active.h> 68 1.86 riastrad 69 1.15 chopps #include "ser.h" 70 1.15 chopps #if NSER > 0 71 1.14 chopps 72 1.80 chs void serattach(device_t, device_t, void *); 73 1.80 chs int sermatch(device_t, cfdata_t, void *); 74 1.15 chopps 75 1.28 jtc struct ser_softc { 76 1.28 jtc struct tty *ser_tty; 77 1.28 jtc }; 78 1.28 jtc 79 1.80 chs CFATTACH_DECL_NEW(ser, sizeof(struct ser_softc), 80 1.67 thorpej sermatch, serattach, NULL, NULL); 81 1.29 thorpej 82 1.43 thorpej extern struct cfdriver ser_cd; 83 1.15 chopps 84 1.63 gehenna dev_type_open(seropen); 85 1.63 gehenna dev_type_close(serclose); 86 1.63 gehenna dev_type_read(serread); 87 1.63 gehenna dev_type_write(serwrite); 88 1.63 gehenna dev_type_ioctl(serioctl); 89 1.63 gehenna dev_type_stop(serstop); 90 1.63 gehenna dev_type_tty(sertty); 91 1.63 gehenna dev_type_poll(serpoll); 92 1.63 gehenna 93 1.63 gehenna const struct cdevsw ser_cdevsw = { 94 1.82 dholland .d_open = seropen, 95 1.82 dholland .d_close = serclose, 96 1.82 dholland .d_read = serread, 97 1.82 dholland .d_write = serwrite, 98 1.82 dholland .d_ioctl = serioctl, 99 1.82 dholland .d_stop = serstop, 100 1.82 dholland .d_tty = sertty, 101 1.82 dholland .d_poll = serpoll, 102 1.82 dholland .d_mmap = nommap, 103 1.82 dholland .d_kqfilter = ttykqfilter, 104 1.83 dholland .d_discard = nodiscard, 105 1.82 dholland .d_flag = D_TTY 106 1.63 gehenna }; 107 1.63 gehenna 108 1.26 chopps #ifndef SEROBUF_SIZE 109 1.15 chopps #define SEROBUF_SIZE 32 110 1.26 chopps #endif 111 1.26 chopps #ifndef SERIBUF_SIZE 112 1.15 chopps #define SERIBUF_SIZE 512 113 1.26 chopps #endif 114 1.26 chopps 115 1.26 chopps #define splser() spl5() 116 1.1 mw 117 1.59 aymeric void serstart(struct tty *); 118 1.59 aymeric void ser_shutdown(struct ser_softc *); 119 1.59 aymeric int serparam(struct tty *, struct termios *); 120 1.59 aymeric void serintr(void); 121 1.59 aymeric int serhwiflow(struct tty *, int); 122 1.59 aymeric int sermctl(dev_t dev, int, int); 123 1.59 aymeric void ser_fastint(void); 124 1.59 aymeric void sereint(int); 125 1.59 aymeric static void ser_putchar(struct tty *, u_short); 126 1.59 aymeric void ser_outintr(void); 127 1.59 aymeric void sercnprobe(struct consdev *); 128 1.59 aymeric void sercninit(struct consdev *); 129 1.59 aymeric void serinit(int); 130 1.59 aymeric int sercngetc(dev_t dev); 131 1.59 aymeric void sercnputc(dev_t, int); 132 1.59 aymeric void sercnpollc(dev_t, int); 133 1.31 veego 134 1.1 mw int nser = NSER; 135 1.1 mw #ifdef SERCONSOLE 136 1.58 aymeric int serconsole = 0; 137 1.1 mw #else 138 1.1 mw int serconsole = -1; 139 1.1 mw #endif 140 1.1 mw int serconsinit; 141 1.1 mw int serdefaultrate = TTYDEF_SPEED; 142 1.14 chopps int serswflags; 143 1.14 chopps 144 1.44 is struct vbl_node ser_vbl_node; 145 1.1 mw struct tty ser_cons; 146 1.44 is struct tty *ser_tty; 147 1.44 is 148 1.44 is static u_short serbuf[SERIBUF_SIZE]; 149 1.44 is static u_short *sbrpt = serbuf; 150 1.44 is static u_short *sbwpt = serbuf; 151 1.44 is static u_short sbcnt; 152 1.44 is static u_short sbovfl; 153 1.44 is static u_char serdcd; 154 1.1 mw 155 1.59 aymeric /* 156 1.14 chopps * Since this UART is not particularly bright (to put it nicely), we'll 157 1.14 chopps * have to do parity stuff on our own. This table contains the 8th bit 158 1.14 chopps * in 7bit character mode, for even parity. If you want odd parity, 159 1.14 chopps * flip the bit. (for generation of the table, see genpar.c) 160 1.14 chopps */ 161 1.14 chopps 162 1.14 chopps u_char even_parity[] = { 163 1.14 chopps 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 164 1.14 chopps 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 165 1.14 chopps 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 166 1.14 chopps 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 167 1.14 chopps 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 168 1.14 chopps 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 169 1.14 chopps 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 170 1.14 chopps 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 171 1.1 mw }; 172 1.1 mw 173 1.59 aymeric /* 174 1.14 chopps * Since we don't get interrupts for changes on the modem control line, 175 1.14 chopps * we'll have to fake them by comparing current settings to the settings 176 1.14 chopps * we remembered on last invocation. 177 1.14 chopps */ 178 1.14 chopps 179 1.14 chopps u_char last_ciab_pra; 180 1.14 chopps 181 1.42 mhitch extern int ser_open_speed; /* current speed of open serial device */ 182 1.42 mhitch 183 1.1 mw #ifdef KGDB 184 1.10 chopps #include <machine/remote-sl.h> 185 1.1 mw 186 1.1 mw extern dev_t kgdb_dev; 187 1.1 mw extern int kgdb_rate; 188 1.1 mw extern int kgdb_debug_init; 189 1.1 mw #endif 190 1.1 mw 191 1.1 mw #ifdef DEBUG 192 1.1 mw long fifoin[17]; 193 1.1 mw long fifoout[17]; 194 1.1 mw long serintrcount[16]; 195 1.1 mw long sermintcount[16]; 196 1.1 mw #endif 197 1.1 mw 198 1.59 aymeric void sermint(register int unit); 199 1.5 mw 200 1.5 mw int 201 1.80 chs sermatch(device_t parent, cfdata_t cf, void *aux) 202 1.15 chopps { 203 1.50 kleink static int ser_matched = 0; 204 1.52 is static int ser_matched_real = 0; 205 1.29 thorpej 206 1.50 kleink /* Allow only once instance. */ 207 1.80 chs if (matchname("ser", (char *)aux) == 0) 208 1.15 chopps return(0); 209 1.52 is 210 1.52 is if (amiga_realconfig) { 211 1.52 is if (ser_matched_real) 212 1.52 is return(0); 213 1.52 is ser_matched_real = 1; 214 1.53 is } else { 215 1.53 is if (serconsole != 0) 216 1.53 is return(0); 217 1.52 is 218 1.53 is if (ser_matched != 0) 219 1.53 is return(0); 220 1.50 kleink 221 1.53 is ser_matched = 1; 222 1.53 is } 223 1.15 chopps return(1); 224 1.15 chopps } 225 1.15 chopps 226 1.15 chopps 227 1.15 chopps void 228 1.80 chs serattach(device_t parent, device_t self, void *aux) 229 1.1 mw { 230 1.44 is struct ser_softc *sc; 231 1.44 is struct tty *tp; 232 1.15 chopps u_short ir; 233 1.14 chopps 234 1.80 chs sc = device_private(self); 235 1.44 is 236 1.14 chopps ir = custom.intenar; 237 1.81 christos __USE(ir); 238 1.15 chopps if (serconsole == 0) 239 1.14 chopps DELAY(100000); 240 1.14 chopps 241 1.44 is ser_vbl_node.function = (void (*) (void *)) sermint; 242 1.44 is add_vbl_function(&ser_vbl_node, SER_VBL_PRIORITY, (void *) 0); 243 1.1 mw #ifdef KGDB 244 1.63 gehenna if (kgdb_dev == makedev(cdevsw_lookup_major(&ser_cdevsw), 0)) { 245 1.15 chopps if (serconsole == 0) 246 1.14 chopps kgdb_dev = NODEV; /* can't debug over console port */ 247 1.14 chopps else { 248 1.44 is (void) serinit(kgdb_rate); 249 1.14 chopps serconsinit = 1; /* don't re-init in serputc */ 250 1.14 chopps if (kgdb_debug_init == 0) 251 1.38 christos printf(" kgdb enabled\n"); 252 1.14 chopps else { 253 1.14 chopps /* 254 1.14 chopps * Print prefix of device name, 255 1.14 chopps * let kgdb_connect print the rest. 256 1.14 chopps */ 257 1.38 christos printf("ser0: "); 258 1.14 chopps kgdb_connect(1); 259 1.14 chopps } 260 1.14 chopps } 261 1.14 chopps } 262 1.5 mw #endif 263 1.14 chopps /* 264 1.14 chopps * Need to reset baud rate, etc. of next print so reset serconsinit. 265 1.14 chopps */ 266 1.15 chopps if (0 == serconsole) 267 1.14 chopps serconsinit = 0; 268 1.44 is 269 1.79 rmind tp = tty_alloc(); 270 1.44 is tp->t_oproc = (void (*) (struct tty *)) serstart; 271 1.44 is tp->t_param = serparam; 272 1.44 is tp->t_hwiflow = serhwiflow; 273 1.44 is tty_attach(tp); 274 1.44 is sc->ser_tty = ser_tty = tp; 275 1.44 is 276 1.80 chs if (self) 277 1.38 christos printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE, 278 1.15 chopps SEROBUF_SIZE); 279 1.1 mw } 280 1.1 mw 281 1.14 chopps 282 1.1 mw /* ARGSUSED */ 283 1.5 mw int 284 1.71 christos seropen(dev_t dev, int flag, int mode, struct lwp *l) 285 1.1 mw { 286 1.44 is struct ser_softc *sc; 287 1.14 chopps struct tty *tp; 288 1.44 is int unit, error, s, s2; 289 1.14 chopps 290 1.14 chopps error = 0; 291 1.14 chopps unit = SERUNIT(dev); 292 1.14 chopps 293 1.78 tsutsui sc = device_lookup_private(&ser_cd, unit); 294 1.78 tsutsui if (sc == NULL) 295 1.14 chopps return (ENXIO); 296 1.14 chopps 297 1.44 is /* XXX com.c: insert KGDB check here */ 298 1.44 is 299 1.44 is /* XXX ser.c had: s = spltty(); */ 300 1.44 is 301 1.44 is tp = sc->ser_tty; 302 1.44 is 303 1.74 elad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 304 1.44 is return (EBUSY); 305 1.44 is 306 1.14 chopps s = spltty(); 307 1.14 chopps 308 1.44 is /* 309 1.44 is * If this is a first open... 310 1.44 is */ 311 1.44 is 312 1.44 is if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { 313 1.44 is struct termios t; 314 1.14 chopps 315 1.44 is tp->t_dev = dev; 316 1.14 chopps 317 1.44 is s2 = splser(); 318 1.14 chopps /* 319 1.44 is * XXX here: hw enable, 320 1.14 chopps */ 321 1.46 is last_ciab_pra = ciab.pra; 322 1.44 is 323 1.44 is splx(s2); 324 1.44 is t.c_ispeed = 0; 325 1.44 is 326 1.44 is /* XXX serconsolerate? */ 327 1.44 is t.c_ospeed = TTYDEF_SPEED; 328 1.44 is t.c_cflag = TTYDEF_CFLAG; 329 1.44 is 330 1.14 chopps if (serswflags & TIOCFLAG_CLOCAL) 331 1.44 is t.c_cflag |= CLOCAL; 332 1.14 chopps if (serswflags & TIOCFLAG_CRTSCTS) 333 1.44 is t.c_cflag |= CRTSCTS; 334 1.14 chopps if (serswflags & TIOCFLAG_MDMBUF) 335 1.44 is t.c_cflag |= MDMBUF; 336 1.44 is 337 1.44 is /* Make sure serparam() will do something. */ 338 1.44 is tp->t_ospeed = 0; 339 1.44 is serparam(tp, &t); 340 1.44 is tp->t_iflag = TTYDEF_IFLAG; 341 1.44 is tp->t_oflag = TTYDEF_OFLAG; 342 1.44 is tp->t_lflag = TTYDEF_LFLAG; 343 1.44 is ttychars(tp); 344 1.14 chopps ttsetwater(tp); 345 1.44 is 346 1.44 is s2 = splser(); 347 1.45 is (void)sermctl(dev, TIOCM_DTR, DMSET); 348 1.44 is /* clear input ring */ 349 1.44 is sbrpt = sbwpt = serbuf; 350 1.44 is sbcnt = 0; 351 1.44 is splx(s2); 352 1.14 chopps } 353 1.14 chopps 354 1.44 is splx(s); 355 1.44 is 356 1.44 is error = ttyopen(tp, DIALOUT(dev), flag & O_NONBLOCK); 357 1.44 is if (error) 358 1.44 is goto bad; 359 1.44 is 360 1.55 aymeric error = tp->t_linesw->l_open(dev, tp); 361 1.44 is if (error) 362 1.44 is goto bad; 363 1.44 is 364 1.44 is return (0); 365 1.14 chopps 366 1.44 is bad: 367 1.44 is if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) { 368 1.44 is ser_shutdown(sc); 369 1.22 chopps } 370 1.22 chopps 371 1.44 is return (error); 372 1.1 mw } 373 1.14 chopps 374 1.1 mw /*ARGSUSED*/ 375 1.5 mw int 376 1.71 christos serclose(dev_t dev, int flag, int mode, struct lwp *l) 377 1.14 chopps { 378 1.44 is struct ser_softc *sc; 379 1.14 chopps struct tty *tp; 380 1.14 chopps 381 1.78 tsutsui sc = device_lookup_private(&ser_cd, SERUNIT(dev)); 382 1.44 is tp = ser_tty; 383 1.44 is 384 1.44 is /* XXX This is for cons.c, according to com.c */ 385 1.44 is if (!(tp->t_state & TS_ISOPEN)) 386 1.44 is return (0); 387 1.14 chopps 388 1.55 aymeric tp->t_linesw->l_close(tp, flag); 389 1.44 is ttyclose(tp); 390 1.44 is 391 1.44 is if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) { 392 1.44 is ser_shutdown(sc); 393 1.44 is } 394 1.44 is return (0); 395 1.44 is } 396 1.44 is 397 1.44 is void 398 1.59 aymeric ser_shutdown(struct ser_softc *sc) 399 1.44 is { 400 1.44 is struct tty *tp = sc->ser_tty; 401 1.44 is int s; 402 1.44 is 403 1.44 is s = splser(); 404 1.44 is 405 1.14 chopps custom.adkcon = ADKCONF_UARTBRK; /* clear break */ 406 1.44 is #if 0 /* XXX fix: #ifdef KGDB */ 407 1.59 aymeric /* 408 1.14 chopps * do not disable interrupts if debugging 409 1.14 chopps */ 410 1.14 chopps if (dev != kgdb_dev) 411 1.1 mw #endif 412 1.44 is custom.intena = INTF_RBF | INTF_TBE; /* disable interrupts */ 413 1.14 chopps custom.intreq = INTF_RBF | INTF_TBE; /* clear intr request */ 414 1.14 chopps 415 1.14 chopps /* 416 1.41 is * If HUPCL is not set, leave DTR unchanged. 417 1.14 chopps */ 418 1.44 is if (tp->t_cflag & HUPCL) { 419 1.44 is (void)sermctl(tp->t_dev, TIOCM_DTR, DMBIC); 420 1.44 is /* 421 1.59 aymeric * Idea from dev/ic/com.c: 422 1.44 is * sleep a bit so that other side will notice, even if we 423 1.44 is * reopen immediately. 424 1.44 is */ 425 1.44 is (void) tsleep(tp, TTIPRI, ttclos, hz); 426 1.44 is } 427 1.41 is 428 1.14 chopps #if not_yet 429 1.14 chopps if (tp != &ser_cons) { 430 1.44 is remove_vbl_function(&ser_vbl_node); 431 1.79 rmind tty_free(tp); 432 1.44 is ser_tty = (struct tty *) NULL; 433 1.14 chopps } 434 1.3 mw #endif 435 1.42 mhitch ser_open_speed = tp->t_ispeed; 436 1.81 christos splx(s); 437 1.44 is return; 438 1.1 mw } 439 1.14 chopps 440 1.5 mw int 441 1.59 aymeric serread(dev_t dev, struct uio *uio, int flag) 442 1.1 mw { 443 1.44 is /* ARGSUSED */ 444 1.44 is 445 1.55 aymeric return ser_tty->t_linesw->l_read(ser_tty, uio, flag); 446 1.14 chopps } 447 1.1 mw 448 1.5 mw int 449 1.59 aymeric serwrite(dev_t dev, struct uio *uio, int flag) 450 1.1 mw { 451 1.44 is /* ARGSUSED */ 452 1.14 chopps 453 1.55 aymeric return ser_tty->t_linesw->l_write(ser_tty, uio, flag); 454 1.56 scw } 455 1.56 scw 456 1.56 scw int 457 1.71 christos serpoll(dev_t dev, int events, struct lwp *l) 458 1.56 scw { 459 1.56 scw /* ARGSUSED */ 460 1.59 aymeric 461 1.71 christos return ser_tty->t_linesw->l_poll(ser_tty, events, l); 462 1.1 mw } 463 1.3 mw 464 1.27 chopps struct tty * 465 1.59 aymeric sertty(dev_t dev) 466 1.27 chopps { 467 1.44 is /* ARGSUSED */ 468 1.44 is 469 1.44 is return (ser_tty); 470 1.27 chopps } 471 1.3 mw 472 1.14 chopps /* 473 1.14 chopps * We don't do any processing of data here, so we store the raw code 474 1.14 chopps * obtained from the uart register. In theory, 110kBaud gives you 475 1.14 chopps * 11kcps, so 16k buffer should be more than enough, interrupt 476 1.14 chopps * latency of 1s should never happen, or something is seriously 477 1.14 chopps * wrong.. 478 1.44 is * buffers moved to above seropen() -is 479 1.14 chopps */ 480 1.14 chopps 481 1.14 chopps /* 482 1.14 chopps * This is a replacement for the lack of a hardware fifo. 32k should be 483 1.14 chopps * enough (there's only one unit anyway, so this is not going to 484 1.14 chopps * accumulate). 485 1.14 chopps */ 486 1.3 mw void 487 1.59 aymeric ser_fastint(void) 488 1.3 mw { 489 1.59 aymeric /* 490 1.14 chopps * We're at RBE-level, which is higher than VBL-level which is used 491 1.14 chopps * to periodically transmit contents of this buffer up one layer, 492 1.59 aymeric * so no spl-raising is necessary. 493 1.14 chopps */ 494 1.47 is u_short code; 495 1.14 chopps 496 1.47 is /* 497 1.47 is * This register contains both data and status bits! 498 1.47 is */ 499 1.47 is code = custom.serdatr; 500 1.14 chopps 501 1.40 mhitch /* 502 1.47 is * Use SERDATF_RBF instead of INTF_RBF; they're equivalent, but 503 1.47 is * we save one (slow) custom chip access. 504 1.40 mhitch */ 505 1.47 is if ((code & SERDATRF_RBF) == 0) 506 1.47 is return; 507 1.40 mhitch 508 1.59 aymeric /* 509 1.59 aymeric * clear interrupt 510 1.14 chopps */ 511 1.44 is custom.intreq = INTF_RBF; 512 1.14 chopps 513 1.14 chopps /* 514 1.14 chopps * check for buffer overflow. 515 1.14 chopps */ 516 1.22 chopps if (sbcnt == SERIBUF_SIZE) { 517 1.18 chopps ++sbovfl; 518 1.14 chopps return; 519 1.14 chopps } 520 1.14 chopps /* 521 1.14 chopps * store in buffer 522 1.14 chopps */ 523 1.14 chopps *sbwpt++ = code; 524 1.14 chopps if (sbwpt == serbuf + SERIBUF_SIZE) 525 1.14 chopps sbwpt = serbuf; 526 1.22 chopps ++sbcnt; 527 1.26 chopps if (sbcnt > SERIBUF_SIZE - 20) 528 1.22 chopps CLRRTS(ciab.pra); /* drop RTS if buffer almost full */ 529 1.3 mw } 530 1.3 mw 531 1.3 mw 532 1.31 veego void 533 1.59 aymeric serintr(void) 534 1.1 mw { 535 1.18 chopps int s1, s2, ovfl; 536 1.44 is struct tty *tp = ser_tty; 537 1.1 mw 538 1.14 chopps /* 539 1.14 chopps * Make sure we're not interrupted by another 540 1.14 chopps * vbl, but allow level5 ints 541 1.14 chopps */ 542 1.14 chopps s1 = spltty(); 543 1.1 mw 544 1.14 chopps /* 545 1.84 andvar * pass along any accumulated information 546 1.14 chopps */ 547 1.22 chopps while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) { 548 1.59 aymeric /* 549 1.14 chopps * no collision with ser_fastint() 550 1.14 chopps */ 551 1.44 is sereint(*sbrpt++); 552 1.14 chopps 553 1.18 chopps ovfl = 0; 554 1.14 chopps /* lock against ser_fastint() */ 555 1.26 chopps s2 = splser(); 556 1.22 chopps sbcnt--; 557 1.14 chopps if (sbrpt == serbuf + SERIBUF_SIZE) 558 1.14 chopps sbrpt = serbuf; 559 1.18 chopps if (sbovfl != 0) { 560 1.18 chopps ovfl = sbovfl; 561 1.18 chopps sbovfl = 0; 562 1.18 chopps } 563 1.14 chopps splx(s2); 564 1.18 chopps if (ovfl != 0) 565 1.21 chopps log(LOG_WARNING, "ser0: %d ring buffer overflows.\n", 566 1.21 chopps ovfl); 567 1.14 chopps } 568 1.33 is s2 = splser(); 569 1.22 chopps if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0) 570 1.22 chopps SETRTS(ciab.pra); /* start accepting data again */ 571 1.33 is splx(s2); 572 1.14 chopps splx(s1); 573 1.1 mw } 574 1.1 mw 575 1.31 veego void 576 1.59 aymeric sereint(int stat) 577 1.1 mw { 578 1.66 aymeric static int break_in_progress = 0; 579 1.14 chopps struct tty *tp; 580 1.14 chopps u_char ch; 581 1.14 chopps int c; 582 1.14 chopps 583 1.44 is tp = ser_tty; 584 1.49 is ch = stat & 0xff; 585 1.14 chopps c = ch; 586 1.14 chopps 587 1.14 chopps if ((tp->t_state & TS_ISOPEN) == 0) { 588 1.1 mw #ifdef KGDB 589 1.63 gehenna int maj; 590 1.63 gehenna 591 1.14 chopps /* we don't care about parity errors */ 592 1.63 gehenna maj = cdevsw_lookup_major(&ser_cdevsw); 593 1.63 gehenna if (kgdb_dev == makedev(maj, 0) && c == FRAME_END) 594 1.14 chopps kgdb_connect(0); /* trap into kgdb */ 595 1.1 mw #endif 596 1.14 chopps return; 597 1.14 chopps } 598 1.14 chopps 599 1.14 chopps /* 600 1.14 chopps * Check for break and (if enabled) parity error. 601 1.14 chopps */ 602 1.66 aymeric if ((stat & 0x1ff) == 0) { 603 1.66 aymeric if (break_in_progress) 604 1.66 aymeric return; 605 1.66 aymeric 606 1.66 aymeric c = TTY_FE; 607 1.66 aymeric break_in_progress = 1; 608 1.66 aymeric #ifdef DDB 609 1.66 aymeric if (serconsole == 0) { 610 1.66 aymeric if (!db_active) { 611 1.66 aymeric console_debugger(); 612 1.66 aymeric return; 613 1.66 aymeric } 614 1.66 aymeric } 615 1.66 aymeric #endif 616 1.66 aymeric } else { 617 1.66 aymeric break_in_progress = 0; 618 1.66 aymeric if ((tp->t_cflag & PARENB) && 619 1.66 aymeric (((ch >> 7) + even_parity[ch & 0x7f] 620 1.66 aymeric + !!(tp->t_cflag & PARODD)) & 1)) 621 1.14 chopps c |= TTY_PE; 622 1.66 aymeric } 623 1.14 chopps 624 1.14 chopps if (stat & SERDATRF_OVRUN) 625 1.15 chopps log(LOG_WARNING, "ser0: silo overflow\n"); 626 1.1 mw 627 1.55 aymeric tp->t_linesw->l_rint(c, tp); 628 1.14 chopps } 629 1.14 chopps 630 1.14 chopps /* 631 1.14 chopps * This interrupt is periodically invoked in the vertical blank 632 1.14 chopps * interrupt. It's used to keep track of the modem control lines 633 1.14 chopps * and (new with the fast_int code) to move accumulated data 634 1.14 chopps * up into the tty layer. 635 1.14 chopps */ 636 1.3 mw void 637 1.59 aymeric sermint(int unit) 638 1.1 mw { 639 1.14 chopps struct tty *tp; 640 1.14 chopps u_char stat, last, istat; 641 1.14 chopps 642 1.44 is tp = ser_tty; 643 1.14 chopps if (!tp) 644 1.14 chopps return; 645 1.14 chopps 646 1.44 is /* 647 1.44 is if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) { 648 1.14 chopps sbrpt = sbwpt = serbuf; 649 1.14 chopps return; 650 1.14 chopps } 651 1.44 is */ 652 1.14 chopps /* 653 1.14 chopps * empty buffer 654 1.14 chopps */ 655 1.44 is serintr(); 656 1.14 chopps 657 1.14 chopps stat = ciab.pra; 658 1.14 chopps last = last_ciab_pra; 659 1.14 chopps last_ciab_pra = stat; 660 1.14 chopps 661 1.14 chopps /* 662 1.14 chopps * check whether any interesting signal changed state 663 1.14 chopps */ 664 1.14 chopps istat = stat ^ last; 665 1.1 mw 666 1.44 is if (istat & serdcd) { 667 1.55 aymeric tp->t_linesw->l_modem(tp, ISDCD(stat)); 668 1.14 chopps } 669 1.44 is 670 1.14 chopps if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) && 671 1.14 chopps (tp->t_cflag & CRTSCTS)) { 672 1.5 mw #if 0 673 1.14 chopps /* the line is up and we want to do rts/cts flow control */ 674 1.14 chopps if (ISCTS(stat)) { 675 1.14 chopps tp->t_state &= ~TS_TTSTOP; 676 1.14 chopps ttstart(tp); 677 1.14 chopps /* cause tbe-int if we were stuck there */ 678 1.14 chopps custom.intreq = INTF_SETCLR | INTF_TBE; 679 1.14 chopps } else 680 1.14 chopps tp->t_state |= TS_TTSTOP; 681 1.5 mw #else 682 1.14 chopps /* do this on hardware level, not with tty driver */ 683 1.14 chopps if (ISCTS(stat)) { 684 1.14 chopps tp->t_state &= ~TS_TTSTOP; 685 1.14 chopps /* cause TBE interrupt */ 686 1.14 chopps custom.intreq = INTF_SETCLR | INTF_TBE; 687 1.14 chopps } 688 1.14 chopps #endif 689 1.5 mw } 690 1.1 mw } 691 1.1 mw 692 1.5 mw int 693 1.76 christos serioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 694 1.1 mw { 695 1.14 chopps register struct tty *tp; 696 1.14 chopps register int error; 697 1.14 chopps 698 1.44 is tp = ser_tty; 699 1.14 chopps if (!tp) 700 1.14 chopps return ENXIO; 701 1.14 chopps 702 1.71 christos error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, l); 703 1.62 atatat if (error != EPASSTHROUGH) 704 1.14 chopps return(error); 705 1.14 chopps 706 1.71 christos error = ttioctl(tp, cmd, data, flag, l); 707 1.62 atatat if (error != EPASSTHROUGH) 708 1.14 chopps return(error); 709 1.14 chopps 710 1.14 chopps switch (cmd) { 711 1.14 chopps case TIOCSBRK: 712 1.14 chopps custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK; 713 1.14 chopps break; 714 1.14 chopps 715 1.14 chopps case TIOCCBRK: 716 1.14 chopps custom.adkcon = ADKCONF_UARTBRK; 717 1.14 chopps break; 718 1.14 chopps 719 1.14 chopps case TIOCSDTR: 720 1.44 is (void) sermctl(dev, TIOCM_DTR, DMBIS); 721 1.14 chopps break; 722 1.14 chopps 723 1.14 chopps case TIOCCDTR: 724 1.44 is (void) sermctl(dev, TIOCM_DTR, DMBIC); 725 1.14 chopps break; 726 1.14 chopps 727 1.14 chopps case TIOCMSET: 728 1.14 chopps (void) sermctl(dev, *(int *) data, DMSET); 729 1.14 chopps break; 730 1.14 chopps 731 1.14 chopps case TIOCMBIS: 732 1.14 chopps (void) sermctl(dev, *(int *) data, DMBIS); 733 1.14 chopps break; 734 1.14 chopps 735 1.14 chopps case TIOCMBIC: 736 1.14 chopps (void) sermctl(dev, *(int *) data, DMBIC); 737 1.14 chopps break; 738 1.14 chopps 739 1.14 chopps case TIOCMGET: 740 1.14 chopps *(int *)data = sermctl(dev, 0, DMGET); 741 1.14 chopps break; 742 1.14 chopps case TIOCGFLAGS: 743 1.44 is *(int *)data = serswflags; 744 1.14 chopps break; 745 1.14 chopps case TIOCSFLAGS: 746 1.75 elad error = kauth_authorize_device_tty(l->l_cred, 747 1.75 elad KAUTH_DEVICE_TTY_PRIVSET, tp); 748 1.14 chopps if (error != 0) 749 1.59 aymeric return(EPERM); 750 1.14 chopps 751 1.14 chopps serswflags = *(int *)data; 752 1.14 chopps serswflags &= /* only allow valid flags */ 753 1.14 chopps (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); 754 1.14 chopps break; 755 1.14 chopps default: 756 1.62 atatat return(EPASSTHROUGH); 757 1.14 chopps } 758 1.1 mw 759 1.14 chopps return(0); 760 1.1 mw } 761 1.1 mw 762 1.5 mw int 763 1.59 aymeric serparam(struct tty *tp, struct termios *t) 764 1.1 mw { 765 1.44 is int cflag, ospeed = 0; 766 1.59 aymeric 767 1.32 is if (t->c_ospeed > 0) { 768 1.32 is if (t->c_ospeed < 110) 769 1.32 is return(EINVAL); 770 1.32 is ospeed = SERBRD(t->c_ospeed); 771 1.32 is } 772 1.32 is 773 1.32 is if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 774 1.14 chopps return(EINVAL); 775 1.14 chopps 776 1.60 aymeric if (serswflags & TIOCFLAG_SOFTCAR || serconsole == 0) { 777 1.44 is t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL; 778 1.44 is } 779 1.44 is 780 1.44 is /* if no changes, dont do anything. com.c explains why. */ 781 1.44 is if (tp->t_ospeed == t->c_ospeed && 782 1.44 is tp->t_cflag == t->c_cflag) 783 1.44 is return (0); 784 1.44 is 785 1.44 is cflag = t->c_cflag; 786 1.44 is 787 1.44 is if (cflag & (CLOCAL | MDMBUF)) 788 1.44 is serdcd = 0; 789 1.44 is else 790 1.44 is serdcd = CIAB_PRA_CD; 791 1.44 is 792 1.44 is /* TODO: support multiple flow control protocols like com.c */ 793 1.44 is 794 1.59 aymeric /* 795 1.14 chopps * copy to tty 796 1.14 chopps */ 797 1.14 chopps tp->t_ispeed = t->c_ispeed; 798 1.14 chopps tp->t_ospeed = t->c_ospeed; 799 1.14 chopps tp->t_cflag = cflag; 800 1.42 mhitch ser_open_speed = tp->t_ispeed; 801 1.14 chopps 802 1.14 chopps /* 803 1.14 chopps * enable interrupts 804 1.14 chopps */ 805 1.14 chopps custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE; 806 1.14 chopps last_ciab_pra = ciab.pra; 807 1.14 chopps 808 1.32 is if (t->c_ospeed == 0) 809 1.14 chopps (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */ 810 1.14 chopps else { 811 1.59 aymeric /* 812 1.14 chopps * (re)enable DTR 813 1.14 chopps * and set baud rate. (8 bit mode) 814 1.14 chopps */ 815 1.45 is (void)sermctl(tp->t_dev, TIOCM_DTR, DMSET); 816 1.14 chopps custom.serper = (0 << 15) | ospeed; 817 1.14 chopps } 818 1.55 aymeric (void)tp->t_linesw->l_modem(tp, ISDCD(last_ciab_pra)); 819 1.59 aymeric 820 1.14 chopps return(0); 821 1.1 mw } 822 1.3 mw 823 1.59 aymeric int serhwiflow(struct tty *tp, int flag) 824 1.22 chopps { 825 1.22 chopps #if 0 826 1.38 christos printf ("serhwiflow %d\n", flag); 827 1.22 chopps #endif 828 1.22 chopps if (flag) 829 1.22 chopps CLRRTS(ciab.pra); 830 1.22 chopps else 831 1.22 chopps SETRTS(ciab.pra); 832 1.22 chopps return 1; 833 1.22 chopps } 834 1.3 mw 835 1.3 mw static void 836 1.59 aymeric ser_putchar(struct tty *tp, u_short c) 837 1.14 chopps { 838 1.49 is if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB)) 839 1.49 is c &= 0x7f; 840 1.14 chopps 841 1.14 chopps /* 842 1.14 chopps * handle parity if necessary 843 1.14 chopps */ 844 1.49 is if (tp->t_cflag & PARENB) { 845 1.14 chopps if (even_parity[c]) 846 1.49 is c |= 0x80; 847 1.49 is if (tp->t_cflag & PARODD) 848 1.49 is c ^= 0x80; 849 1.14 chopps } 850 1.59 aymeric /* 851 1.14 chopps * add stop bit(s) 852 1.14 chopps */ 853 1.49 is if (tp->t_cflag & CSTOPB) 854 1.49 is c |= 0x300; 855 1.49 is else 856 1.49 is c |= 0x100; 857 1.14 chopps 858 1.14 chopps custom.serdat = c; 859 1.3 mw } 860 1.3 mw 861 1.3 mw 862 1.3 mw static u_char ser_outbuf[SEROBUF_SIZE]; 863 1.14 chopps static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf; 864 1.14 chopps 865 1.3 mw void 866 1.59 aymeric ser_outintr(void) 867 1.3 mw { 868 1.44 is struct tty *tp; 869 1.14 chopps int s; 870 1.14 chopps 871 1.44 is tp = ser_tty; 872 1.14 chopps s = spltty(); 873 1.14 chopps 874 1.14 chopps if (tp == 0) 875 1.14 chopps goto out; 876 1.14 chopps 877 1.14 chopps if ((custom.intreqr & INTF_TBE) == 0) 878 1.14 chopps goto out; 879 1.14 chopps 880 1.14 chopps /* 881 1.14 chopps * clear interrupt 882 1.14 chopps */ 883 1.14 chopps custom.intreq = INTF_TBE; 884 1.14 chopps 885 1.14 chopps if (sob_ptr == sob_end) { 886 1.14 chopps tp->t_state &= ~(TS_BUSY | TS_FLUSH); 887 1.55 aymeric if (tp->t_linesw) 888 1.55 aymeric tp->t_linesw->l_start(tp); 889 1.14 chopps else 890 1.14 chopps serstart(tp); 891 1.14 chopps goto out; 892 1.14 chopps } 893 1.14 chopps 894 1.14 chopps /* 895 1.14 chopps * Do hardware flow control here. if the CTS line goes down, don't 896 1.14 chopps * transmit anything. That way, we'll be restarted by the periodic 897 1.59 aymeric * interrupt when CTS comes back up. 898 1.14 chopps */ 899 1.14 chopps if (ISCTS(ciab.pra)) 900 1.14 chopps ser_putchar(tp, *sob_ptr++); 901 1.22 chopps else 902 1.22 chopps CLRCTS(last_ciab_pra); /* Remember that CTS is off */ 903 1.5 mw out: 904 1.14 chopps splx(s); 905 1.3 mw } 906 1.14 chopps 907 1.31 veego void 908 1.59 aymeric serstart(struct tty *tp) 909 1.1 mw { 910 1.44 is int cc, s, hiwat; 911 1.44 is #ifdef DIAGNOSTIC 912 1.44 is int unit; 913 1.44 is #endif 914 1.59 aymeric 915 1.14 chopps hiwat = 0; 916 1.14 chopps 917 1.14 chopps if ((tp->t_state & TS_ISOPEN) == 0) 918 1.14 chopps return; 919 1.14 chopps 920 1.44 is #ifdef DIAGNOSTIC 921 1.14 chopps unit = SERUNIT(tp->t_dev); 922 1.44 is if (unit) 923 1.64 provos panic("serstart: unit is %d", unit); 924 1.44 is #endif 925 1.1 mw 926 1.14 chopps s = spltty(); 927 1.14 chopps if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) 928 1.14 chopps goto out; 929 1.14 chopps 930 1.14 chopps cc = tp->t_outq.c_cc; 931 1.77 ad if (!ttypull(tp) || (tp->t_state & TS_BUSY)) 932 1.14 chopps goto out; 933 1.14 chopps 934 1.14 chopps /* 935 1.14 chopps * We only do bulk transfers if using CTSRTS flow control, not for 936 1.14 chopps * (probably sloooow) ixon/ixoff devices. 937 1.14 chopps */ 938 1.14 chopps if ((tp->t_cflag & CRTSCTS) == 0) 939 1.14 chopps cc = 1; 940 1.14 chopps 941 1.14 chopps /* 942 1.14 chopps * Limit the amount of output we do in one burst 943 1.14 chopps * to prevent hogging the CPU. 944 1.14 chopps */ 945 1.14 chopps if (cc > SEROBUF_SIZE) { 946 1.14 chopps hiwat++; 947 1.14 chopps cc = SEROBUF_SIZE; 948 1.14 chopps } 949 1.14 chopps cc = q_to_b(&tp->t_outq, ser_outbuf, cc); 950 1.14 chopps if (cc > 0) { 951 1.14 chopps tp->t_state |= TS_BUSY; 952 1.14 chopps 953 1.14 chopps sob_ptr = ser_outbuf; 954 1.14 chopps sob_end = ser_outbuf + cc; 955 1.14 chopps 956 1.14 chopps /* 957 1.14 chopps * Get first character out, then have TBE-interrupts blow out 958 1.14 chopps * further characters, until buffer is empty, and TS_BUSY gets 959 1.59 aymeric * cleared. 960 1.14 chopps */ 961 1.14 chopps ser_putchar(tp, *sob_ptr++); 962 1.14 chopps } 963 1.14 chopps out: 964 1.14 chopps splx(s); 965 1.1 mw } 966 1.14 chopps 967 1.1 mw /* 968 1.1 mw * Stop output on a line. 969 1.1 mw */ 970 1.1 mw /*ARGSUSED*/ 971 1.36 mycroft void 972 1.59 aymeric serstop(struct tty *tp, int flag) 973 1.1 mw { 974 1.14 chopps int s; 975 1.1 mw 976 1.14 chopps s = spltty(); 977 1.14 chopps if (tp->t_state & TS_BUSY) { 978 1.14 chopps if ((tp->t_state & TS_TTSTOP) == 0) 979 1.14 chopps tp->t_state |= TS_FLUSH; 980 1.14 chopps } 981 1.14 chopps splx(s); 982 1.1 mw } 983 1.14 chopps 984 1.5 mw int 985 1.59 aymeric sermctl(dev_t dev, int bits, int how) 986 1.1 mw { 987 1.44 is int s; 988 1.31 veego u_char ub = 0; 989 1.14 chopps 990 1.14 chopps /* 991 1.14 chopps * convert TIOCM* mask into CIA mask 992 1.14 chopps * which is active low 993 1.14 chopps */ 994 1.14 chopps if (how != DMGET) { 995 1.14 chopps ub = 0; 996 1.14 chopps if (bits & TIOCM_DTR) 997 1.14 chopps ub |= CIAB_PRA_DTR; 998 1.14 chopps if (bits & TIOCM_RTS) 999 1.14 chopps ub |= CIAB_PRA_RTS; 1000 1.14 chopps if (bits & TIOCM_CTS) 1001 1.14 chopps ub |= CIAB_PRA_CTS; 1002 1.14 chopps if (bits & TIOCM_CD) 1003 1.14 chopps ub |= CIAB_PRA_CD; 1004 1.14 chopps if (bits & TIOCM_RI) 1005 1.14 chopps ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */ 1006 1.14 chopps if (bits & TIOCM_DSR) 1007 1.14 chopps ub |= CIAB_PRA_DSR; 1008 1.14 chopps } 1009 1.14 chopps s = spltty(); 1010 1.14 chopps switch (how) { 1011 1.14 chopps case DMSET: 1012 1.14 chopps /* invert and set */ 1013 1.14 chopps ciab.pra = ~ub; 1014 1.14 chopps break; 1015 1.14 chopps 1016 1.14 chopps case DMBIC: 1017 1.14 chopps ciab.pra |= ub; 1018 1.14 chopps ub = ~ciab.pra; 1019 1.14 chopps break; 1020 1.14 chopps 1021 1.14 chopps case DMBIS: 1022 1.14 chopps ciab.pra &= ~ub; 1023 1.14 chopps ub = ~ciab.pra; 1024 1.14 chopps break; 1025 1.14 chopps 1026 1.14 chopps case DMGET: 1027 1.14 chopps ub = ~ciab.pra; 1028 1.14 chopps break; 1029 1.14 chopps } 1030 1.14 chopps (void)splx(s); 1031 1.14 chopps 1032 1.14 chopps bits = 0; 1033 1.14 chopps if (ub & CIAB_PRA_DTR) 1034 1.14 chopps bits |= TIOCM_DTR; 1035 1.14 chopps if (ub & CIAB_PRA_RTS) 1036 1.14 chopps bits |= TIOCM_RTS; 1037 1.14 chopps if (ub & CIAB_PRA_CTS) 1038 1.14 chopps bits |= TIOCM_CTS; 1039 1.14 chopps if (ub & CIAB_PRA_CD) 1040 1.14 chopps bits |= TIOCM_CD; 1041 1.14 chopps if (ub & CIAB_PRA_SEL) 1042 1.14 chopps bits |= TIOCM_RI; 1043 1.14 chopps if (ub & CIAB_PRA_DSR) 1044 1.14 chopps bits |= TIOCM_DSR; 1045 1.14 chopps 1046 1.14 chopps return(bits); 1047 1.1 mw } 1048 1.1 mw 1049 1.1 mw /* 1050 1.1 mw * Following are all routines needed for SER to act as console 1051 1.1 mw */ 1052 1.31 veego void 1053 1.59 aymeric sercnprobe(struct consdev *cp) 1054 1.1 mw { 1055 1.63 gehenna int maj, unit; 1056 1.63 gehenna #ifdef KGDB 1057 1.63 gehenna extern const struct cdevsw ctty_cdevsw; 1058 1.63 gehenna #endif 1059 1.59 aymeric 1060 1.14 chopps /* locate the major number */ 1061 1.63 gehenna maj = cdevsw_lookup_major(&ser_cdevsw); 1062 1.14 chopps 1063 1.59 aymeric 1064 1.14 chopps unit = CONUNIT; /* XXX: ick */ 1065 1.14 chopps 1066 1.14 chopps /* 1067 1.14 chopps * initialize required fields 1068 1.14 chopps */ 1069 1.63 gehenna cp->cn_dev = makedev(maj, unit); 1070 1.14 chopps if (serconsole == unit) 1071 1.14 chopps cp->cn_pri = CN_REMOTE; 1072 1.59 aymeric else 1073 1.14 chopps cp->cn_pri = CN_NORMAL; 1074 1.1 mw #ifdef KGDB 1075 1.63 gehenna /* XXX */ 1076 1.63 gehenna if (cdevsw_lookup(kgdb_dev) == &ctty_cdevsw) 1077 1.63 gehenna kgdb_dev = makedev(maj, minor(kgdb_dev)); 1078 1.1 mw #endif 1079 1.1 mw } 1080 1.1 mw 1081 1.31 veego void 1082 1.59 aymeric sercninit(struct consdev *cp) 1083 1.1 mw { 1084 1.14 chopps int unit; 1085 1.1 mw 1086 1.14 chopps unit = SERUNIT(cp->cn_dev); 1087 1.14 chopps 1088 1.44 is serinit(serdefaultrate); 1089 1.14 chopps serconsole = unit; 1090 1.14 chopps serconsinit = 1; 1091 1.1 mw } 1092 1.1 mw 1093 1.31 veego void 1094 1.59 aymeric serinit(int rate) 1095 1.1 mw { 1096 1.14 chopps int s; 1097 1.1 mw 1098 1.26 chopps s = splser(); 1099 1.14 chopps /* 1100 1.14 chopps * might want to fiddle with the CIA later ??? 1101 1.14 chopps */ 1102 1.32 is custom.serper = (rate>=110 ? SERBRD(rate) : 0); 1103 1.14 chopps splx(s); 1104 1.1 mw } 1105 1.1 mw 1106 1.31 veego int 1107 1.59 aymeric sercngetc(dev_t dev) 1108 1.1 mw { 1109 1.14 chopps u_short stat; 1110 1.14 chopps int c, s; 1111 1.1 mw 1112 1.26 chopps s = splser(); 1113 1.14 chopps /* 1114 1.14 chopps * poll 1115 1.14 chopps */ 1116 1.14 chopps while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0) 1117 1.14 chopps ; 1118 1.66 aymeric 1119 1.14 chopps c = stat & 0xff; 1120 1.14 chopps /* 1121 1.14 chopps * clear interrupt 1122 1.14 chopps */ 1123 1.14 chopps custom.intreq = INTF_RBF; 1124 1.14 chopps splx(s); 1125 1.66 aymeric 1126 1.14 chopps return(c); 1127 1.1 mw } 1128 1.1 mw 1129 1.1 mw /* 1130 1.1 mw * Console kernel output character routine. 1131 1.1 mw */ 1132 1.31 veego void 1133 1.59 aymeric sercnputc(dev_t dev, int c) 1134 1.1 mw { 1135 1.14 chopps register int timo; 1136 1.14 chopps int s; 1137 1.14 chopps 1138 1.14 chopps s = splhigh(); 1139 1.1 mw 1140 1.14 chopps if (serconsinit == 0) { 1141 1.44 is (void)serinit(serdefaultrate); 1142 1.14 chopps serconsinit = 1; 1143 1.14 chopps } 1144 1.14 chopps 1145 1.14 chopps /* 1146 1.59 aymeric * wait for any pending transmission to finish 1147 1.14 chopps */ 1148 1.14 chopps timo = 50000; 1149 1.14 chopps while (!(custom.serdatr & SERDATRF_TBE) && --timo); 1150 1.14 chopps 1151 1.14 chopps /* 1152 1.14 chopps * transmit char. 1153 1.14 chopps */ 1154 1.14 chopps custom.serdat = (c & 0xff) | 0x100; 1155 1.14 chopps 1156 1.59 aymeric /* 1157 1.14 chopps * wait for this transmission to complete 1158 1.14 chopps */ 1159 1.14 chopps timo = 1500000; 1160 1.14 chopps while (!(custom.serdatr & SERDATRF_TBE) && --timo) 1161 1.14 chopps ; 1162 1.14 chopps 1163 1.14 chopps /* 1164 1.14 chopps * Wait for the device (my vt100..) to process the data, since we 1165 1.14 chopps * don't do flow-control with cnputc 1166 1.14 chopps */ 1167 1.14 chopps for (timo = 0; timo < 30000; timo++) 1168 1.14 chopps ; 1169 1.14 chopps 1170 1.59 aymeric /* 1171 1.51 aymeric * We set TBE so that ser_outintr() is called right after to check 1172 1.51 aymeric * whether there still are chars to process. 1173 1.51 aymeric * We used to clear this, but it hung the tty output if the kernel 1174 1.51 aymeric * output a char while userland did on the same serial port. 1175 1.14 chopps */ 1176 1.51 aymeric custom.intreq = INTF_SETCLR | INTF_TBE; 1177 1.14 chopps splx(s); 1178 1.25 chopps } 1179 1.25 chopps 1180 1.25 chopps void 1181 1.59 aymeric sercnpollc(dev_t dev, int on) 1182 1.25 chopps { 1183 1.1 mw } 1184 1.1 mw #endif 1185