1 1.62 rillig /* $NetBSD: mfc.c,v 1.62 2024/09/08 09:36:48 rillig Exp $ */ 2 1.3 chopps 3 1.1 chopps /* 4 1.1 chopps * Copyright (c) 1982, 1990 The Regents of the University of California. 5 1.1 chopps * All rights reserved. 6 1.1 chopps * 7 1.1 chopps * Redistribution and use in source and binary forms, with or without 8 1.1 chopps * modification, are permitted provided that the following conditions 9 1.1 chopps * are met: 10 1.1 chopps * 1. Redistributions of source code must retain the above copyright 11 1.1 chopps * notice, this list of conditions and the following disclaimer. 12 1.1 chopps * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 chopps * notice, this list of conditions and the following disclaimer in the 14 1.1 chopps * documentation and/or other materials provided with the distribution. 15 1.33 agc * 3. Neither the name of the University nor the names of its contributors 16 1.33 agc * may be used to endorse or promote products derived from this software 17 1.33 agc * without specific prior written permission. 18 1.33 agc * 19 1.33 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.33 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.33 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.33 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.33 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.33 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.33 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.33 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.33 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.33 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.33 agc * SUCH DAMAGE. 30 1.33 agc */ 31 1.33 agc /* 32 1.33 agc * Copyright (c) 1994 Michael L. Hitch 33 1.33 agc * 34 1.33 agc * Redistribution and use in source and binary forms, with or without 35 1.33 agc * modification, are permitted provided that the following conditions 36 1.33 agc * are met: 37 1.33 agc * 1. Redistributions of source code must retain the above copyright 38 1.33 agc * notice, this list of conditions and the following disclaimer. 39 1.33 agc * 2. Redistributions in binary form must reproduce the above copyright 40 1.33 agc * notice, this list of conditions and the following disclaimer in the 41 1.33 agc * documentation and/or other materials provided with the distribution. 42 1.1 chopps * 43 1.34 mhitch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 44 1.34 mhitch * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 45 1.34 mhitch * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 46 1.34 mhitch * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 47 1.34 mhitch * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 48 1.34 mhitch * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 1.34 mhitch * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 1.34 mhitch * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 1.34 mhitch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 52 1.34 mhitch * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 1.1 chopps */ 54 1.24 lukem 55 1.24 lukem #include "opt_kgdb.h" 56 1.26 aymeric 57 1.26 aymeric #include <sys/cdefs.h> 58 1.62 rillig __KERNEL_RCSID(0, "$NetBSD: mfc.c,v 1.62 2024/09/08 09:36:48 rillig Exp $"); 59 1.1 chopps 60 1.1 chopps #include <sys/param.h> 61 1.1 chopps #include <sys/systm.h> 62 1.1 chopps #include <sys/kernel.h> 63 1.1 chopps #include <sys/device.h> 64 1.1 chopps #include <sys/tty.h> 65 1.1 chopps #include <sys/proc.h> 66 1.1 chopps #include <sys/file.h> 67 1.1 chopps #include <sys/uio.h> 68 1.1 chopps #include <sys/syslog.h> 69 1.1 chopps #include <sys/queue.h> 70 1.29 gehenna #include <sys/conf.h> 71 1.40 elad #include <sys/kauth.h> 72 1.1 chopps #include <machine/cpu.h> 73 1.1 chopps #include <amiga/amiga/device.h> 74 1.2 chopps #include <amiga/amiga/isr.h> 75 1.1 chopps #include <amiga/amiga/custom.h> 76 1.1 chopps #include <amiga/amiga/cia.h> 77 1.1 chopps #include <amiga/amiga/cc.h> 78 1.2 chopps #include <amiga/dev/zbusvar.h> 79 1.1 chopps 80 1.1 chopps #include <dev/cons.h> 81 1.1 chopps 82 1.1 chopps #include "mfcs.h" 83 1.1 chopps 84 1.7 chopps #ifndef SEROBUF_SIZE 85 1.1 chopps #define SEROBUF_SIZE 128 86 1.7 chopps #endif 87 1.7 chopps #ifndef SERIBUF_SIZE 88 1.1 chopps #define SERIBUF_SIZE 1024 89 1.7 chopps #endif 90 1.1 chopps 91 1.2 chopps #define splser() spl6() 92 1.2 chopps 93 1.2 chopps /* 94 1.2 chopps * 68581 DUART registers 95 1.2 chopps */ 96 1.1 chopps struct mfc_regs { 97 1.1 chopps volatile u_char du_mr1a; 98 1.1 chopps #define du_mr2a du_mr1a 99 1.1 chopps u_char pad0; 100 1.1 chopps volatile u_char du_csra; 101 1.1 chopps #define du_sra du_csra 102 1.1 chopps u_char pad2; 103 1.1 chopps volatile u_char du_cra; 104 1.1 chopps u_char pad4; 105 1.1 chopps volatile u_char du_tba; 106 1.1 chopps #define du_rba du_tba 107 1.1 chopps u_char pad6; 108 1.1 chopps volatile u_char du_acr; 109 1.1 chopps #define du_ipcr du_acr 110 1.1 chopps u_char pad8; 111 1.1 chopps volatile u_char du_imr; 112 1.1 chopps #define du_isr du_imr 113 1.1 chopps u_char pad10; 114 1.1 chopps volatile u_char du_ctur; 115 1.1 chopps #define du_cmsb du_ctur 116 1.1 chopps u_char pad12; 117 1.1 chopps volatile u_char du_ctlr; 118 1.1 chopps #define du_clsb du_ctlr 119 1.1 chopps u_char pad14; 120 1.1 chopps volatile u_char du_mr1b; 121 1.1 chopps #define du_mr2b du_mr1b 122 1.1 chopps u_char pad16; 123 1.1 chopps volatile u_char du_csrb; 124 1.1 chopps #define du_srb du_csrb 125 1.1 chopps u_char pad18; 126 1.1 chopps volatile u_char du_crb; 127 1.1 chopps u_char pad20; 128 1.1 chopps volatile u_char du_tbb; 129 1.1 chopps #define du_rbb du_tbb 130 1.1 chopps u_char pad22; 131 1.1 chopps volatile u_char du_ivr; 132 1.1 chopps u_char pad24; 133 1.1 chopps volatile u_char du_opcr; 134 1.1 chopps #define du_ip du_opcr 135 1.1 chopps u_char pad26; 136 1.1 chopps volatile u_char du_btst; 137 1.1 chopps #define du_strc du_btst 138 1.1 chopps u_char pad28; 139 1.1 chopps volatile u_char du_btrst; 140 1.1 chopps #define du_stpc du_btrst 141 1.1 chopps u_char pad30; 142 1.1 chopps }; 143 1.1 chopps 144 1.2 chopps /* 145 1.2 chopps * 68681 DUART serial port registers 146 1.2 chopps */ 147 1.1 chopps struct duart_regs { 148 1.1 chopps volatile u_char ch_mr1; 149 1.1 chopps #define ch_mr2 ch_mr1 150 1.1 chopps u_char pad0; 151 1.1 chopps volatile u_char ch_csr; 152 1.1 chopps #define ch_sr ch_csr 153 1.1 chopps u_char pad1; 154 1.1 chopps volatile u_char ch_cr; 155 1.1 chopps u_char pad2; 156 1.1 chopps volatile u_char ch_tb; 157 1.1 chopps #define ch_rb ch_tb 158 1.1 chopps u_char pad3; 159 1.1 chopps }; 160 1.1 chopps 161 1.1 chopps struct mfc_softc { 162 1.55 chs device_t sc_dev; 163 1.2 chopps struct isr sc_isr; 164 1.1 chopps struct mfc_regs *sc_regs; 165 1.1 chopps u_long clk_frq; 166 1.1 chopps u_short ct_val; 167 1.1 chopps u_char ct_usecnt; 168 1.1 chopps u_char imask; 169 1.1 chopps u_char mfc_iii; 170 1.1 chopps u_char last_ip; 171 1.1 chopps }; 172 1.1 chopps 173 1.2 chopps #if NMFCS > 0 174 1.1 chopps struct mfcs_softc { 175 1.55 chs device_t sc_dev; 176 1.6 chopps struct tty *sc_tty; 177 1.1 chopps struct duart_regs *sc_duart; 178 1.1 chopps struct mfc_regs *sc_regs; 179 1.1 chopps struct mfc_softc *sc_mfc; 180 1.9 jtc int swflags; 181 1.1 chopps long flags; /* XXX */ 182 1.1 chopps #define CT_USED 1 /* CT in use */ 183 1.1 chopps u_short *rptr, *wptr, incnt, ovfl; 184 1.1 chopps u_short inbuf[SERIBUF_SIZE]; 185 1.1 chopps char *ptr, *end; 186 1.1 chopps char outbuf[SEROBUF_SIZE]; 187 1.52 phx struct vbl_node vbl_node; 188 1.52 phx void *mfcs_si; 189 1.1 chopps }; 190 1.2 chopps #endif 191 1.2 chopps 192 1.2 chopps #if NMFCP > 0 193 1.2 chopps struct mfcp_softc { 194 1.2 chopps }; 195 1.2 chopps #endif 196 1.1 chopps 197 1.1 chopps struct mfc_args { 198 1.1 chopps struct zbus_args zargs; 199 1.36 jmc const char *subdev; 200 1.1 chopps char unit; 201 1.1 chopps }; 202 1.1 chopps 203 1.55 chs int mfcprint(void *, const char *); 204 1.55 chs void mfcattach(device_t, device_t, void *); 205 1.55 chs int mfcmatch(device_t, cfdata_t, void *); 206 1.12 veego 207 1.2 chopps #if NMFCS > 0 208 1.55 chs int mfcsmatch(device_t, cfdata_t, void *); 209 1.55 chs void mfcsattach(device_t, device_t, void *); 210 1.25 aymeric int mfcsparam( struct tty *, struct termios *); 211 1.25 aymeric int mfcshwiflow(struct tty *, int); 212 1.25 aymeric void mfcsstart(struct tty *); 213 1.25 aymeric int mfcsmctl(dev_t, int, int); 214 1.25 aymeric void mfcsxintr(int); 215 1.25 aymeric void mfcseint(int, int); 216 1.25 aymeric void mfcsmint(register int); 217 1.52 phx void mfcs_intr_soft(void *); 218 1.2 chopps #endif 219 1.12 veego 220 1.2 chopps #if NMFCP > 0 221 1.55 chs void mfcpattach(device_t, device_t, void *); 222 1.55 chs int mfcpmatch(device_t, cfdata_t, void *); 223 1.2 chopps #endif 224 1.25 aymeric int mfcintr(void *); 225 1.1 chopps 226 1.55 chs CFATTACH_DECL_NEW(mfc, sizeof(struct mfc_softc), 227 1.31 thorpej mfcmatch, mfcattach, NULL, NULL); 228 1.10 thorpej 229 1.2 chopps #if NMFCS > 0 230 1.55 chs CFATTACH_DECL_NEW(mfcs, sizeof(struct mfcs_softc), 231 1.31 thorpej mfcsmatch, mfcsattach, NULL, NULL); 232 1.10 thorpej 233 1.19 thorpej extern struct cfdriver mfcs_cd; 234 1.2 chopps #endif 235 1.2 chopps 236 1.2 chopps #if NMFCP > 0 237 1.55 chs CFATTACH_DECL_NEW(mfcp, sizeof(struct mfcp_softc), 238 1.31 thorpej mfcpmatch, mfcpattach, NULL, NULL); 239 1.2 chopps #endif 240 1.1 chopps 241 1.29 gehenna dev_type_open(mfcsopen); 242 1.29 gehenna dev_type_close(mfcsclose); 243 1.29 gehenna dev_type_read(mfcsread); 244 1.29 gehenna dev_type_write(mfcswrite); 245 1.29 gehenna dev_type_ioctl(mfcsioctl); 246 1.29 gehenna dev_type_stop(mfcsstop); 247 1.29 gehenna dev_type_tty(mfcstty); 248 1.29 gehenna dev_type_poll(mfcspoll); 249 1.29 gehenna 250 1.29 gehenna const struct cdevsw mfcs_cdevsw = { 251 1.56 dholland .d_open = mfcsopen, 252 1.56 dholland .d_close = mfcsclose, 253 1.56 dholland .d_read = mfcsread, 254 1.56 dholland .d_write = mfcswrite, 255 1.56 dholland .d_ioctl = mfcsioctl, 256 1.56 dholland .d_stop = mfcsstop, 257 1.56 dholland .d_tty = mfcstty, 258 1.56 dholland .d_poll = mfcspoll, 259 1.56 dholland .d_mmap = nommap, 260 1.56 dholland .d_kqfilter = ttykqfilter, 261 1.57 dholland .d_discard = nodiscard, 262 1.56 dholland .d_flag = D_TTY 263 1.29 gehenna }; 264 1.12 veego 265 1.1 chopps int mfcs_active; 266 1.1 chopps int mfcsdefaultrate = 38400 /*TTYDEF_SPEED*/; 267 1.9 jtc #define SWFLAGS(dev) (sc->swflags | (((dev) & 0x80) == 0 ? TIOCFLAG_SOFTCAR : 0)) 268 1.1 chopps 269 1.4 chopps #ifdef notyet 270 1.4 chopps /* 271 1.4 chopps * MultiFaceCard III, II+ (not supported yet), and 272 1.4 chopps * SerialMaster 500+ (not supported yet) 273 1.4 chopps * baud rate tables for BRG set 1 [not used yet] 274 1.4 chopps */ 275 1.4 chopps 276 1.35 matt const struct speedtab mfcs3speedtab1[] = { 277 1.12 veego { 0, 0 }, 278 1.12 veego { 100, 0x00 }, 279 1.12 veego { 220, 0x11 }, 280 1.12 veego { 600, 0x44 }, 281 1.12 veego { 1200, 0x55 }, 282 1.12 veego { 2400, 0x66 }, 283 1.12 veego { 4800, 0x88 }, 284 1.12 veego { 9600, 0x99 }, 285 1.12 veego { 19200, 0xbb }, 286 1.12 veego { 115200, 0xcc }, 287 1.12 veego { -1, -1 } 288 1.4 chopps }; 289 1.4 chopps 290 1.4 chopps /* 291 1.4 chopps * MultiFaceCard II, I, and SerialMaster 500 292 1.4 chopps * baud rate tables for BRG set 1 [not used yet] 293 1.4 chopps */ 294 1.4 chopps 295 1.35 matt const struct speedtab mfcs2speedtab1[] = { 296 1.12 veego { 0, 0 }, 297 1.12 veego { 50, 0x00 }, 298 1.12 veego { 110, 0x11 }, 299 1.12 veego { 300, 0x44 }, 300 1.12 veego { 600, 0x55 }, 301 1.12 veego { 1200, 0x66 }, 302 1.12 veego { 2400, 0x88 }, 303 1.12 veego { 4800, 0x99 }, 304 1.12 veego { 9600, 0xbb }, 305 1.12 veego { 38400, 0xcc }, 306 1.12 veego { -1, -1 } 307 1.4 chopps }; 308 1.4 chopps #endif 309 1.4 chopps 310 1.4 chopps /* 311 1.4 chopps * MultiFaceCard III, II+ (not supported yet), and 312 1.4 chopps * SerialMaster 500+ (not supported yet) 313 1.4 chopps * baud rate tables for BRG set 2 314 1.4 chopps */ 315 1.4 chopps 316 1.35 matt const struct speedtab mfcs3speedtab2[] = { 317 1.12 veego { 0, 0 }, 318 1.12 veego { 150, 0x00 }, 319 1.12 veego { 200, 0x11 }, 320 1.12 veego { 300, 0x33 }, 321 1.12 veego { 600, 0x44 }, 322 1.12 veego { 1200, 0x55 }, 323 1.12 veego { 2400, 0x66 }, 324 1.12 veego { 4800, 0x88 }, 325 1.12 veego { 9600, 0x99 }, 326 1.12 veego { 19200, 0xbb }, 327 1.12 veego { 38400, 0xcc }, 328 1.12 veego { -1, -1 } 329 1.1 chopps }; 330 1.1 chopps 331 1.4 chopps /* 332 1.4 chopps * MultiFaceCard II, I, and SerialMaster 500 333 1.4 chopps * baud rate tables for BRG set 2 334 1.4 chopps */ 335 1.4 chopps 336 1.35 matt const struct speedtab mfcs2speedtab2[] = { 337 1.12 veego { 0, 0 }, 338 1.12 veego { 75, 0x00 }, 339 1.12 veego { 100, 0x11 }, 340 1.12 veego { 150, 0x33 }, 341 1.12 veego { 300, 0x44 }, 342 1.12 veego { 600, 0x55 }, 343 1.12 veego { 1200, 0x66 }, 344 1.12 veego { 2400, 0x88 }, 345 1.12 veego { 4800, 0x99 }, 346 1.12 veego { 9600, 0xbb }, 347 1.12 veego { 19200, 0xcc }, 348 1.12 veego { -1, -1 } 349 1.1 chopps }; 350 1.1 chopps 351 1.1 chopps /* 352 1.62 rillig * if we are a bsc/Alf Data MultFaceCard (I, II, and III) 353 1.1 chopps */ 354 1.1 chopps int 355 1.55 chs mfcmatch(device_t parent, cfdata_t cf, void *aux) 356 1.1 chopps { 357 1.1 chopps struct zbus_args *zap; 358 1.1 chopps 359 1.55 chs zap = aux; 360 1.1 chopps if (zap->manid == 2092 && 361 1.1 chopps (zap->prodid == 16 || zap->prodid == 17 || zap->prodid == 18)) 362 1.2 chopps 363 1.1 chopps return(1); 364 1.1 chopps return(0); 365 1.1 chopps } 366 1.1 chopps 367 1.1 chopps void 368 1.55 chs mfcattach(device_t parent, device_t self, void *aux) 369 1.1 chopps { 370 1.1 chopps struct mfc_softc *scc; 371 1.1 chopps struct zbus_args *zap; 372 1.1 chopps struct mfc_args ma; 373 1.1 chopps int unit; 374 1.1 chopps struct mfc_regs *rp; 375 1.1 chopps 376 1.55 chs zap = aux; 377 1.2 chopps 378 1.17 christos printf ("\n"); 379 1.1 chopps 380 1.55 chs scc = device_private(self); 381 1.55 chs scc->sc_dev = self; 382 1.55 chs unit = device_unit(self); 383 1.1 chopps scc->sc_regs = rp = zap->va; 384 1.1 chopps if (zap->prodid == 18) 385 1.1 chopps scc->mfc_iii = 3; 386 1.1 chopps scc->clk_frq = scc->mfc_iii ? 230400 : 115200; 387 1.1 chopps 388 1.1 chopps rp->du_opcr = 0x00; /* configure output port? */ 389 1.1 chopps rp->du_btrst = 0x0f; /* clear modem lines */ 390 1.1 chopps rp->du_ivr = 0; /* IVR */ 391 1.1 chopps rp->du_imr = 0; /* IMR */ 392 1.1 chopps rp->du_acr = 0xe0; /* baud rate generate set 2 */ 393 1.1 chopps rp->du_ctur = 0; 394 1.1 chopps rp->du_ctlr = 4; 395 1.1 chopps rp->du_csra = 0xcc; /* clock select = 38400 */ 396 1.1 chopps rp->du_cra = 0x10; /* reset mode register ptr */ 397 1.1 chopps rp->du_cra = 0x20; 398 1.1 chopps rp->du_cra = 0x30; 399 1.1 chopps rp->du_cra = 0x40; 400 1.1 chopps rp->du_mr1a = 0x93; /* MRA1 */ 401 1.1 chopps rp->du_mr2a = 0x17; /* MRA2 */ 402 1.1 chopps rp->du_csrb = 0xcc; /* clock select = 38400 */ 403 1.1 chopps rp->du_crb = 0x10; /* reset mode register ptr */ 404 1.1 chopps rp->du_crb = 0x20; 405 1.1 chopps rp->du_crb = 0x30; 406 1.1 chopps rp->du_crb = 0x40; 407 1.1 chopps rp->du_mr1b = 0x93; /* MRB1 */ 408 1.1 chopps rp->du_mr2b = 0x17; /* MRB2 */ 409 1.1 chopps rp->du_cra = 0x05; /* enable A Rx & Tx */ 410 1.1 chopps rp->du_crb = 0x05; /* enable B Rx & Tx */ 411 1.1 chopps 412 1.2 chopps scc->sc_isr.isr_intr = mfcintr; 413 1.2 chopps scc->sc_isr.isr_arg = scc; 414 1.2 chopps scc->sc_isr.isr_ipl = 6; 415 1.2 chopps add_isr(&scc->sc_isr); 416 1.1 chopps 417 1.1 chopps /* configure ports */ 418 1.53 cegger memcpy(&ma.zargs, zap, sizeof(struct zbus_args)); 419 1.58 thorpej 420 1.1 chopps ma.subdev = "mfcs"; 421 1.1 chopps ma.unit = unit * 2; 422 1.59 thorpej config_found(self, &ma, mfcprint, CFARGS_NONE); 423 1.58 thorpej 424 1.1 chopps ma.unit = unit * 2 + 1; 425 1.59 thorpej config_found(self, &ma, mfcprint, CFARGS_NONE); 426 1.58 thorpej 427 1.1 chopps ma.subdev = "mfcp"; 428 1.1 chopps ma.unit = unit; 429 1.59 thorpej config_found(self, &ma, mfcprint, CFARGS_NONE); 430 1.1 chopps } 431 1.1 chopps 432 1.1 chopps /* 433 1.2 chopps * 434 1.1 chopps */ 435 1.1 chopps int 436 1.55 chs mfcsmatch(device_t parent, cfdata_t cf, void *aux) 437 1.1 chopps { 438 1.1 chopps struct mfc_args *ma; 439 1.1 chopps 440 1.55 chs ma = aux; 441 1.1 chopps if (strcmp(ma->subdev, "mfcs") == 0) 442 1.1 chopps return (1); 443 1.1 chopps return (0); 444 1.1 chopps } 445 1.1 chopps 446 1.1 chopps void 447 1.55 chs mfcsattach(device_t parent, device_t self, void *aux) 448 1.1 chopps { 449 1.1 chopps int unit; 450 1.1 chopps struct mfcs_softc *sc; 451 1.1 chopps struct mfc_softc *scc; 452 1.1 chopps struct mfc_args *ma; 453 1.1 chopps struct mfc_regs *rp; 454 1.1 chopps 455 1.55 chs sc = device_private(self); 456 1.55 chs sc->sc_dev = self; 457 1.55 chs scc = device_private(parent); 458 1.55 chs ma = aux; 459 1.1 chopps 460 1.52 phx printf (": input fifo %d output fifo %d\n", SERIBUF_SIZE, 461 1.52 phx SEROBUF_SIZE); 462 1.1 chopps 463 1.1 chopps unit = ma->unit; 464 1.1 chopps mfcs_active |= 1 << unit; 465 1.1 chopps sc->rptr = sc->wptr = sc->inbuf; 466 1.1 chopps sc->sc_mfc = scc; 467 1.1 chopps sc->sc_regs = rp = scc->sc_regs; 468 1.36 jmc sc->sc_duart = (struct duart_regs *) ((unit & 1) ? 469 1.36 jmc __UNVOLATILE(&rp->du_mr1b) : __UNVOLATILE(&rp->du_mr1a)); 470 1.52 phx sc->mfcs_si = softint_establish(SOFTINT_SERIAL, mfcs_intr_soft, sc); 471 1.1 chopps /* 472 1.1 chopps * should have only one vbl routine to handle all ports? 473 1.1 chopps */ 474 1.9 jtc sc->vbl_node.function = (void (*) (void *)) mfcsmint; 475 1.9 jtc sc->vbl_node.data = (void *) unit; 476 1.9 jtc add_vbl_function(&sc->vbl_node, 1, (void *) unit); 477 1.1 chopps } 478 1.1 chopps 479 1.1 chopps /* 480 1.1 chopps * print diag if pnp is NULL else just extra 481 1.1 chopps */ 482 1.1 chopps int 483 1.55 chs mfcprint(void *aux, const char *pnp) 484 1.1 chopps { 485 1.1 chopps if (pnp == NULL) 486 1.1 chopps return(UNCONF); 487 1.1 chopps return(QUIET); 488 1.1 chopps } 489 1.1 chopps 490 1.1 chopps int 491 1.38 christos mfcsopen(dev_t dev, int flag, int mode, struct lwp *l) 492 1.1 chopps { 493 1.1 chopps struct tty *tp; 494 1.6 chopps struct mfcs_softc *sc; 495 1.47 ad int unit, error; 496 1.1 chopps 497 1.1 chopps error = 0; 498 1.1 chopps unit = dev & 0x1f; 499 1.1 chopps 500 1.50 tsutsui sc = device_lookup_private(&mfcs_cd, unit); 501 1.50 tsutsui if (sc == NULL || (mfcs_active & (1 << unit)) == 0) 502 1.1 chopps return (ENXIO); 503 1.1 chopps 504 1.6 chopps if (sc->sc_tty) 505 1.6 chopps tp = sc->sc_tty; 506 1.13 mhitch else { 507 1.54 rmind tp = sc->sc_tty = tty_alloc(); 508 1.13 mhitch tty_attach(tp); 509 1.13 mhitch } 510 1.1 chopps 511 1.1 chopps tp->t_oproc = (void (*) (struct tty *)) mfcsstart; 512 1.1 chopps tp->t_param = mfcsparam; 513 1.1 chopps tp->t_dev = dev; 514 1.1 chopps tp->t_hwiflow = mfcshwiflow; 515 1.1 chopps 516 1.47 ad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 517 1.42 elad return (EBUSY); 518 1.42 elad 519 1.61 riastrad ttylock(tp); 520 1.20 mhitch if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { 521 1.1 chopps ttychars(tp); 522 1.1 chopps if (tp->t_ispeed == 0) { 523 1.1 chopps /* 524 1.1 chopps * only when cleared do we reset to defaults. 525 1.1 chopps */ 526 1.1 chopps tp->t_iflag = TTYDEF_IFLAG; 527 1.1 chopps tp->t_oflag = TTYDEF_OFLAG; 528 1.1 chopps tp->t_cflag = TTYDEF_CFLAG; 529 1.1 chopps tp->t_lflag = TTYDEF_LFLAG; 530 1.1 chopps tp->t_ispeed = tp->t_ospeed = mfcsdefaultrate; 531 1.1 chopps } 532 1.1 chopps /* 533 1.1 chopps * do these all the time 534 1.1 chopps */ 535 1.9 jtc if (sc->swflags & TIOCFLAG_CLOCAL) 536 1.1 chopps tp->t_cflag |= CLOCAL; 537 1.9 jtc if (sc->swflags & TIOCFLAG_CRTSCTS) 538 1.1 chopps tp->t_cflag |= CRTSCTS; 539 1.9 jtc if (sc->swflags & TIOCFLAG_MDMBUF) 540 1.1 chopps tp->t_cflag |= MDMBUF; 541 1.1 chopps mfcsparam(tp, &tp->t_termios); 542 1.1 chopps ttsetwater(tp); 543 1.2 chopps 544 1.1 chopps (void)mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET); 545 1.2 chopps if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) || 546 1.1 chopps (mfcsmctl(dev, 0, DMGET) & TIOCM_CD)) 547 1.1 chopps tp->t_state |= TS_CARR_ON; 548 1.1 chopps else 549 1.1 chopps tp->t_state &= ~TS_CARR_ON; 550 1.1 chopps } 551 1.1 chopps 552 1.1 chopps /* 553 1.1 chopps * if NONBLOCK requested, ignore carrier 554 1.1 chopps */ 555 1.1 chopps if (flag & O_NONBLOCK) 556 1.1 chopps goto done; 557 1.1 chopps 558 1.1 chopps /* 559 1.1 chopps * block waiting for carrier 560 1.1 chopps */ 561 1.1 chopps while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) { 562 1.20 mhitch tp->t_wopen++; 563 1.49 ad error = ttysleep(tp, &tp->t_rawcv, true, 0); 564 1.20 mhitch tp->t_wopen--; 565 1.1 chopps if (error) { 566 1.61 riastrad ttyunlock(tp); 567 1.1 chopps return(error); 568 1.1 chopps } 569 1.1 chopps } 570 1.1 chopps done: 571 1.1 chopps /* This is a way to handle lost XON characters */ 572 1.1 chopps if ((flag & O_TRUNC) && (tp->t_state & TS_TTSTOP)) { 573 1.1 chopps tp->t_state &= ~TS_TTSTOP; 574 1.1 chopps ttstart (tp); 575 1.1 chopps } 576 1.1 chopps /* 577 1.1 chopps * Reset the tty pointer, as there could have been a dialout 578 1.1 chopps * use of the tty with a dialin open waiting. 579 1.1 chopps */ 580 1.1 chopps tp->t_dev = dev; 581 1.61 riastrad ttyunlock(tp); 582 1.22 aymeric return tp->t_linesw->l_open(dev, tp); 583 1.1 chopps } 584 1.1 chopps 585 1.1 chopps /*ARGSUSED*/ 586 1.1 chopps int 587 1.38 christos mfcsclose(dev_t dev, int flag, int mode, struct lwp *l) 588 1.1 chopps { 589 1.1 chopps struct tty *tp; 590 1.1 chopps int unit; 591 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, dev & 31); 592 1.1 chopps struct mfc_softc *scc= sc->sc_mfc; 593 1.1 chopps 594 1.1 chopps unit = dev & 31; 595 1.1 chopps 596 1.6 chopps tp = sc->sc_tty; 597 1.22 aymeric tp->t_linesw->l_close(tp, flag); 598 1.1 chopps sc->sc_duart->ch_cr = 0x70; /* stop break */ 599 1.1 chopps 600 1.1 chopps scc->imask &= ~(0x7 << ((unit & 1) * 4)); 601 1.1 chopps scc->sc_regs->du_imr = scc->imask; 602 1.1 chopps if (sc->flags & CT_USED) { 603 1.1 chopps --scc->ct_usecnt; 604 1.1 chopps sc->flags &= ~CT_USED; 605 1.1 chopps } 606 1.1 chopps 607 1.1 chopps /* 608 1.1 chopps * If the device is closed, it's close, no matter whether we deal with 609 1.1 chopps * modem control signals nor not. 610 1.1 chopps */ 611 1.1 chopps #if 0 612 1.20 mhitch if (tp->t_cflag & HUPCL || tp->t_wopen != 0 || 613 1.1 chopps (tp->t_state & TS_ISOPEN) == 0) 614 1.1 chopps #endif 615 1.1 chopps (void) mfcsmctl(dev, 0, DMSET); 616 1.1 chopps ttyclose(tp); 617 1.1 chopps #if not_yet 618 1.1 chopps if (tp != &mfcs_cons) { 619 1.9 jtc remove_vbl_function(&sc->vbl_node); 620 1.54 rmind tty_free(tp); 621 1.6 chopps sc->sc_tty = (struct tty *) NULL; 622 1.1 chopps } 623 1.1 chopps #endif 624 1.1 chopps return (0); 625 1.1 chopps } 626 1.1 chopps 627 1.1 chopps int 628 1.25 aymeric mfcsread(dev_t dev, struct uio *uio, int flag) 629 1.1 chopps { 630 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, dev & 31); 631 1.6 chopps struct tty *tp = sc->sc_tty; 632 1.6 chopps if (tp == NULL) 633 1.1 chopps return(ENXIO); 634 1.22 aymeric return tp->t_linesw->l_read(tp, uio, flag); 635 1.1 chopps } 636 1.1 chopps 637 1.1 chopps int 638 1.25 aymeric mfcswrite(dev_t dev, struct uio *uio, int flag) 639 1.1 chopps { 640 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, dev & 31); 641 1.6 chopps struct tty *tp = sc->sc_tty; 642 1.1 chopps 643 1.6 chopps if (tp == NULL) 644 1.1 chopps return(ENXIO); 645 1.22 aymeric return tp->t_linesw->l_write(tp, uio, flag); 646 1.23 scw } 647 1.23 scw 648 1.23 scw int 649 1.38 christos mfcspoll(dev_t dev, int events, struct lwp *l) 650 1.23 scw { 651 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, dev & 31); 652 1.23 scw struct tty *tp = sc->sc_tty; 653 1.23 scw 654 1.23 scw if (tp == NULL) 655 1.23 scw return(ENXIO); 656 1.38 christos return ((*tp->t_linesw->l_poll)(tp, events, l)); 657 1.1 chopps } 658 1.5 chopps 659 1.5 chopps struct tty * 660 1.25 aymeric mfcstty(dev_t dev) 661 1.5 chopps { 662 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, dev & 31); 663 1.6 chopps 664 1.6 chopps return (sc->sc_tty); 665 1.5 chopps } 666 1.5 chopps 667 1.1 chopps int 668 1.46 christos mfcsioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 669 1.1 chopps { 670 1.1 chopps register struct tty *tp; 671 1.1 chopps register int error; 672 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, dev & 31); 673 1.1 chopps 674 1.6 chopps tp = sc->sc_tty; 675 1.1 chopps if (!tp) 676 1.1 chopps return ENXIO; 677 1.1 chopps 678 1.38 christos error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, l); 679 1.28 atatat if (error != EPASSTHROUGH) 680 1.1 chopps return(error); 681 1.1 chopps 682 1.38 christos error = ttioctl(tp, cmd, data, flag, l); 683 1.28 atatat if (error != EPASSTHROUGH) 684 1.1 chopps return(error); 685 1.1 chopps 686 1.1 chopps switch (cmd) { 687 1.1 chopps case TIOCSBRK: 688 1.1 chopps sc->sc_duart->ch_cr = 0x60; /* start break */ 689 1.1 chopps break; 690 1.1 chopps 691 1.1 chopps case TIOCCBRK: 692 1.1 chopps sc->sc_duart->ch_cr = 0x70; /* stop break */ 693 1.1 chopps break; 694 1.1 chopps 695 1.1 chopps case TIOCSDTR: 696 1.1 chopps (void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS); 697 1.1 chopps break; 698 1.1 chopps 699 1.1 chopps case TIOCCDTR: 700 1.1 chopps (void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC); 701 1.1 chopps break; 702 1.1 chopps 703 1.1 chopps case TIOCMSET: 704 1.1 chopps (void) mfcsmctl(dev, *(int *) data, DMSET); 705 1.1 chopps break; 706 1.1 chopps 707 1.1 chopps case TIOCMBIS: 708 1.1 chopps (void) mfcsmctl(dev, *(int *) data, DMBIS); 709 1.1 chopps break; 710 1.1 chopps 711 1.1 chopps case TIOCMBIC: 712 1.1 chopps (void) mfcsmctl(dev, *(int *) data, DMBIC); 713 1.1 chopps break; 714 1.1 chopps 715 1.1 chopps case TIOCMGET: 716 1.1 chopps *(int *)data = mfcsmctl(dev, 0, DMGET); 717 1.1 chopps break; 718 1.1 chopps case TIOCGFLAGS: 719 1.1 chopps *(int *)data = SWFLAGS(dev); 720 1.1 chopps break; 721 1.1 chopps case TIOCSFLAGS: 722 1.44 elad error = kauth_authorize_device_tty(l->l_cred, 723 1.44 elad KAUTH_DEVICE_TTY_PRIVSET, tp); 724 1.1 chopps if (error != 0) 725 1.2 chopps return(EPERM); 726 1.1 chopps 727 1.9 jtc sc->swflags = *(int *)data; 728 1.9 jtc sc->swflags &= /* only allow valid flags */ 729 1.1 chopps (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); 730 1.4 chopps /* XXXX need to change duart parameters? */ 731 1.1 chopps break; 732 1.1 chopps default: 733 1.28 atatat return(EPASSTHROUGH); 734 1.1 chopps } 735 1.1 chopps 736 1.1 chopps return(0); 737 1.1 chopps } 738 1.1 chopps 739 1.1 chopps int 740 1.25 aymeric mfcsparam(struct tty *tp, struct termios *t) 741 1.1 chopps { 742 1.12 veego int cflag, unit, ospeed; 743 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, tp->t_dev & 31); 744 1.1 chopps struct mfc_softc *scc= sc->sc_mfc; 745 1.2 chopps 746 1.1 chopps cflag = t->c_cflag; 747 1.1 chopps unit = tp->t_dev & 31; 748 1.1 chopps if (sc->flags & CT_USED) { 749 1.1 chopps --scc->ct_usecnt; 750 1.1 chopps sc->flags &= ~CT_USED; 751 1.1 chopps } 752 1.4 chopps ospeed = ttspeedtab(t->c_ospeed, scc->mfc_iii ? mfcs3speedtab2 : 753 1.4 chopps mfcs2speedtab2); 754 1.1 chopps 755 1.1 chopps /* 756 1.1 chopps * If Baud Rate Generator can't generate requested speed, 757 1.1 chopps * try to use the counter/timer. 758 1.1 chopps */ 759 1.1 chopps if (ospeed < 0 && (scc->clk_frq % t->c_ospeed) == 0) { 760 1.1 chopps ospeed = scc->clk_frq / t->c_ospeed; /* divisor */ 761 1.1 chopps if (scc->ct_usecnt > 0 && scc->ct_val != ospeed) 762 1.1 chopps ospeed = -1; 763 1.1 chopps else { 764 1.1 chopps scc->sc_regs->du_ctur = ospeed >> 8; 765 1.1 chopps scc->sc_regs->du_ctlr = ospeed; 766 1.1 chopps scc->ct_val = ospeed; 767 1.1 chopps ++scc->ct_usecnt; 768 1.1 chopps sc->flags |= CT_USED; 769 1.1 chopps ospeed = 0xdd; 770 1.1 chopps } 771 1.1 chopps } 772 1.1 chopps /* XXXX 68681 duart could handle split speeds */ 773 1.1 chopps if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 774 1.1 chopps return(EINVAL); 775 1.1 chopps 776 1.4 chopps /* XXXX handle parity, character size, stop bits, flow control */ 777 1.4 chopps 778 1.2 chopps /* 779 1.1 chopps * copy to tty 780 1.1 chopps */ 781 1.1 chopps tp->t_ispeed = t->c_ispeed; 782 1.1 chopps tp->t_ospeed = t->c_ospeed; 783 1.1 chopps tp->t_cflag = cflag; 784 1.1 chopps 785 1.1 chopps /* 786 1.1 chopps * enable interrupts 787 1.1 chopps */ 788 1.1 chopps scc->imask |= (0x2 << ((unit & 1) * 4)) | 0x80; 789 1.1 chopps scc->sc_regs->du_imr = scc->imask; 790 1.1 chopps #if defined(DEBUG) && 0 791 1.17 christos printf("mfcsparam: speed %d => %x ct %d imask %x cflag %x\n", 792 1.1 chopps t->c_ospeed, ospeed, scc->ct_val, scc->imask, cflag); 793 1.1 chopps #endif 794 1.1 chopps if (ospeed == 0) 795 1.1 chopps (void)mfcsmctl(tp->t_dev, 0, DMSET); /* hang up line */ 796 1.1 chopps else { 797 1.2 chopps /* 798 1.1 chopps * (re)enable DTR 799 1.1 chopps * and set baud rate. (8 bit mode) 800 1.1 chopps */ 801 1.1 chopps (void)mfcsmctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET); 802 1.1 chopps sc->sc_duart->ch_csr = ospeed; 803 1.1 chopps } 804 1.1 chopps return(0); 805 1.1 chopps } 806 1.1 chopps 807 1.12 veego int 808 1.25 aymeric mfcshwiflow(struct tty *tp, int flag) 809 1.1 chopps { 810 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, tp->t_dev & 31); 811 1.1 chopps int unit = tp->t_dev & 1; 812 1.1 chopps 813 1.1 chopps if (flag) 814 1.1 chopps sc->sc_regs->du_btrst = 1 << unit; 815 1.1 chopps else 816 1.1 chopps sc->sc_regs->du_btst = 1 << unit; 817 1.1 chopps return 1; 818 1.1 chopps } 819 1.1 chopps 820 1.12 veego void 821 1.25 aymeric mfcsstart(struct tty *tp) 822 1.1 chopps { 823 1.1 chopps int cc, s, unit; 824 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, tp->t_dev & 31); 825 1.1 chopps struct mfc_softc *scc= sc->sc_mfc; 826 1.1 chopps 827 1.1 chopps if ((tp->t_state & TS_ISOPEN) == 0) 828 1.1 chopps return; 829 1.1 chopps 830 1.1 chopps unit = tp->t_dev & 1; 831 1.1 chopps 832 1.2 chopps s = splser(); 833 1.1 chopps if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) 834 1.1 chopps goto out; 835 1.1 chopps 836 1.1 chopps cc = tp->t_outq.c_cc; 837 1.48 ad if (!ttypull(tp) || (tp->t_state & TS_BUSY)) 838 1.1 chopps goto out; 839 1.1 chopps 840 1.1 chopps /* 841 1.1 chopps * We only do bulk transfers if using CTSRTS flow control, not for 842 1.1 chopps * (probably sloooow) ixon/ixoff devices. 843 1.1 chopps */ 844 1.1 chopps if ((tp->t_cflag & CRTSCTS) == 0) 845 1.1 chopps cc = 1; 846 1.1 chopps 847 1.1 chopps /* 848 1.1 chopps * Limit the amount of output we do in one burst 849 1.1 chopps * to prevent hogging the CPU. 850 1.1 chopps */ 851 1.1 chopps if (cc > SEROBUF_SIZE) 852 1.1 chopps cc = SEROBUF_SIZE; 853 1.1 chopps cc = q_to_b(&tp->t_outq, sc->outbuf, cc); 854 1.1 chopps if (cc > 0) { 855 1.1 chopps tp->t_state |= TS_BUSY; 856 1.1 chopps 857 1.1 chopps sc->ptr = sc->outbuf; 858 1.1 chopps sc->end = sc->outbuf + cc; 859 1.1 chopps 860 1.1 chopps /* 861 1.1 chopps * Get first character out, then have TBE-interrupts blow out 862 1.1 chopps * further characters, until buffer is empty, and TS_BUSY gets 863 1.2 chopps * cleared. 864 1.1 chopps */ 865 1.1 chopps sc->sc_duart->ch_tb = *sc->ptr++; 866 1.1 chopps scc->imask |= 1 << (unit * 4); 867 1.1 chopps sc->sc_regs->du_imr = scc->imask; 868 1.1 chopps } 869 1.1 chopps out: 870 1.1 chopps splx(s); 871 1.1 chopps } 872 1.1 chopps 873 1.1 chopps /* 874 1.1 chopps * Stop output on a line. 875 1.1 chopps */ 876 1.1 chopps /*ARGSUSED*/ 877 1.15 mycroft void 878 1.25 aymeric mfcsstop(struct tty *tp, int flag) 879 1.1 chopps { 880 1.1 chopps int s; 881 1.1 chopps 882 1.2 chopps s = splser(); 883 1.1 chopps if (tp->t_state & TS_BUSY) { 884 1.1 chopps if ((tp->t_state & TS_TTSTOP) == 0) 885 1.1 chopps tp->t_state |= TS_FLUSH; 886 1.1 chopps } 887 1.1 chopps splx(s); 888 1.1 chopps } 889 1.1 chopps 890 1.1 chopps int 891 1.25 aymeric mfcsmctl(dev_t dev, int bits, int how) 892 1.1 chopps { 893 1.1 chopps int unit, s; 894 1.12 veego u_char ub = 0; 895 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, dev & 31); 896 1.1 chopps 897 1.1 chopps unit = dev & 1; 898 1.1 chopps 899 1.1 chopps /* 900 1.1 chopps * convert TIOCM* mask into CIA mask 901 1.1 chopps * which is active low 902 1.1 chopps */ 903 1.1 chopps if (how != DMGET) { 904 1.1 chopps /* 905 1.1 chopps * need to save current state of DTR & RTS ? 906 1.1 chopps */ 907 1.1 chopps if (bits & TIOCM_DTR) 908 1.1 chopps ub |= 0x04 << unit; 909 1.1 chopps if (bits & TIOCM_RTS) 910 1.1 chopps ub |= 0x01 << unit; 911 1.1 chopps } 912 1.2 chopps s = splser(); 913 1.1 chopps switch (how) { 914 1.1 chopps case DMSET: 915 1.1 chopps sc->sc_regs->du_btst = ub; 916 1.4 chopps sc->sc_regs->du_btrst = ub ^ (0x05 << unit); 917 1.1 chopps break; 918 1.1 chopps 919 1.1 chopps case DMBIC: 920 1.1 chopps sc->sc_regs->du_btrst = ub; 921 1.1 chopps ub = ~sc->sc_regs->du_ip; 922 1.1 chopps break; 923 1.1 chopps 924 1.1 chopps case DMBIS: 925 1.1 chopps sc->sc_regs->du_btst = ub; 926 1.1 chopps ub = ~sc->sc_regs->du_ip; 927 1.1 chopps break; 928 1.1 chopps 929 1.1 chopps case DMGET: 930 1.1 chopps ub = ~sc->sc_regs->du_ip; 931 1.1 chopps break; 932 1.1 chopps } 933 1.1 chopps (void)splx(s); 934 1.1 chopps 935 1.4 chopps /* XXXX should keep DTR & RTS states in softc? */ 936 1.1 chopps bits = TIOCM_DTR | TIOCM_RTS; 937 1.1 chopps if (ub & (1 << unit)) 938 1.1 chopps bits |= TIOCM_CTS; 939 1.1 chopps if (ub & (4 << unit)) 940 1.1 chopps bits |= TIOCM_DSR; 941 1.1 chopps if (ub & (0x10 << unit)) 942 1.1 chopps bits |= TIOCM_CD; 943 1.4 chopps /* XXXX RI is not supported on all boards */ 944 1.1 chopps if (sc->sc_regs->pad26 & (1 << unit)) 945 1.1 chopps bits |= TIOCM_RI; 946 1.1 chopps 947 1.1 chopps return(bits); 948 1.1 chopps } 949 1.1 chopps 950 1.1 chopps /* 951 1.2 chopps * Level 6 interrupt processing for the MultiFaceCard 68681 DUART 952 1.1 chopps */ 953 1.1 chopps 954 1.1 chopps int 955 1.25 aymeric mfcintr(void *arg) 956 1.1 chopps { 957 1.12 veego struct mfc_softc *scc = arg; 958 1.1 chopps struct mfcs_softc *sc; 959 1.1 chopps struct mfc_regs *regs; 960 1.2 chopps struct tty *tp; 961 1.2 chopps int istat, unit; 962 1.2 chopps u_short c; 963 1.1 chopps 964 1.2 chopps regs = scc->sc_regs; 965 1.2 chopps istat = regs->du_isr & scc->imask; 966 1.2 chopps if (istat == 0) 967 1.2 chopps return (0); 968 1.55 chs unit = device_unit(scc->sc_dev) * 2; 969 1.2 chopps if (istat & 0x02) { /* channel A receive interrupt */ 970 1.50 tsutsui sc = device_lookup_private(&mfcs_cd, unit); 971 1.2 chopps while (1) { 972 1.2 chopps c = regs->du_sra << 8; 973 1.2 chopps if ((c & 0x0100) == 0) 974 1.2 chopps break; 975 1.2 chopps c |= regs->du_rba; 976 1.2 chopps if (sc->incnt == SERIBUF_SIZE) 977 1.2 chopps ++sc->ovfl; 978 1.2 chopps else { 979 1.2 chopps *sc->wptr++ = c; 980 1.2 chopps if (sc->wptr == sc->inbuf + SERIBUF_SIZE) 981 1.2 chopps sc->wptr = sc->inbuf; 982 1.2 chopps ++sc->incnt; 983 1.2 chopps if (sc->incnt > SERIBUF_SIZE - 16) 984 1.2 chopps regs->du_btrst = 1; 985 1.1 chopps } 986 1.2 chopps if (c & 0x1000) 987 1.2 chopps regs->du_cra = 0x40; 988 1.1 chopps } 989 1.2 chopps } 990 1.2 chopps if (istat & 0x20) { /* channel B receive interrupt */ 991 1.50 tsutsui sc = device_lookup_private(&mfcs_cd, unit + 1); 992 1.2 chopps while (1) { 993 1.2 chopps c = regs->du_srb << 8; 994 1.2 chopps if ((c & 0x0100) == 0) 995 1.2 chopps break; 996 1.2 chopps c |= regs->du_rbb; 997 1.2 chopps if (sc->incnt == SERIBUF_SIZE) 998 1.2 chopps ++sc->ovfl; 999 1.2 chopps else { 1000 1.2 chopps *sc->wptr++ = c; 1001 1.2 chopps if (sc->wptr == sc->inbuf + SERIBUF_SIZE) 1002 1.2 chopps sc->wptr = sc->inbuf; 1003 1.2 chopps ++sc->incnt; 1004 1.2 chopps if (sc->incnt > SERIBUF_SIZE - 16) 1005 1.2 chopps regs->du_btrst = 2; 1006 1.1 chopps } 1007 1.2 chopps if (c & 0x1000) 1008 1.2 chopps regs->du_crb = 0x40; 1009 1.1 chopps } 1010 1.2 chopps } 1011 1.2 chopps if (istat & 0x01) { /* channel A transmit interrupt */ 1012 1.50 tsutsui sc = device_lookup_private(&mfcs_cd, unit); 1013 1.6 chopps tp = sc->sc_tty; 1014 1.2 chopps if (sc->ptr == sc->end) { 1015 1.2 chopps tp->t_state &= ~(TS_BUSY | TS_FLUSH); 1016 1.2 chopps scc->imask &= ~0x01; 1017 1.2 chopps regs->du_imr = scc->imask; 1018 1.52 phx softint_schedule(sc->mfcs_si); 1019 1.1 chopps } 1020 1.2 chopps else 1021 1.2 chopps regs->du_tba = *sc->ptr++; 1022 1.2 chopps } 1023 1.2 chopps if (istat & 0x10) { /* channel B transmit interrupt */ 1024 1.50 tsutsui sc = device_lookup_private(&mfcs_cd, unit + 1); 1025 1.6 chopps tp = sc->sc_tty; 1026 1.2 chopps if (sc->ptr == sc->end) { 1027 1.2 chopps tp->t_state &= ~(TS_BUSY | TS_FLUSH); 1028 1.2 chopps scc->imask &= ~0x10; 1029 1.2 chopps regs->du_imr = scc->imask; 1030 1.52 phx softint_schedule(sc->mfcs_si); 1031 1.1 chopps } 1032 1.2 chopps else 1033 1.2 chopps regs->du_tbb = *sc->ptr++; 1034 1.2 chopps } 1035 1.2 chopps if (istat & 0x80) { /* input port change interrupt */ 1036 1.2 chopps c = regs->du_ipcr; 1037 1.55 chs printf ("%s: ipcr %02x", device_xname(scc->sc_dev), c); 1038 1.1 chopps } 1039 1.2 chopps return(1); 1040 1.1 chopps } 1041 1.1 chopps 1042 1.12 veego void 1043 1.25 aymeric mfcsxintr(int unit) 1044 1.1 chopps { 1045 1.1 chopps int s1, s2, ovfl; 1046 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, unit); 1047 1.6 chopps struct tty *tp = sc->sc_tty; 1048 1.1 chopps 1049 1.1 chopps /* 1050 1.1 chopps * Make sure we're not interrupted by another 1051 1.1 chopps * vbl, but allow level6 ints 1052 1.1 chopps */ 1053 1.1 chopps s1 = spltty(); 1054 1.1 chopps 1055 1.1 chopps /* 1056 1.60 andvar * pass along any accumulated information 1057 1.1 chopps * while input is not blocked 1058 1.1 chopps */ 1059 1.1 chopps while (sc->incnt && (tp->t_state & TS_TBLOCK) == 0) { 1060 1.2 chopps /* 1061 1.1 chopps * no collision with ser_fastint() 1062 1.1 chopps */ 1063 1.1 chopps mfcseint(unit, *sc->rptr++); 1064 1.1 chopps 1065 1.1 chopps ovfl = 0; 1066 1.1 chopps /* lock against mfcs_fastint() */ 1067 1.2 chopps s2 = splser(); 1068 1.1 chopps --sc->incnt; 1069 1.1 chopps if (sc->rptr == sc->inbuf + SERIBUF_SIZE) 1070 1.1 chopps sc->rptr = sc->inbuf; 1071 1.1 chopps if (sc->ovfl != 0) { 1072 1.1 chopps ovfl = sc->ovfl; 1073 1.1 chopps sc->ovfl = 0; 1074 1.1 chopps } 1075 1.1 chopps splx(s2); 1076 1.1 chopps if (ovfl != 0) 1077 1.1 chopps log(LOG_WARNING, "%s: %d buffer overflow!\n", 1078 1.55 chs device_xname(sc->sc_dev), ovfl); 1079 1.1 chopps } 1080 1.1 chopps if (sc->incnt == 0 && (tp->t_state & TS_TBLOCK) == 0) { 1081 1.4 chopps sc->sc_regs->du_btst = 1 << unit; /* XXXX */ 1082 1.1 chopps } 1083 1.1 chopps splx(s1); 1084 1.1 chopps } 1085 1.1 chopps 1086 1.12 veego void 1087 1.25 aymeric mfcseint(int unit, int stat) 1088 1.1 chopps { 1089 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, unit); 1090 1.1 chopps struct tty *tp; 1091 1.1 chopps u_char ch; 1092 1.1 chopps int c; 1093 1.1 chopps 1094 1.6 chopps tp = sc->sc_tty; 1095 1.1 chopps ch = stat & 0xff; 1096 1.1 chopps c = ch; 1097 1.1 chopps 1098 1.1 chopps if ((tp->t_state & TS_ISOPEN) == 0) { 1099 1.1 chopps #ifdef KGDB 1100 1.29 gehenna extern const struct cdevsw ser_cdevsw; 1101 1.29 gehenna int maj; 1102 1.29 gehenna 1103 1.1 chopps /* we don't care about parity errors */ 1104 1.29 gehenna maj = cdevsw_lookup_major(&ser_cdevsw); 1105 1.29 gehenna if (kgdb_dev == makedev(maj, unit) && c == FRAME_END) 1106 1.1 chopps kgdb_connect(0); /* trap into kgdb */ 1107 1.1 chopps #endif 1108 1.1 chopps return; 1109 1.1 chopps } 1110 1.1 chopps 1111 1.1 chopps /* 1112 1.1 chopps * Check for break and (if enabled) parity error. 1113 1.1 chopps */ 1114 1.1 chopps if (stat & 0xc000) 1115 1.1 chopps c |= TTY_FE; 1116 1.1 chopps else if (stat & 0x2000) 1117 1.1 chopps c |= TTY_PE; 1118 1.1 chopps 1119 1.1 chopps if (stat & 0x1000) 1120 1.2 chopps log(LOG_WARNING, "%s: fifo overflow\n", 1121 1.50 tsutsui device_xname(device_lookup_private(&mfcs_cd, unit))); 1122 1.1 chopps 1123 1.22 aymeric tp->t_linesw->l_rint(c, tp); 1124 1.1 chopps } 1125 1.1 chopps 1126 1.1 chopps /* 1127 1.1 chopps * This interrupt is periodically invoked in the vertical blank 1128 1.1 chopps * interrupt. It's used to keep track of the modem control lines 1129 1.1 chopps * and (new with the fast_int code) to move accumulated data 1130 1.1 chopps * up into the tty layer. 1131 1.1 chopps */ 1132 1.1 chopps void 1133 1.25 aymeric mfcsmint(int unit) 1134 1.1 chopps { 1135 1.1 chopps struct tty *tp; 1136 1.50 tsutsui struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, unit); 1137 1.1 chopps u_char stat, last, istat; 1138 1.1 chopps 1139 1.6 chopps tp = sc->sc_tty; 1140 1.1 chopps if (!tp) 1141 1.1 chopps return; 1142 1.1 chopps 1143 1.20 mhitch if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { 1144 1.1 chopps sc->rptr = sc->wptr = sc->inbuf; 1145 1.1 chopps sc->incnt = 0; 1146 1.1 chopps return; 1147 1.1 chopps } 1148 1.1 chopps /* 1149 1.1 chopps * empty buffer 1150 1.1 chopps */ 1151 1.1 chopps mfcsxintr(unit); 1152 1.1 chopps 1153 1.1 chopps stat = ~sc->sc_regs->du_ip; 1154 1.1 chopps last = sc->sc_mfc->last_ip; 1155 1.1 chopps sc->sc_mfc->last_ip = stat; 1156 1.1 chopps 1157 1.1 chopps /* 1158 1.1 chopps * check whether any interesting signal changed state 1159 1.1 chopps */ 1160 1.1 chopps istat = stat ^ last; 1161 1.1 chopps 1162 1.1 chopps if ((istat & (0x10 << (unit & 1))) && /* CD changed */ 1163 1.1 chopps (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) { 1164 1.1 chopps if (stat & (0x10 << (unit & 1))) 1165 1.22 aymeric tp->t_linesw->l_modem(tp, 1); 1166 1.22 aymeric else if (tp->t_linesw->l_modem(tp, 0) == 0) { 1167 1.1 chopps sc->sc_regs->du_btrst = 0x0a << (unit & 1); 1168 1.1 chopps } 1169 1.1 chopps } 1170 1.1 chopps } 1171 1.52 phx 1172 1.52 phx void 1173 1.52 phx mfcs_intr_soft(void *arg) 1174 1.52 phx { 1175 1.52 phx struct mfcs_softc *sc = (struct mfcs_softc *)arg; 1176 1.52 phx struct tty *tp = sc->sc_tty; 1177 1.52 phx 1178 1.52 phx if (tp->t_linesw) 1179 1.52 phx tp->t_linesw->l_start(tp); 1180 1.52 phx else 1181 1.52 phx mfcsstart(tp); 1182 1.52 phx } 1183