1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 23 /* All Rights Reserved */ 24 25 /* 26 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 33 * Serial I/O driver for 82510/8250/16450/16550AF/16C554D chips. 34 * Modified as sparc keyboard/mouse driver. 35 */ 36 #define SU_REGISTER_FILE_NO 0 37 #define SU_REGOFFSET 0 38 #define SU_REGISTER_LEN 8 39 40 #include <sys/param.h> 41 #include <sys/types.h> 42 #include <sys/signal.h> 43 #include <sys/stream.h> 44 #include <sys/termio.h> 45 #include <sys/errno.h> 46 #include <sys/file.h> 47 #include <sys/cmn_err.h> 48 #include <sys/stropts.h> 49 #include <sys/strsubr.h> 50 #include <sys/strsun.h> 51 #include <sys/strtty.h> 52 #include <sys/debug.h> 53 #include <sys/kbio.h> 54 #include <sys/cred.h> 55 #include <sys/modctl.h> 56 #include <sys/stat.h> 57 #include <sys/consdev.h> 58 #include <sys/mkdev.h> 59 #include <sys/kmem.h> 60 #include <sys/cred.h> 61 #ifdef DEBUG 62 #include <sys/promif.h> 63 #endif 64 #include <sys/ddi.h> 65 #include <sys/sunddi.h> 66 #include <sys/sudev.h> 67 #include <sys/note.h> 68 #include <sys/timex.h> 69 #include <sys/policy.h> 70 71 #define async_stopc async_ttycommon.t_stopc 72 #define async_startc async_ttycommon.t_startc 73 74 #define ASY_INIT 1 75 #define ASY_NOINIT 0 76 77 #ifdef DEBUG 78 #define ASY_DEBUG_INIT 0x001 79 #define ASY_DEBUG_INPUT 0x002 80 #define ASY_DEBUG_EOT 0x004 81 #define ASY_DEBUG_CLOSE 0x008 82 #define ASY_DEBUG_HFLOW 0x010 83 #define ASY_DEBUG_PROCS 0x020 84 #define ASY_DEBUG_STATE 0x040 85 #define ASY_DEBUG_INTR 0x080 86 static int asydebug = 0; 87 #endif 88 static int su_log = 0; 89 90 int su_drain_check = 15000000; /* tunable: exit drain check time */ 91 92 static struct ppsclockev asy_ppsev; 93 94 static int max_asy_instance = -1; 95 static void *su_asycom; /* soft state asycom pointer */ 96 static void *su_asyncline; /* soft state asyncline pointer */ 97 static boolean_t abort_charseq_recognize(uchar_t ch); 98 99 static uint_t asysoftintr(caddr_t intarg); 100 static uint_t asyintr(caddr_t argasy); 101 102 /* The async interrupt entry points */ 103 static void async_txint(struct asycom *asy, uchar_t lsr); 104 static void async_rxint(struct asycom *asy, uchar_t lsr); 105 static void async_msint(struct asycom *asy); 106 static int async_softint(struct asycom *asy); 107 108 static void async_ioctl(struct asyncline *async, queue_t *q, mblk_t *mp, 109 boolean_t iswput); 110 static void async_reioctl(void *); 111 static void async_iocdata(queue_t *q, mblk_t *mp); 112 static void async_restart(void *); 113 static void async_start(struct asyncline *async); 114 static void async_nstart(struct asyncline *async, int mode); 115 static void async_resume(struct asyncline *async); 116 static int asy_program(struct asycom *asy, int mode); 117 118 /* Polled mode functions */ 119 static void asyputchar(cons_polledio_arg_t, uchar_t c); 120 static int asygetchar(cons_polledio_arg_t); 121 static boolean_t asyischar(cons_polledio_arg_t); 122 static void asy_polled_enter(cons_polledio_arg_t); 123 static void asy_polled_exit(cons_polledio_arg_t); 124 125 static int asymctl(struct asycom *, int, int); 126 static int asytodm(int, int); 127 static int dmtoasy(int); 128 static void asycheckflowcontrol_hw(struct asycom *asy); 129 static boolean_t asycheckflowcontrol_sw(struct asycom *asy); 130 static void asy_ppsevent(struct asycom *asy, int msr); 131 132 extern kcondvar_t lbolt_cv; 133 extern int ddi_create_internal_pathname(dev_info_t *dip, char *name, 134 int spec_type, minor_t minor_num); 135 136 137 /* 138 * Baud rate table. Indexed by #defines found in sys/termios.h 139 */ 140 ushort_t asyspdtab[] = { 141 0, /* 0 baud rate */ 142 0x900, /* 50 baud rate */ 143 0x600, /* 75 baud rate */ 144 0x417, /* 110 baud rate (%0.026) */ 145 0x359, /* 134 baud rate (%0.058) */ 146 0x300, /* 150 baud rate */ 147 0x240, /* 200 baud rate */ 148 0x180, /* 300 baud rate */ 149 0x0c0, /* 600 baud rate */ 150 0x060, /* 1200 baud rate */ 151 0x040, /* 1800 baud rate */ 152 0x030, /* 2400 baud rate */ 153 0x018, /* 4800 baud rate */ 154 0x00c, /* 9600 baud rate */ 155 0x006, /* 19200 baud rate */ 156 0x003, /* 38400 baud rate */ 157 0x002, /* 57600 baud rate */ 158 0, /* 76800 baud rate - not supported */ 159 0x001, /* 115200 baud rate */ 160 0, /* 153600 baud rate - not supported */ 161 0x8002, /* 230400 baud rate - supported on specific platforms */ 162 0, /* 307200 baud rate - not supported */ 163 0x8001 /* 460800 baud rate - supported on specific platforms */ 164 }; 165 166 /* 167 * Number of speeds supported is the number of entries in 168 * the above table. 169 */ 170 #define N_SU_SPEEDS (sizeof (asyspdtab)/sizeof (ushort_t)) 171 172 /* 173 * Human-readable baud rate table. 174 * Indexed by #defines found in sys/termios.h 175 */ 176 int baudtable[] = { 177 0, /* 0 baud rate */ 178 50, /* 50 baud rate */ 179 75, /* 75 baud rate */ 180 110, /* 110 baud rate */ 181 134, /* 134 baud rate */ 182 150, /* 150 baud rate */ 183 200, /* 200 baud rate */ 184 300, /* 300 baud rate */ 185 600, /* 600 baud rate */ 186 1200, /* 1200 baud rate */ 187 1800, /* 1800 baud rate */ 188 2400, /* 2400 baud rate */ 189 4800, /* 4800 baud rate */ 190 9600, /* 9600 baud rate */ 191 19200, /* 19200 baud rate */ 192 38400, /* 38400 baud rate */ 193 57600, /* 57600 baud rate */ 194 76800, /* 76800 baud rate */ 195 115200, /* 115200 baud rate */ 196 153600, /* 153600 baud rate */ 197 230400, /* 230400 baud rate */ 198 307200, /* 307200 baud rate */ 199 460800 /* 460800 baud rate */ 200 }; 201 202 static int asyopen(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); 203 static int asyclose(queue_t *q, int flag); 204 static void asywput(queue_t *q, mblk_t *mp); 205 static void asyrsrv(queue_t *q); 206 207 struct module_info asy_info = { 208 0, 209 "su", 210 0, 211 INFPSZ, 212 32*4096, 213 4096 214 }; 215 216 static struct qinit asy_rint = { 217 putq, 218 (int (*)())asyrsrv, 219 asyopen, 220 asyclose, 221 NULL, 222 &asy_info, 223 NULL 224 }; 225 226 static struct qinit asy_wint = { 227 (int (*)())asywput, 228 NULL, 229 NULL, 230 NULL, 231 NULL, 232 &asy_info, 233 NULL 234 }; 235 236 struct streamtab asy_str_info = { 237 &asy_rint, 238 &asy_wint, 239 NULL, 240 NULL 241 }; 242 243 static int asyinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 244 void **result); 245 static int asyprobe(dev_info_t *); 246 static int asyattach(dev_info_t *, ddi_attach_cmd_t); 247 static int asydetach(dev_info_t *, ddi_detach_cmd_t); 248 249 static struct cb_ops cb_asy_ops = { 250 nodev, /* cb_open */ 251 nodev, /* cb_close */ 252 nodev, /* cb_strategy */ 253 nodev, /* cb_print */ 254 nodev, /* cb_dump */ 255 nodev, /* cb_read */ 256 nodev, /* cb_write */ 257 nodev, /* cb_ioctl */ 258 nodev, /* cb_devmap */ 259 nodev, /* cb_mmap */ 260 nodev, /* cb_segmap */ 261 nochpoll, /* cb_chpoll */ 262 ddi_prop_op, /* cb_prop_op */ 263 &asy_str_info, /* cb_stream */ 264 D_MP /* cb_flag */ 265 }; 266 267 struct dev_ops asy_ops = { 268 DEVO_REV, /* devo_rev */ 269 0, /* devo_refcnt */ 270 asyinfo, /* devo_getinfo */ 271 nulldev, /* devo_identify */ 272 asyprobe, /* devo_probe */ 273 asyattach, /* devo_attach */ 274 asydetach, /* devo_detach */ 275 nodev, /* devo_reset */ 276 &cb_asy_ops, /* devo_cb_ops */ 277 }; 278 279 /* 280 * Module linkage information for the kernel. 281 */ 282 283 static struct modldrv modldrv = { 284 &mod_driverops, /* Type of module. This one is a driver */ 285 "su driver %I%", 286 &asy_ops, /* driver ops */ 287 }; 288 289 static struct modlinkage modlinkage = { 290 MODREV_1, 291 &modldrv, 292 NULL 293 }; 294 295 int 296 _init(void) 297 { 298 int status; 299 300 status = ddi_soft_state_init(&su_asycom, sizeof (struct asycom), 301 SU_INITIAL_SOFT_ITEMS); 302 if (status != 0) 303 return (status); 304 status = ddi_soft_state_init(&su_asyncline, sizeof (struct asyncline), 305 SU_INITIAL_SOFT_ITEMS); 306 if (status != 0) { 307 ddi_soft_state_fini(&su_asycom); 308 return (status); 309 } 310 311 if ((status = mod_install(&modlinkage)) != 0) { 312 ddi_soft_state_fini(&su_asycom); 313 ddi_soft_state_fini(&su_asyncline); 314 } 315 316 return (status); 317 } 318 319 int 320 _fini(void) 321 { 322 int i; 323 324 i = mod_remove(&modlinkage); 325 if (i == 0) { 326 ddi_soft_state_fini(&su_asycom); 327 ddi_soft_state_fini(&su_asyncline); 328 } 329 330 return (i); 331 } 332 333 int 334 _info(struct modinfo *modinfop) 335 { 336 return (mod_info(&modlinkage, modinfop)); 337 } 338 339 static int 340 asyprobe(dev_info_t *devi) 341 { 342 int instance; 343 ddi_acc_handle_t handle; 344 uchar_t *addr; 345 ddi_device_acc_attr_t attr; 346 347 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 348 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 349 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 350 if (ddi_regs_map_setup(devi, SU_REGISTER_FILE_NO, (caddr_t *)&addr, 351 SU_REGOFFSET, SU_REGISTER_LEN, &attr, &handle) != DDI_SUCCESS) { 352 cmn_err(CE_WARN, "asyprobe regs map setup failed"); 353 return (DDI_PROBE_FAILURE); 354 } 355 #ifdef DEBUG 356 if (asydebug) 357 printf("Probe address mapped %p\n", (void *)addr); 358 #endif 359 360 /* 361 * Probe for the device: 362 * Ser. int. uses bits 0,1,2; FIFO uses 3,6,7; 4,5 wired low. 363 * If bit 4 or 5 appears on inb() ISR, board is not there. 364 */ 365 if (ddi_get8(handle, addr+ISR) & 0x30) { 366 ddi_regs_map_free(&handle); 367 return (DDI_PROBE_FAILURE); 368 } 369 370 instance = ddi_get_instance(devi); 371 if (max_asy_instance < instance) 372 max_asy_instance = instance; 373 ddi_regs_map_free(&handle); 374 375 return (DDI_PROBE_SUCCESS); /* hw is present */ 376 } 377 378 static int 379 asydetach(dev_info_t *devi, ddi_detach_cmd_t cmd) 380 { 381 register int instance; 382 struct asycom *asy; 383 struct asyncline *async; 384 char name[16]; 385 386 instance = ddi_get_instance(devi); /* find out which unit */ 387 388 asy = (struct asycom *)ddi_get_soft_state(su_asycom, instance); 389 async = (struct asyncline *)ddi_get_soft_state(su_asyncline, instance); 390 391 switch (cmd) { 392 case DDI_DETACH: 393 break; 394 case DDI_SUSPEND: 395 /* grab both mutex locks */ 396 mutex_enter(asy->asy_excl); 397 mutex_enter(asy->asy_excl_hi); 398 if (asy->suspended) { 399 mutex_exit(asy->asy_excl_hi); 400 mutex_exit(asy->asy_excl); 401 return (DDI_SUCCESS); 402 } 403 asy->suspended = B_TRUE; 404 405 /* 406 * The quad UART ST16C554D, version D2 (made by EXAR) 407 * has an anomaly of generating spurious interrupts 408 * when the ICR is loaded with zero. The workaround 409 * would be to read/write any register with DATA1 bit 410 * set to 0 before such write. 411 */ 412 if (asy->asy_hwtype == ASY16C554D) 413 OUTB(SPR, 0); 414 415 /* Disable further interrupts */ 416 OUTB(ICR, 0); 417 mutex_exit(asy->asy_excl_hi); 418 mutex_exit(asy->asy_excl); 419 return (DDI_SUCCESS); 420 421 default: 422 return (DDI_FAILURE); 423 } 424 425 #ifdef DEBUG 426 if (asydebug & ASY_DEBUG_INIT) 427 cmn_err(CE_NOTE, "su%d: ASY%s shutdown.", instance, 428 asy->asy_hwtype == ASY82510 ? "82510" : 429 asy->asy_hwtype == ASY16550AF ? "16550AF" : 430 asy->asy_hwtype == ASY16C554D ? "16C554D" : 431 "8250"); 432 #endif 433 /* 434 * Before removing interrupts it is always better to disable 435 * interrupts if the chip gives a provision to disable the 436 * serial port interrupts. 437 */ 438 mutex_enter(asy->asy_excl); 439 mutex_enter(asy->asy_excl_hi); 440 /* disable interrupts, see EXAR bug */ 441 if (asy->asy_hwtype == ASY16C554D) 442 OUTB(SPR, 0); 443 OUTB(ICR, 0); 444 mutex_exit(asy->asy_excl_hi); 445 mutex_exit(asy->asy_excl); 446 447 /* remove minor device node(s) for this device */ 448 (void) sprintf(name, "%c", (instance+'a')); /* serial-port */ 449 ddi_remove_minor_node(devi, name); 450 (void) sprintf(name, "%c,cu", (instance+'a')); /* serial-port:dailout */ 451 ddi_remove_minor_node(devi, name); 452 453 mutex_destroy(asy->asy_excl); 454 mutex_destroy(asy->asy_excl_hi); 455 kmem_free(asy->asy_excl, sizeof (kmutex_t)); 456 kmem_free(asy->asy_excl_hi, sizeof (kmutex_t)); 457 cv_destroy(&async->async_flags_cv); 458 kstat_delete(asy->sukstat); 459 ddi_remove_intr(devi, 0, asy->asy_iblock); 460 ddi_regs_map_free(&asy->asy_handle); 461 ddi_remove_softintr(asy->asy_softintr_id); 462 mutex_destroy(asy->asy_soft_lock); 463 kmem_free(asy->asy_soft_lock, sizeof (kmutex_t)); 464 ddi_soft_state_free(su_asycom, instance); 465 ddi_soft_state_free(su_asyncline, instance); 466 return (DDI_SUCCESS); 467 } 468 469 static int 470 asyattach(dev_info_t *devi, ddi_attach_cmd_t cmd) 471 { 472 register int instance; 473 struct asycom *asy; 474 struct asyncline *async; 475 char name[40]; 476 ddi_device_acc_attr_t attr; 477 enum states { EMPTY, SOFTSTATE, REGSMAP, MUTEXES, ADDINTR, 478 SOFTINTR, ASYINIT, KSTAT, MINORNODE }; 479 enum states state = EMPTY; 480 char *hwtype; 481 482 instance = ddi_get_instance(devi); /* find out which unit */ 483 484 /* cannot attach a device that has not been probed first */ 485 if (instance > max_asy_instance) 486 return (DDI_FAILURE); 487 488 if (cmd != DDI_RESUME) { 489 /* Allocate soft state space */ 490 if (ddi_soft_state_zalloc(su_asycom, instance) != DDI_SUCCESS) { 491 cmn_err(CE_WARN, "su%d: cannot allocate soft state", 492 instance); 493 goto error; 494 } 495 } 496 state = SOFTSTATE; 497 498 asy = (struct asycom *)ddi_get_soft_state(su_asycom, instance); 499 500 if (asy == NULL) { 501 cmn_err(CE_WARN, "su%d: cannot get soft state", instance); 502 goto error; 503 } 504 505 switch (cmd) { 506 case DDI_ATTACH: 507 break; 508 case DDI_RESUME: { 509 struct asyncline *async; 510 511 /* grab both mutex locks */ 512 mutex_enter(asy->asy_excl); 513 mutex_enter(asy->asy_excl_hi); 514 if (!asy->suspended) { 515 mutex_exit(asy->asy_excl_hi); 516 mutex_exit(asy->asy_excl); 517 return (DDI_SUCCESS); 518 } 519 /* 520 * re-setup all the registers and enable interrupts if 521 * needed 522 */ 523 async = (struct asyncline *)asy->asy_priv; 524 if ((async) && (async->async_flags & ASYNC_ISOPEN)) 525 (void) asy_program(asy, ASY_INIT); 526 asy->suspended = B_FALSE; 527 mutex_exit(asy->asy_excl_hi); 528 mutex_exit(asy->asy_excl); 529 return (DDI_SUCCESS); 530 } 531 default: 532 goto error; 533 } 534 535 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 536 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 537 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 538 539 if (ddi_regs_map_setup(devi, SU_REGISTER_FILE_NO, 540 (caddr_t *)&asy->asy_ioaddr, SU_REGOFFSET, SU_REGISTER_LEN, 541 &attr, &asy->asy_handle) != DDI_SUCCESS) { 542 cmn_err(CE_WARN, "asyprobe regs map setup failed"); 543 goto error; 544 } 545 state = REGSMAP; 546 547 #ifdef DEBUG 548 if (asydebug) 549 printf("su attach mapped %p\n", (void *)asy->asy_ioaddr); 550 #endif 551 552 /* 553 * Initialize the port with default settings. 554 */ 555 asy->asy_fifo_buf = 1; 556 asy->asy_use_fifo = FIFO_OFF; 557 558 /* 559 * Check for baudrate generator's "baud-divisor-factor" property setup 560 * by OBP, since different UART chips might have different baudrate 561 * generator divisor. e.g., in case of NSPG's Sputnik platform, the 562 * baud-divisor-factor is 13, it uses dedicated 16552 "DUART" chip 563 * instead of SuperIO. Since the baud-divisor-factor must be a positive 564 * integer, the divisors will always be at least as large as the values 565 * in asyspdtab[]. Make the default factor 1. 566 */ 567 asy->asy_baud_divisor_factor = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 568 DDI_PROP_DONTPASS, "baud-divisor-factor", 1); 569 570 /* set speed cap */ 571 asy->asy_speed_cap = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 572 DDI_PROP_DONTPASS, "serial-speed-cap", 115200); 573 574 /* check for ASY82510 chip */ 575 OUTB(ISR, 0x20); 576 if (INB(ISR) & 0x20) { /* 82510 chip is present */ 577 /* 578 * Since most of the general operation of the 82510 chip 579 * can be done from BANK 0 (8250A/16450 compatable mode) 580 * we will default to BANK 0. 581 */ 582 asy->asy_hwtype = ASY82510; 583 OUTB(DAT+7, 0x04); /* clear status */ 584 OUTB(ISR, 0x40); /* set to bank 2 */ 585 OUTB(MCR, 0x08); /* IMD */ 586 OUTB(DAT, 0x21); /* FMD */ 587 OUTB(ISR, 0x00); /* set to bank 0 */ 588 asy->asy_trig_level = 0; 589 } else { /* Set the UART in FIFO mode if it has FIFO buffers */ 590 asy->asy_hwtype = ASY16550AF; 591 OUTB(FIFOR, 0x00); /* clear fifo register */ 592 asy->asy_trig_level = 0x00; /* sets the fifo Threshold to 1 */ 593 594 /* set/Enable FIFO */ 595 OUTB(FIFOR, FIFO_ON | FIFODMA | FIFOTXFLSH | FIFORXFLSH | 596 (asy->asy_trig_level & 0xff)); 597 598 if ((INB(ISR) & 0xc0) == 0xc0) 599 asy->asy_use_fifo = FIFO_ON; 600 else { 601 asy->asy_hwtype = ASY8250; 602 OUTB(FIFOR, 0x00); /* NO FIFOs */ 603 asy->asy_trig_level = 0; 604 } 605 } 606 607 /* check for ST16C554D chip */ 608 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, DDI_PROP_NOTPROM | 609 DDI_PROP_DONTPASS, "hwtype", &hwtype)) == DDI_PROP_SUCCESS) { 610 if (strcmp(hwtype, "ST16C554D") == 0) 611 asy->asy_hwtype = ASY16C554D; 612 ddi_prop_free(hwtype); 613 } 614 615 /* disable interrupts, see EXAR bug */ 616 if (asy->asy_hwtype == ASY16C554D) 617 OUTB(SPR, 0); 618 OUTB(ICR, 0); 619 OUTB(LCR, DLAB); /* select baud rate generator */ 620 /* Set the baud rate to 9600 */ 621 OUTB(DAT+DLL, (ASY9600*asy->asy_baud_divisor_factor) & 0xff); 622 OUTB(DAT+DLH, ((ASY9600*asy->asy_baud_divisor_factor) >> 8) & 0xff); 623 OUTB(LCR, STOP1|BITS8); 624 OUTB(MCR, (DTR | RTS| OUT2)); 625 626 /* 627 * Set up the other components of the asycom structure for this port. 628 */ 629 asy->asy_excl = (kmutex_t *) 630 kmem_zalloc(sizeof (kmutex_t), KM_SLEEP); 631 asy->asy_excl_hi = (kmutex_t *) 632 kmem_zalloc(sizeof (kmutex_t), KM_SLEEP); 633 asy->asy_soft_lock = (kmutex_t *) 634 kmem_zalloc(sizeof (kmutex_t), KM_SLEEP); 635 asy->asy_unit = instance; 636 asy->asy_dip = devi; 637 638 if (ddi_get_iblock_cookie(devi, 0, &asy->asy_iblock) != DDI_SUCCESS) { 639 cmn_err(CE_NOTE, 640 "Get iblock_cookie failed-Device interrupt%x\n", instance); 641 goto error; 642 } 643 644 if (ddi_get_soft_iblock_cookie(devi, DDI_SOFTINT_HIGH, 645 &asy->asy_soft_iblock) != DDI_SUCCESS) { 646 cmn_err(CE_NOTE, "Get iblock_cookie failed -soft interrupt%x\n", 647 instance); 648 goto error; 649 } 650 651 mutex_init(asy->asy_soft_lock, NULL, MUTEX_DRIVER, 652 (void *)asy->asy_soft_iblock); 653 mutex_init(asy->asy_excl, NULL, MUTEX_DRIVER, NULL); 654 mutex_init(asy->asy_excl_hi, NULL, MUTEX_DRIVER, 655 (void *)asy->asy_iblock); 656 state = MUTEXES; 657 658 /* 659 * Install interrupt handlers for this device. 660 */ 661 if (ddi_add_intr(devi, 0, &(asy->asy_iblock), 0, asyintr, 662 (caddr_t)asy) != DDI_SUCCESS) { 663 cmn_err(CE_CONT, 664 "Cannot set device interrupt for su driver\n"); 665 goto error; 666 } 667 state = ADDINTR; 668 669 if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &(asy->asy_softintr_id), 670 &asy->asy_soft_iblock, 0, asysoftintr, (caddr_t)asy) 671 != DDI_SUCCESS) { 672 cmn_err(CE_CONT, "Cannot set soft interrupt for su driver\n"); 673 goto error; 674 } 675 state = SOFTINTR; 676 677 /* initialize the asyncline structure */ 678 if (ddi_soft_state_zalloc(su_asyncline, instance) != DDI_SUCCESS) { 679 cmn_err(CE_CONT, "su%d: cannot allocate soft state", instance); 680 goto error; 681 } 682 state = ASYINIT; 683 684 async = (struct asyncline *)ddi_get_soft_state(su_asyncline, instance); 685 686 mutex_enter(asy->asy_excl); 687 async->async_common = asy; 688 cv_init(&async->async_flags_cv, NULL, CV_DEFAULT, NULL); 689 mutex_exit(asy->asy_excl); 690 691 if ((asy->sukstat = kstat_create("su", instance, "serialstat", 692 "misc", KSTAT_TYPE_NAMED, 2, KSTAT_FLAG_VIRTUAL)) != NULL) { 693 asy->sukstat->ks_data = &asy->kstats; 694 kstat_named_init(&asy->kstats.ringover, "ring buffer overflow", 695 KSTAT_DATA_UINT64); 696 kstat_named_init(&asy->kstats.siloover, "silo overflow", 697 KSTAT_DATA_UINT64); 698 kstat_install(asy->sukstat); 699 } 700 state = KSTAT; 701 702 if (strcmp(ddi_node_name(devi), "rsc-console") == 0) { 703 /* 704 * If the device is configured as the 'rsc-console' 705 * create the minor device for this node. 706 */ 707 if (ddi_create_minor_node(devi, "ssp", S_IFCHR, 708 asy->asy_unit | RSC_DEVICE, DDI_PSEUDO, NULL) 709 == DDI_FAILURE) { 710 cmn_err(CE_WARN, 711 "%s%d: Failed to create node rsc-console", 712 ddi_get_name(devi), ddi_get_instance(devi)); 713 goto error; 714 } 715 716 asy->asy_lom_console = 0; 717 asy->asy_rsc_console = 1; 718 asy->asy_rsc_control = 0; 719 asy->asy_device_type = ASY_SERIAL; 720 asy->asy_flags |= ASY_IGNORE_CD; 721 722 } else if (strcmp(ddi_node_name(devi), "lom-console") == 0) { 723 /* 724 * If the device is configured as the 'lom-console' 725 * create the minor device for this node. 726 * Do not create a dialout device. 727 * Use the same minor numbers as would be used for standard 728 * serial instances. 729 */ 730 if (ddi_create_minor_node(devi, "lom-console", S_IFCHR, 731 instance, DDI_NT_SERIAL_LOMCON, NULL) == DDI_FAILURE) { 732 cmn_err(CE_WARN, 733 "%s%d: Failed to create node lom-console", 734 ddi_get_name(devi), ddi_get_instance(devi)); 735 goto error; 736 } 737 asy->asy_lom_console = 1; 738 asy->asy_rsc_console = 0; 739 asy->asy_rsc_control = 0; 740 asy->asy_device_type = ASY_SERIAL; 741 asy->asy_flags |= ASY_IGNORE_CD; 742 743 } else if (strcmp(ddi_node_name(devi), "rsc-control") == 0) { 744 /* 745 * If the device is configured as the 'rsc-control' 746 * create the minor device for this node. 747 */ 748 if (ddi_create_minor_node(devi, "sspctl", S_IFCHR, 749 asy->asy_unit | RSC_DEVICE, DDI_PSEUDO, NULL) 750 == DDI_FAILURE) { 751 cmn_err(CE_WARN, "%s%d: Failed to create rsc-control", 752 ddi_get_name(devi), ddi_get_instance(devi)); 753 goto error; 754 } 755 756 asy->asy_lom_console = 0; 757 asy->asy_rsc_console = 0; 758 asy->asy_rsc_control = 1; 759 asy->asy_device_type = ASY_SERIAL; 760 asy->asy_flags |= ASY_IGNORE_CD; 761 762 } else if (ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 763 "keyboard", 0)) { 764 /* 765 * If the device is a keyboard, then create an internal 766 * pathname so that the dacf code will link the node into 767 * the keyboard console stream. See dacf.conf. 768 */ 769 if (ddi_create_internal_pathname(devi, "keyboard", 770 S_IFCHR, instance) == DDI_FAILURE) { 771 goto error; 772 } 773 asy->asy_flags |= ASY_IGNORE_CD; /* ignore cd */ 774 asy->asy_device_type = ASY_KEYBOARD; /* Device type */ 775 } else if (ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 776 "mouse", 0)) { 777 /* 778 * If the device is a mouse, then create an internal 779 * pathname so that the dacf code will link the node into 780 * the mouse stream. See dacf.conf. 781 */ 782 if (ddi_create_internal_pathname(devi, "mouse", S_IFCHR, 783 instance) == DDI_FAILURE) { 784 goto error; 785 } 786 asy->asy_flags |= ASY_IGNORE_CD; /* ignore cd */ 787 asy->asy_device_type = ASY_MOUSE; 788 } else { 789 /* 790 * If not used for keyboard/mouse, create minor devices nodes 791 * for this device 792 */ 793 /* serial-port */ 794 (void) sprintf(name, "%c", (instance+'a')); 795 if (ddi_create_minor_node(devi, name, S_IFCHR, instance, 796 DDI_NT_SERIAL_MB, NULL) == DDI_FAILURE) { 797 goto error; 798 } 799 state = MINORNODE; 800 /* serial-port:dailout */ 801 (void) sprintf(name, "%c,cu", (instance+'a')); 802 if (ddi_create_minor_node(devi, name, S_IFCHR, instance|OUTLINE, 803 DDI_NT_SERIAL_MB_DO, NULL) == DDI_FAILURE) { 804 goto error; 805 } 806 /* Property for ignoring DCD */ 807 if (ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 808 "ignore-cd", 0)) { 809 asy->asy_flags |= ASY_IGNORE_CD; /* ignore cd */ 810 } else { 811 asy->asy_flags &= ~ASY_IGNORE_CD; 812 /* 813 * if ignore-cd is not available it could be 814 * some old legacy platform, try to see 815 * whether the old legacy property exists 816 */ 817 (void) sprintf(name, 818 "port-%c-ignore-cd", (instance+ 'a')); 819 if (ddi_getprop(DDI_DEV_T_ANY, devi, 820 DDI_PROP_DONTPASS, name, 0)) 821 asy->asy_flags |= ASY_IGNORE_CD; 822 } 823 asy->asy_device_type = ASY_SERIAL; 824 } 825 826 /* 827 * Fill in the polled I/O structure 828 */ 829 asy->polledio.cons_polledio_version = CONSPOLLEDIO_V0; 830 asy->polledio.cons_polledio_argument = (cons_polledio_arg_t)asy; 831 asy->polledio.cons_polledio_putchar = asyputchar; 832 asy->polledio.cons_polledio_getchar = asygetchar; 833 asy->polledio.cons_polledio_ischar = asyischar; 834 asy->polledio.cons_polledio_enter = asy_polled_enter; 835 asy->polledio.cons_polledio_exit = asy_polled_exit; 836 837 /* Initialize saved ICR and polled_enter */ 838 asy->polled_icr = 0; 839 asy->polled_enter = B_FALSE; 840 841 ddi_report_dev(devi); 842 return (DDI_SUCCESS); 843 844 error: 845 if (state == MINORNODE) { 846 (void) sprintf(name, "%c", (instance+'a')); 847 ddi_remove_minor_node(devi, name); 848 } 849 if (state >= KSTAT) 850 kstat_delete(asy->sukstat); 851 if (state >= ASYINIT) { 852 cv_destroy(&async->async_flags_cv); 853 ddi_soft_state_free(su_asyncline, instance); 854 } 855 if (state >= SOFTINTR) 856 ddi_remove_softintr(asy->asy_softintr_id); 857 if (state >= ADDINTR) 858 ddi_remove_intr(devi, 0, asy->asy_iblock); 859 if (state >= MUTEXES) { 860 mutex_destroy(asy->asy_excl_hi); 861 mutex_destroy(asy->asy_excl); 862 mutex_destroy(asy->asy_soft_lock); 863 kmem_free(asy->asy_excl_hi, sizeof (kmutex_t)); 864 kmem_free(asy->asy_excl, sizeof (kmutex_t)); 865 kmem_free(asy->asy_soft_lock, sizeof (kmutex_t)); 866 } 867 if (state >= REGSMAP) 868 ddi_regs_map_free(&asy->asy_handle); 869 if (state >= SOFTSTATE) 870 ddi_soft_state_free(su_asycom, instance); 871 /* no action for EMPTY state */ 872 return (DDI_FAILURE); 873 } 874 875 static int 876 asyinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 877 void **result) 878 { 879 _NOTE(ARGUNUSED(dip)) 880 register dev_t dev = (dev_t)arg; 881 register int instance, error; 882 struct asycom *asy; 883 884 if ((instance = UNIT(dev)) > max_asy_instance) 885 return (DDI_FAILURE); 886 887 switch (infocmd) { 888 case DDI_INFO_DEVT2DEVINFO: 889 asy = (struct asycom *)ddi_get_soft_state(su_asycom, 890 instance); 891 if (asy->asy_dip == NULL) 892 error = DDI_FAILURE; 893 else { 894 *result = (void *) asy->asy_dip; 895 error = DDI_SUCCESS; 896 } 897 break; 898 case DDI_INFO_DEVT2INSTANCE: 899 *result = (void *)(uintptr_t)instance; 900 error = DDI_SUCCESS; 901 break; 902 default: 903 error = DDI_FAILURE; 904 } 905 return (error); 906 } 907 908 static int 909 asyopen(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 910 { 911 _NOTE(ARGUNUSED(sflag)) 912 struct asycom *asy; 913 struct asyncline *async; 914 int mcr; 915 int unit; 916 int len; 917 struct termios *termiosp; 918 919 #ifdef DEBUG 920 if (asydebug & ASY_DEBUG_CLOSE) 921 printf("open\n"); 922 #endif 923 unit = UNIT(*dev); 924 if (unit > max_asy_instance) 925 return (ENXIO); /* unit not configured */ 926 927 async = (struct asyncline *)ddi_get_soft_state(su_asyncline, unit); 928 if (async == NULL) 929 return (ENXIO); 930 931 asy = async->async_common; 932 if (asy == NULL) 933 return (ENXIO); /* device not found by autoconfig */ 934 935 mutex_enter(asy->asy_excl); 936 asy->asy_priv = (caddr_t)async; 937 938 again: 939 mutex_enter(asy->asy_excl_hi); 940 /* 941 * Block waiting for carrier to come up, unless this is a no-delay open. 942 */ 943 if (!(async->async_flags & ASYNC_ISOPEN)) { 944 /* 945 * If this port is for a RSC console or control 946 * use the following termio info 947 */ 948 if (asy->asy_rsc_console || asy->asy_rsc_control) { 949 async->async_ttycommon.t_cflag = CIBAUDEXT | CBAUDEXT | 950 (B115200 & CBAUD); 951 async->async_ttycommon.t_cflag |= ((B115200 << IBSHIFT) 952 & CIBAUD); 953 async->async_ttycommon.t_cflag |= CS8 | CREAD | CLOCAL; 954 } else if (asy->asy_lom_console) { 955 async->async_ttycommon.t_cflag = B9600 & CBAUD; 956 async->async_ttycommon.t_cflag |= ((B9600 << IBSHIFT) 957 & CIBAUD); 958 async->async_ttycommon.t_cflag |= CS8 | CREAD | CLOCAL; 959 } else { 960 961 /* 962 * Set the default termios settings (cflag). 963 * Others are set in ldterm. Release the spin 964 * mutex as we can block here, reaquire before 965 * calling asy_program. 966 */ 967 mutex_exit(asy->asy_excl_hi); 968 if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 969 0, "ttymodes", (caddr_t)&termiosp, &len) 970 == DDI_PROP_SUCCESS && 971 len == sizeof (struct termios)) { 972 async->async_ttycommon.t_cflag = 973 termiosp->c_cflag; 974 kmem_free(termiosp, len); 975 } else { 976 cmn_err(CE_WARN, 977 "su: couldn't get ttymodes property!"); 978 } 979 mutex_enter(asy->asy_excl_hi); 980 } 981 async->async_ttycommon.t_iflag = 0; 982 async->async_ttycommon.t_iocpending = NULL; 983 async->async_ttycommon.t_size.ws_row = 0; 984 async->async_ttycommon.t_size.ws_col = 0; 985 async->async_ttycommon.t_size.ws_xpixel = 0; 986 async->async_ttycommon.t_size.ws_ypixel = 0; 987 async->async_dev = *dev; 988 async->async_wbufcid = 0; 989 990 async->async_startc = CSTART; 991 async->async_stopc = CSTOP; 992 (void) asy_program(asy, ASY_INIT); 993 } else if ((async->async_ttycommon.t_flags & TS_XCLUDE) && 994 secpolicy_excl_open(cr) != 0) { 995 mutex_exit(asy->asy_excl_hi); 996 mutex_exit(asy->asy_excl); 997 return (EBUSY); 998 } else if ((*dev & OUTLINE) && !(async->async_flags & ASYNC_OUT)) { 999 mutex_exit(asy->asy_excl_hi); 1000 mutex_exit(asy->asy_excl); 1001 return (EBUSY); 1002 } 1003 1004 if (*dev & OUTLINE) 1005 async->async_flags |= ASYNC_OUT; 1006 1007 /* Raise DTR on every open */ 1008 mcr = INB(MCR); 1009 OUTB(MCR, mcr|DTR); 1010 1011 /* 1012 * Check carrier. 1013 */ 1014 if (asy->asy_flags & ASY_IGNORE_CD) 1015 async->async_ttycommon.t_flags |= TS_SOFTCAR; 1016 if ((async->async_ttycommon.t_flags & TS_SOFTCAR) || 1017 (INB(MSR) & DCD)) 1018 async->async_flags |= ASYNC_CARR_ON; 1019 else 1020 async->async_flags &= ~ASYNC_CARR_ON; 1021 mutex_exit(asy->asy_excl_hi); 1022 1023 /* 1024 * If FNDELAY and FNONBLOCK are clear, block until carrier up. 1025 * Quit on interrupt. 1026 */ 1027 if (!(flag & (FNDELAY|FNONBLOCK)) && 1028 !(async->async_ttycommon.t_cflag & CLOCAL)) { 1029 if (!(async->async_flags & (ASYNC_CARR_ON|ASYNC_OUT)) || 1030 ((async->async_flags & ASYNC_OUT) && 1031 !(*dev & OUTLINE))) { 1032 async->async_flags |= ASYNC_WOPEN; 1033 if (cv_wait_sig(&async->async_flags_cv, 1034 asy->asy_excl) == 0) { 1035 async->async_flags &= ~ASYNC_WOPEN; 1036 mutex_exit(asy->asy_excl); 1037 return (EINTR); 1038 } 1039 async->async_flags &= ~ASYNC_WOPEN; 1040 goto again; 1041 } 1042 } else if ((async->async_flags & ASYNC_OUT) && !(*dev & OUTLINE)) { 1043 mutex_exit(asy->asy_excl); 1044 return (EBUSY); 1045 } 1046 1047 if (asy->suspended) { 1048 mutex_exit(asy->asy_excl); 1049 (void) ddi_dev_is_needed(asy->asy_dip, 0, 1); 1050 mutex_enter(asy->asy_excl); 1051 } 1052 1053 async->async_ttycommon.t_readq = rq; 1054 async->async_ttycommon.t_writeq = WR(rq); 1055 rq->q_ptr = WR(rq)->q_ptr = (caddr_t)async; 1056 mutex_exit(asy->asy_excl); 1057 qprocson(rq); 1058 async->async_flags |= ASYNC_ISOPEN; 1059 async->async_polltid = 0; 1060 return (0); 1061 } 1062 1063 static void 1064 async_progress_check(void *arg) 1065 { 1066 struct asyncline *async = arg; 1067 struct asycom *asy = async->async_common; 1068 mblk_t *bp; 1069 1070 /* 1071 * We define "progress" as either waiting on a timed break or delay, or 1072 * having had at least one transmitter interrupt. If none of these are 1073 * true, then just terminate the output and wake up that close thread. 1074 */ 1075 mutex_enter(asy->asy_excl); 1076 mutex_enter(asy->asy_excl_hi); 1077 if (!(async->async_flags & (ASYNC_BREAK|ASYNC_DELAY|ASYNC_PROGRESS))) { 1078 async->async_ocnt = 0; 1079 async->async_flags &= ~ASYNC_BUSY; 1080 async->async_timer = 0; 1081 bp = async->async_xmitblk; 1082 async->async_xmitblk = NULL; 1083 mutex_exit(asy->asy_excl_hi); 1084 if (bp != NULL) 1085 freeb(bp); 1086 /* 1087 * Since this timer is running, we know that we're in exit(2). 1088 * That means that the user can't possibly be waiting on any 1089 * valid ioctl(2) completion anymore, and we should just flush 1090 * everything. 1091 */ 1092 flushq(async->async_ttycommon.t_writeq, FLUSHALL); 1093 cv_broadcast(&async->async_flags_cv); 1094 } else { 1095 async->async_flags &= ~ASYNC_PROGRESS; 1096 async->async_timer = timeout(async_progress_check, async, 1097 drv_usectohz(su_drain_check)); 1098 mutex_exit(asy->asy_excl_hi); 1099 } 1100 mutex_exit(asy->asy_excl); 1101 } 1102 1103 /* 1104 * Close routine. 1105 */ 1106 static int 1107 asyclose(queue_t *q, int flag) 1108 { 1109 struct asyncline *async; 1110 struct asycom *asy; 1111 int icr, lcr; 1112 int nohupcl; 1113 1114 1115 #ifdef DEBUG 1116 if (asydebug & ASY_DEBUG_CLOSE) 1117 printf("close\n"); 1118 #endif 1119 async = q->q_ptr; 1120 ASSERT(async != NULL); 1121 asy = async->async_common; 1122 1123 /* get the nohupcl OBP property of this device */ 1124 nohupcl = ddi_getprop(DDI_DEV_T_ANY, asy->asy_dip, DDI_PROP_DONTPASS, 1125 "nohupcl", 0); 1126 1127 mutex_enter(asy->asy_excl); 1128 async->async_flags |= ASYNC_CLOSING; 1129 1130 /* 1131 * Turn off PPS handling early to avoid events occuring during 1132 * close. Also reset the DCD edge monitoring bit. 1133 */ 1134 mutex_enter(asy->asy_excl_hi); 1135 asy->asy_flags &= ~(ASY_PPS | ASY_PPS_EDGE); 1136 mutex_exit(asy->asy_excl_hi); 1137 1138 /* 1139 * There are two flavors of break -- timed (M_BREAK or TCSBRK) and 1140 * untimed (TIOCSBRK). For the timed case, these are enqueued on our 1141 * write queue and there's a timer running, so we don't have to worry 1142 * about them. For the untimed case, though, the user obviously made a 1143 * mistake, because these are handled immediately. We'll terminate the 1144 * break now and honor his implicit request by discarding the rest of 1145 * the data. 1146 */ 1147 if (!(async->async_flags & ASYNC_BREAK)) { 1148 mutex_enter(asy->asy_excl_hi); 1149 lcr = INB(LCR); 1150 if (lcr & SETBREAK) { 1151 OUTB(LCR, (lcr & ~SETBREAK)); 1152 } 1153 mutex_exit(asy->asy_excl_hi); 1154 if (lcr & SETBREAK) 1155 goto nodrain; 1156 } 1157 1158 /* 1159 * If the user told us not to delay the close ("non-blocking"), then 1160 * don't bother trying to drain. 1161 * 1162 * If the user did M_STOP (ASYNC_STOPPED), there's no hope of ever 1163 * getting an M_START (since these messages aren't enqueued), and the 1164 * only other way to clear the stop condition is by loss of DCD, which 1165 * would discard the queue data. Thus, we drop the output data if 1166 * ASYNC_STOPPED is set. 1167 */ 1168 if ((flag & (FNDELAY|FNONBLOCK)) || 1169 (async->async_flags & ASYNC_STOPPED)) { 1170 goto nodrain; 1171 } 1172 1173 /* 1174 * If there's any pending output, then we have to try to drain it. 1175 * There are two main cases to be handled: 1176 * - called by close(2): need to drain until done or until 1177 * a signal is received. No timeout. 1178 * - called by exit(2): need to drain while making progress 1179 * or until a timeout occurs. No signals. 1180 * 1181 * If we can't rely on receiving a signal to get us out of a hung 1182 * session, then we have to use a timer. In this case, we set a timer 1183 * to check for progress in sending the output data -- all that we ask 1184 * (at each interval) is that there's been some progress made. Since 1185 * the interrupt routine grabs buffers from the write queue, we can't 1186 * trust async_ocnt. Instead, we use a flag. 1187 * 1188 * Note that loss of carrier will cause the output queue to be flushed, 1189 * and we'll wake up again and finish normally. 1190 */ 1191 if (!ddi_can_receive_sig() && su_drain_check != 0) { 1192 async->async_flags &= ~ASYNC_PROGRESS; 1193 async->async_timer = timeout(async_progress_check, async, 1194 drv_usectohz(su_drain_check)); 1195 } 1196 1197 while (async->async_ocnt > 0 || 1198 async->async_ttycommon.t_writeq->q_first != NULL || 1199 (async->async_flags & (ASYNC_BUSY|ASYNC_BREAK|ASYNC_DELAY))) { 1200 if (cv_wait_sig(&async->async_flags_cv, asy->asy_excl) == 0) 1201 break; 1202 } 1203 if (async->async_timer != 0) { 1204 (void) untimeout(async->async_timer); 1205 async->async_timer = 0; 1206 } 1207 1208 nodrain: 1209 mutex_enter(asy->asy_excl_hi); 1210 1211 /* turn off the loopback mode */ 1212 if ((async->async_dev != rconsdev) && 1213 (async->async_dev != kbddev) && 1214 (async->async_dev != stdindev)) { 1215 OUTB(MCR, INB(MCR) & ~ ASY_LOOP); 1216 } 1217 1218 async->async_ocnt = 0; 1219 if (async->async_xmitblk != NULL) 1220 freeb(async->async_xmitblk); 1221 async->async_xmitblk = NULL; 1222 1223 /* 1224 * If the "nohupcl" OBP property is set for this device, do 1225 * not turn off DTR and RTS no matter what. Otherwise, if the 1226 * line has HUPCL set or is incompletely opened, turn off DTR 1227 * and RTS to fix the modem line. 1228 */ 1229 if (!nohupcl && ((async->async_ttycommon.t_cflag & HUPCL) || 1230 (async->async_flags & ASYNC_WOPEN))) { 1231 /* turn off DTR, RTS but NOT interrupt to 386 */ 1232 OUTB(MCR, OUT2); 1233 mutex_exit(asy->asy_excl_hi); 1234 /* 1235 * Don't let an interrupt in the middle of close 1236 * bounce us back to the top; just continue closing 1237 * as if nothing had happened. 1238 */ 1239 if (cv_wait_sig(&lbolt_cv, asy->asy_excl) == 0) 1240 goto out; 1241 mutex_enter(asy->asy_excl_hi); 1242 } 1243 1244 /* 1245 * If nobody's using it now, turn off receiver interrupts. 1246 */ 1247 if ((async->async_flags & (ASYNC_WOPEN|ASYNC_ISOPEN)) == 0) { 1248 icr = INB(ICR); 1249 OUTB(ICR, (icr & ~RIEN)); 1250 } 1251 mutex_exit(asy->asy_excl_hi); 1252 out: 1253 /* 1254 * Clear out device state. 1255 */ 1256 async->async_flags = 0; 1257 ttycommon_close(&async->async_ttycommon); 1258 cv_broadcast(&async->async_flags_cv); 1259 1260 /* 1261 * Clear ASY_DOINGSOFT and ASY_NEEDSOFT in case we were in 1262 * async_softint or an interrupt was pending when the process 1263 * using the port exited. 1264 */ 1265 asy->asy_flags &= ~ASY_DOINGSOFT & ~ASY_NEEDSOFT; 1266 1267 /* 1268 * Cancel outstanding "bufcall" request. 1269 */ 1270 if (async->async_wbufcid) { 1271 unbufcall(async->async_wbufcid); 1272 async->async_wbufcid = 0; 1273 } 1274 1275 /* 1276 * If inperim is true, it means the port is closing while there's 1277 * a pending software interrupt. async_flags has been zeroed out, 1278 * so this instance of leaveq() needs to be called before we call 1279 * qprocsoff() to disable services on the q. If inperim is false, 1280 * leaveq() has already been called or we're not in a perimeter. 1281 */ 1282 if (asy->inperim == B_TRUE) { 1283 asy->inperim = B_FALSE; 1284 mutex_exit(asy->asy_excl); 1285 leaveq(q); 1286 } else { 1287 mutex_exit(asy->asy_excl); 1288 } 1289 1290 /* Note that qprocsoff can't be done until after interrupts are off */ 1291 qprocsoff(q); 1292 q->q_ptr = WR(q)->q_ptr = NULL; 1293 async->async_ttycommon.t_readq = NULL; 1294 async->async_ttycommon.t_writeq = NULL; 1295 1296 return (0); 1297 } 1298 1299 /* 1300 * Checks to see if the serial port is still transmitting 1301 * characters. It returns true when there are characters 1302 * queued to transmit, when the holding register contains 1303 * a byte, or when the shifting register still contains 1304 * data to send. 1305 * 1306 */ 1307 static boolean_t 1308 asy_isbusy(struct asycom *asy) 1309 { 1310 struct asyncline *async; 1311 1312 #ifdef DEBUG 1313 if (asydebug & ASY_DEBUG_EOT) 1314 printf("isbusy\n"); 1315 #endif 1316 async = (struct asyncline *)asy->asy_priv; 1317 ASSERT(mutex_owned(asy->asy_excl)); 1318 ASSERT(mutex_owned(asy->asy_excl_hi)); 1319 return ((async->async_ocnt > 0) || 1320 ((INB(LSR) & XSRE) == 0)); 1321 } 1322 1323 /* 1324 * Program the ASY port. Most of the async operation is based on the values 1325 * of 'c_iflag' and 'c_cflag'. 1326 */ 1327 static int 1328 asy_program(struct asycom *asy, int mode) 1329 { 1330 struct asyncline *async; 1331 int baudrate, c_flag; 1332 int icr, lcr; 1333 int ocflags; 1334 int error = 0; 1335 1336 ASSERT(mutex_owned(asy->asy_excl)); 1337 ASSERT(mutex_owned(asy->asy_excl_hi)); 1338 1339 #ifdef DEBUG 1340 if (asydebug & ASY_DEBUG_PROCS) 1341 printf("program\n"); 1342 #endif 1343 async = (struct asyncline *)asy->asy_priv; 1344 1345 baudrate = async->async_ttycommon.t_cflag & CBAUD; 1346 if (async->async_ttycommon.t_cflag & CBAUDEXT) 1347 baudrate += 16; 1348 1349 /* Limit baudrate so it can't index out of baudtable */ 1350 if (baudrate >= N_SU_SPEEDS) baudrate = B9600; 1351 1352 /* 1353 * If baud rate requested is greater than the speed cap 1354 * or is an unsupported baud rate then reset t_cflag baud 1355 * to the last valid baud rate. If this is the initial 1356 * pass through asy_program then set it to 9600. 1357 */ 1358 if (((baudrate > 0) && (asyspdtab[baudrate] == 0)) || 1359 (baudtable[baudrate] > asy->asy_speed_cap)) { 1360 async->async_ttycommon.t_cflag &= ~CBAUD & ~CBAUDEXT & 1361 ~CIBAUD & ~CIBAUDEXT; 1362 if (mode == ASY_INIT) { 1363 async->async_ttycommon.t_cflag |= B9600; 1364 async->async_ttycommon.t_cflag |= B9600 << IBSHIFT; 1365 baudrate = B9600; 1366 } else { 1367 async->async_ttycommon.t_cflag |= 1368 (asy->asy_ocflags & (CBAUD | CBAUDEXT | 1369 CIBAUD | CIBAUDEXT)); 1370 error = EINVAL; 1371 goto end; 1372 } 1373 } 1374 1375 /* 1376 * If CIBAUD and CIBAUDEXT are zero then we should set them to 1377 * the equivelant output baud bits. Else, if CIBAUD and CIBAUDEXT 1378 * don't match CBAUD and CBAUDEXT respectively then we should 1379 * notify the requestor that we do not support split speeds. 1380 */ 1381 if ((async->async_ttycommon.t_cflag & (CIBAUD|CIBAUDEXT)) == 0) { 1382 async->async_ttycommon.t_cflag |= 1383 (async->async_ttycommon.t_cflag & CBAUD) << IBSHIFT; 1384 if (async->async_ttycommon.t_cflag & CBAUDEXT) 1385 async->async_ttycommon.t_cflag |= CIBAUDEXT; 1386 } else { 1387 if ((((async->async_ttycommon.t_cflag & CBAUD) << IBSHIFT) != 1388 (async->async_ttycommon.t_cflag & CIBAUD)) || 1389 !(((async->async_ttycommon.t_cflag & (CBAUDEXT | 1390 CIBAUDEXT)) == (CBAUDEXT | CIBAUDEXT)) || 1391 ((async->async_ttycommon.t_cflag & (CBAUDEXT | 1392 CIBAUDEXT)) == 0))) { 1393 async->async_ttycommon.t_cflag &= ~CBAUD & ~CBAUDEXT & 1394 ~CIBAUD & ~CIBAUDEXT; 1395 async->async_ttycommon.t_cflag |= 1396 (asy->asy_ocflags & (CBAUD | CBAUDEXT | 1397 CIBAUD | CIBAUDEXT)); 1398 error = EINVAL; 1399 goto end; 1400 } 1401 } 1402 1403 c_flag = async->async_ttycommon.t_cflag & 1404 (CLOCAL | CREAD | CSTOPB | CSIZE | PARENB | PARODD | CBAUD | 1405 CBAUDEXT | CIBAUD | CIBAUDEXT); 1406 1407 /* disable interrupts, see EXAR bug */ 1408 if (asy->asy_hwtype == ASY16C554D) 1409 OUTB(SPR, 0); 1410 OUTB(ICR, 0); 1411 1412 ocflags = asy->asy_ocflags; 1413 1414 /* flush/reset the status registers */ 1415 if (mode == ASY_INIT) { 1416 (void) INB(DAT); 1417 (void) INB(ISR); 1418 (void) INB(LSR); 1419 (void) INB(MSR); 1420 } 1421 1422 if (ocflags != (c_flag & ~CLOCAL) || mode == ASY_INIT) { 1423 /* Set line control */ 1424 lcr = INB(LCR); 1425 lcr &= ~(WLS0|WLS1|STB|PEN|EPS); 1426 1427 if (c_flag & CSTOPB) 1428 lcr |= STB; /* 2 stop bits */ 1429 1430 if (c_flag & PARENB) 1431 lcr |= PEN; 1432 1433 if ((c_flag & PARODD) == 0) 1434 lcr |= EPS; 1435 1436 switch (c_flag & CSIZE) { 1437 case CS5: 1438 lcr |= BITS5; 1439 break; 1440 case CS6: 1441 lcr |= BITS6; 1442 break; 1443 case CS7: 1444 lcr |= BITS7; 1445 break; 1446 case CS8: 1447 lcr |= BITS8; 1448 break; 1449 } 1450 1451 /* set the baud rate when the rate is NOT B0 */ 1452 if (baudrate != 0) { 1453 OUTB(LCR, DLAB); 1454 OUTB(DAT, (asyspdtab[baudrate] * 1455 asy->asy_baud_divisor_factor) & 0xff); 1456 OUTB(ICR, ((asyspdtab[baudrate] * 1457 asy->asy_baud_divisor_factor) >> 8) & 0xff); 1458 } 1459 /* set the line control modes */ 1460 OUTB(LCR, lcr); 1461 1462 /* 1463 * if transitioning from CREAD off to CREAD on, 1464 * flush the FIFO buffer if we have one. 1465 */ 1466 if ((ocflags & CREAD) == 0 && (c_flag & CREAD)) { 1467 if (asy->asy_use_fifo == FIFO_ON) { 1468 OUTB(FIFOR, FIFO_ON | FIFODMA | FIFORXFLSH | 1469 (asy->asy_trig_level & 0xff)); 1470 } 1471 } 1472 1473 /* remember the new cflags */ 1474 asy->asy_ocflags = c_flag & ~CLOCAL; 1475 } 1476 1477 /* whether or not CLOCAL is set, modify the modem control lines */ 1478 if (baudrate == 0) 1479 /* B0 has been issued, lower DTR */ 1480 OUTB(MCR, RTS|OUT2); 1481 else 1482 /* raise DTR */ 1483 OUTB(MCR, DTR|RTS|OUT2); 1484 1485 /* 1486 * Call the modem status interrupt handler to check for the carrier 1487 * in case CLOCAL was turned off after the carrier came on. 1488 * (Note: Modem status interrupt is not enabled if CLOCAL is ON.) 1489 */ 1490 async_msint(asy); 1491 1492 /* Set interrupt control */ 1493 if ((c_flag & CLOCAL) && !(async->async_ttycommon.t_cflag & CRTSCTS)) 1494 /* 1495 * direct-wired line ignores DCD, so we don't enable modem 1496 * status interrupts. 1497 */ 1498 icr = (TIEN | SIEN); 1499 else 1500 icr = (TIEN | SIEN | MIEN); 1501 1502 if (c_flag & CREAD) 1503 icr |= RIEN; 1504 1505 OUTB(ICR, icr); 1506 end: 1507 return (error); 1508 } 1509 1510 /* 1511 * Polled mode support -- all functions called with interrupts 1512 * disabled. 1513 */ 1514 1515 static void 1516 asyputchar(cons_polledio_arg_t arg, uchar_t c) 1517 { 1518 struct asycom *asy = (struct asycom *)arg; 1519 1520 /* 1521 * If we see a line feed make sure to also 1522 * put out a carriage return. 1523 */ 1524 if (c == '\n') 1525 asyputchar(arg, '\r'); 1526 1527 while ((INB(LSR) & XHRE) == 0) { 1528 /* wait for the transmission to complete */ 1529 drv_usecwait(10); 1530 } 1531 1532 /* ouput the character */ 1533 OUTB(DAT, c); 1534 } 1535 1536 /* 1537 * Determines if there is a character avaialable for 1538 * reading. 1539 */ 1540 static boolean_t 1541 asyischar(cons_polledio_arg_t arg) 1542 { 1543 struct asycom *asy = (struct asycom *)arg; 1544 return ((INB(LSR) & RCA) != 0); 1545 } 1546 1547 static int 1548 asygetchar(cons_polledio_arg_t arg) 1549 { 1550 struct asycom *asy = (struct asycom *)arg; 1551 1552 /* 1553 * Spin waiting for a character to be 1554 * available to read. 1555 */ 1556 while (!asyischar(arg)) 1557 drv_usecwait(10); 1558 1559 return (INB(DAT)); 1560 } 1561 1562 /* 1563 * Called when machine is transitioning to polled mode 1564 */ 1565 static void 1566 asy_polled_enter(cons_polledio_arg_t arg) 1567 { 1568 struct asycom *asy = (struct asycom *)arg; 1569 1570 mutex_enter(asy->asy_excl); 1571 mutex_enter(asy->asy_excl_hi); 1572 1573 /* 1574 * If this is the first time that asy_polled_enter() 1575 * has been called, during this transition request, 1576 * save the ICR. Clear the software interrupt 1577 * flags since we won't be able to handle these when 1578 * we are in polled mode. 1579 */ 1580 if (!asy->polled_enter) { 1581 asy->polled_enter = B_TRUE; 1582 asy->polled_icr = INB(ICR); 1583 1584 /* Disable HW interrupts */ 1585 if (asy->asy_hwtype == ASY16C554D) 1586 OUTB(SPR, 0); 1587 OUTB(ICR, 0); 1588 1589 asy->asy_flags &= ~ASY_DOINGSOFT & ~ASY_NEEDSOFT; 1590 } 1591 mutex_exit(asy->asy_excl_hi); 1592 mutex_exit(asy->asy_excl); 1593 } 1594 1595 /* 1596 * Called when machine is transitioning from polled mode. 1597 */ 1598 static void 1599 asy_polled_exit(cons_polledio_arg_t arg) 1600 { 1601 struct asycom *asy = (struct asycom *)arg; 1602 1603 mutex_enter(asy->asy_excl); 1604 mutex_enter(asy->asy_excl_hi); 1605 1606 /* Restore the ICR */ 1607 OUTB(ICR, asy->polled_icr); 1608 1609 /* 1610 * We have finished this polled IO transition. 1611 * Set polled_enter to B_FALSE to note this. 1612 */ 1613 asy->polled_enter = B_FALSE; 1614 mutex_exit(asy->asy_excl_hi); 1615 mutex_exit(asy->asy_excl); 1616 } 1617 1618 /* 1619 * asyintr() is the High Level Interrupt Handler. 1620 * 1621 * There are four different interrupt types indexed by ISR register values: 1622 * 0: modem 1623 * 1: Tx holding register is empty, ready for next char 1624 * 2: Rx register now holds a char to be picked up 1625 * 3: error or break on line 1626 * This routine checks the Bit 0 (interrupt-not-pending) to determine if 1627 * the interrupt is from this port. 1628 */ 1629 uint_t 1630 asyintr(caddr_t argasy) 1631 { 1632 struct asycom *asy = (struct asycom *)argasy; 1633 struct asyncline *async; 1634 int ret_status = DDI_INTR_UNCLAIMED; 1635 uchar_t interrupt_id, lsr; 1636 1637 interrupt_id = INB(ISR) & 0x0F; 1638 async = (struct asyncline *)asy->asy_priv; 1639 if ((async == NULL) || 1640 !(async->async_flags & (ASYNC_ISOPEN|ASYNC_WOPEN))) { 1641 if (interrupt_id & NOINTERRUPT) { 1642 return (DDI_INTR_UNCLAIMED); 1643 } else { 1644 lsr = INB(LSR); 1645 if ((lsr & BRKDET) && 1646 ((abort_enable == KIOCABORTENABLE) && 1647 (async->async_dev == rconsdev))) 1648 abort_sequence_enter((char *)NULL); 1649 else { 1650 /* reset line status */ 1651 (void) INB(LSR); 1652 /* discard any data */ 1653 (void) INB(DAT); 1654 /* reset modem status */ 1655 (void) INB(MSR); 1656 return (DDI_INTR_CLAIMED); 1657 } 1658 } 1659 } 1660 /* 1661 * Spurious interrupts happen in this driver 1662 * because of the transmission on serial port not handled 1663 * properly. 1664 * 1665 * The reasons for Spurious interrupts are: 1666 * 1. There is a path in async_nstart which transmits 1667 * characters without going through interrupt services routine 1668 * which causes spurious interrupts to happen. 1669 * 2. In the async_txint more than one character is sent 1670 * in one interrupt service. 1671 * 3. In async_rxint more than one characters are received in 1672 * in one interrupt service. 1673 * 1674 * Hence we have flags to indicate that such scenerio has happened. 1675 * and claim only such interrupts and others we donot claim it 1676 * as it could be a indicator of some hardware problem. 1677 * 1678 */ 1679 if (interrupt_id & NOINTERRUPT) { 1680 mutex_enter(asy->asy_excl_hi); 1681 if ((asy->asy_xmit_count > 1) || 1682 (asy->asy_out_of_band_xmit > 0) || 1683 (asy->asy_rx_count > 1)) { 1684 asy->asy_xmit_count = 0; 1685 asy->asy_out_of_band_xmit = 0; 1686 asy->asy_rx_count = 0; 1687 mutex_exit(asy->asy_excl_hi); 1688 return (DDI_INTR_CLAIMED); 1689 } else { 1690 mutex_exit(asy->asy_excl_hi); 1691 return (DDI_INTR_UNCLAIMED); 1692 } 1693 } 1694 ret_status = DDI_INTR_CLAIMED; 1695 mutex_enter(asy->asy_excl_hi); 1696 if (asy->asy_hwtype == ASY82510) 1697 OUTB(ISR, 0x00); /* set bank 0 */ 1698 1699 #ifdef DEBUG 1700 if (asydebug & ASY_DEBUG_INTR) 1701 prom_printf("l"); 1702 #endif 1703 lsr = INB(LSR); 1704 switch (interrupt_id) { 1705 case RxRDY: 1706 case RSTATUS: 1707 case FFTMOUT: 1708 /* receiver interrupt or receiver errors */ 1709 async_rxint(asy, lsr); 1710 break; 1711 case TxRDY: 1712 /* transmit interrupt */ 1713 async_txint(asy, lsr); 1714 break; 1715 case MSTATUS: 1716 /* modem status interrupt */ 1717 async_msint(asy); 1718 break; 1719 } 1720 mutex_exit(asy->asy_excl_hi); 1721 return (ret_status); 1722 } 1723 1724 /* 1725 * Transmitter interrupt service routine. 1726 * If there is more data to transmit in the current pseudo-DMA block, 1727 * send the next character if output is not stopped or draining. 1728 * Otherwise, queue up a soft interrupt. 1729 * 1730 * XXX - Needs review for HW FIFOs. 1731 */ 1732 static void 1733 async_txint(struct asycom *asy, uchar_t lsr) 1734 { 1735 struct asyncline *async = (struct asyncline *)asy->asy_priv; 1736 int fifo_len; 1737 int xmit_progress; 1738 1739 asycheckflowcontrol_hw(asy); 1740 1741 /* 1742 * If ASYNC_BREAK has been set, return to asyintr()'s context to 1743 * claim the interrupt without performing any action. 1744 */ 1745 if (async->async_flags & ASYNC_BREAK) 1746 return; 1747 1748 fifo_len = asy->asy_fifo_buf; /* with FIFO buffers */ 1749 1750 /* 1751 * Check for flow control and do the needed action. 1752 */ 1753 if (asycheckflowcontrol_sw(asy)) { 1754 return; 1755 } 1756 1757 if (async->async_ocnt > 0 && 1758 !(async->async_flags & (ASYNC_HW_OUT_FLW|ASYNC_STOPPED))) { 1759 xmit_progress = 0; 1760 while (fifo_len > 0 && async->async_ocnt > 0) { 1761 if (lsr & XHRE) { 1762 OUTB(DAT, *async->async_optr++); 1763 fifo_len--; 1764 async->async_ocnt--; 1765 xmit_progress++; 1766 } 1767 /* 1768 * Reading the lsr, (moved reading at the end of 1769 * while loop) as already we have read once at 1770 * the beginning of interrupt service 1771 */ 1772 lsr = INB(LSR); 1773 } 1774 asy->asy_xmit_count = xmit_progress; 1775 if (xmit_progress > 0) 1776 async->async_flags |= ASYNC_PROGRESS; 1777 } 1778 1779 if (fifo_len == 0) { 1780 return; 1781 } 1782 1783 1784 ASYSETSOFT(asy); 1785 } 1786 1787 /* 1788 * Receiver interrupt: RxRDY interrupt, FIFO timeout interrupt or receive 1789 * error interrupt. 1790 * Try to put the character into the circular buffer for this line; if it 1791 * overflows, indicate a circular buffer overrun. If this port is always 1792 * to be serviced immediately, or the character is a STOP character, or 1793 * more than 15 characters have arrived, queue up a soft interrupt to 1794 * drain the circular buffer. 1795 * XXX - needs review for hw FIFOs support. 1796 */ 1797 1798 static void 1799 async_rxint(struct asycom *asy, uchar_t lsr) 1800 { 1801 struct asyncline *async = (struct asyncline *)asy->asy_priv; 1802 uchar_t c = 0; 1803 uint_t s = 0, needsoft = 0; 1804 register tty_common_t *tp; 1805 1806 tp = &async->async_ttycommon; 1807 if (!(tp->t_cflag & CREAD)) { 1808 if (lsr & (RCA|PARERR|FRMERR|BRKDET|OVRRUN)) { 1809 (void) (INB(DAT) & 0xff); 1810 } 1811 return; /* line is not open for read? */ 1812 } 1813 asy->asy_rx_count = 0; 1814 while (lsr & (RCA|PARERR|FRMERR|BRKDET|OVRRUN)) { 1815 c = 0; 1816 s = 0; 1817 asy->asy_rx_count++; 1818 if (lsr & RCA) { 1819 c = INB(DAT) & 0xff; 1820 /* 1821 * Even a single character is received 1822 * we need Soft interrupt to pass it to 1823 * higher layers. 1824 */ 1825 needsoft = 1; 1826 } 1827 1828 /* Check for character break sequence */ 1829 if ((abort_enable == KIOCABORTALTERNATE) && 1830 (async->async_dev == rconsdev)) { 1831 if (abort_charseq_recognize(c)) 1832 abort_sequence_enter((char *)NULL); 1833 } 1834 1835 /* Handle framing errors */ 1836 if (lsr & (PARERR|FRMERR|BRKDET|OVRRUN)) { 1837 if (lsr & PARERR) { 1838 if (tp->t_iflag & INPCK) /* parity enabled */ 1839 s |= PERROR; 1840 } 1841 if (lsr & (FRMERR|BRKDET)) 1842 s |= FRERROR; 1843 if (lsr & OVRRUN) { 1844 async->async_hw_overrun = 1; 1845 s |= OVERRUN; 1846 } 1847 } 1848 1849 if (s == 0) 1850 if ((tp->t_iflag & PARMRK) && 1851 !(tp->t_iflag & (IGNPAR|ISTRIP)) && 1852 (c == 0377)) 1853 if (RING_POK(async, 2)) { 1854 RING_PUT(async, 0377); 1855 RING_PUT(async, c); 1856 } else 1857 async->async_sw_overrun = 1; 1858 else 1859 if (RING_POK(async, 1)) 1860 RING_PUT(async, c); 1861 else 1862 async->async_sw_overrun = 1; 1863 else 1864 if (s & FRERROR) { /* Handle framing errors */ 1865 if (c == 0) { 1866 /* Look for break on kbd, stdin, or rconsdev */ 1867 if ((async->async_dev == kbddev) || 1868 ((async->async_dev == rconsdev) || 1869 (async->async_dev == stdindev)) && 1870 (abort_enable != 1871 KIOCABORTALTERNATE)) 1872 abort_sequence_enter((char *)0); 1873 else 1874 async->async_break++; 1875 } else { 1876 if (RING_POK(async, 1)) 1877 RING_MARK(async, c, s); 1878 else 1879 async->async_sw_overrun = 1; 1880 } 1881 } else { /* Parity errors handled by ldterm */ 1882 if (RING_POK(async, 1)) 1883 RING_MARK(async, c, s); 1884 else 1885 async->async_sw_overrun = 1; 1886 } 1887 lsr = INB(LSR); 1888 if (asy->asy_rx_count > 16) break; 1889 } 1890 /* Check whether there is a request for hw/sw inbound/input flow ctrl */ 1891 if ((async->async_ttycommon.t_cflag & CRTSXOFF) || 1892 (async->async_ttycommon.t_iflag & IXOFF)) 1893 if ((int)(RING_CNT(async)) > (RINGSIZE * 3)/4) { 1894 #ifdef DEBUG 1895 if (asydebug & ASY_DEBUG_HFLOW) 1896 printf("asy%d: hardware flow stop input.\n", 1897 UNIT(async->async_dev)); 1898 #endif 1899 async->async_flags |= ASYNC_HW_IN_FLOW; 1900 async->async_flowc = async->async_stopc; 1901 async->async_ringbuf_overflow = 1; 1902 } 1903 1904 if ((async->async_flags & ASYNC_SERVICEIMM) || needsoft || 1905 (RING_FRAC(async)) || (async->async_polltid == 0)) 1906 ASYSETSOFT(asy); /* need a soft interrupt */ 1907 } 1908 1909 /* 1910 * Interrupt on port: handle PPS event. This function is only called 1911 * for a port on which PPS event handling has been enabled. 1912 */ 1913 static void 1914 asy_ppsevent(struct asycom *asy, int msr) 1915 { 1916 if (asy->asy_flags & ASY_PPS_EDGE) { 1917 /* Have seen leading edge, now look for and record drop */ 1918 if ((msr & DCD) == 0) 1919 asy->asy_flags &= ~ASY_PPS_EDGE; 1920 /* 1921 * Waiting for leading edge, look for rise; stamp event and 1922 * calibrate kernel clock. 1923 */ 1924 } else if (msr & DCD) { 1925 /* 1926 * This code captures a timestamp at the designated 1927 * transition of the PPS signal (DCD asserted). The 1928 * code provides a pointer to the timestamp, as well 1929 * as the hardware counter value at the capture. 1930 * 1931 * Note: the kernel has nano based time values while 1932 * NTP requires micro based, an in-line fast algorithm 1933 * to convert nsec to usec is used here -- see hrt2ts() 1934 * in common/os/timers.c for a full description. 1935 */ 1936 struct timeval *tvp = &asy_ppsev.tv; 1937 timestruc_t ts; 1938 long nsec, usec; 1939 1940 asy->asy_flags |= ASY_PPS_EDGE; 1941 gethrestime(&ts); 1942 nsec = ts.tv_nsec; 1943 usec = nsec + (nsec >> 2); 1944 usec = nsec + (usec >> 1); 1945 usec = nsec + (usec >> 2); 1946 usec = nsec + (usec >> 4); 1947 usec = nsec - (usec >> 3); 1948 usec = nsec + (usec >> 2); 1949 usec = nsec + (usec >> 3); 1950 usec = nsec + (usec >> 4); 1951 usec = nsec + (usec >> 1); 1952 usec = nsec + (usec >> 6); 1953 tvp->tv_usec = usec >> 10; 1954 tvp->tv_sec = ts.tv_sec; 1955 1956 ++asy_ppsev.serial; 1957 1958 /* 1959 * Because the kernel keeps a high-resolution time, 1960 * pass the current highres timestamp in tvp and zero 1961 * in usec. 1962 */ 1963 ddi_hardpps(tvp, 0); 1964 } 1965 } 1966 1967 /* 1968 * Modem status interrupt. 1969 * 1970 * (Note: It is assumed that the MSR hasn't been read by asyintr().) 1971 */ 1972 1973 static void 1974 async_msint(struct asycom *asy) 1975 { 1976 struct asyncline *async = (struct asyncline *)asy->asy_priv; 1977 int msr; 1978 1979 msr = INB(MSR); /* this resets the interrupt */ 1980 asy->asy_cached_msr = msr; 1981 #ifdef DEBUG 1982 if (asydebug & ASY_DEBUG_STATE) { 1983 printf(" transition: %3s %3s %3s %3s\n" 1984 "current state: %3s %3s %3s %3s\n", 1985 (msr & DCTS) ? "CTS" : " ", 1986 (msr & DDSR) ? "DSR" : " ", 1987 (msr & DRI) ? "RI " : " ", 1988 (msr & DDCD) ? "DCD" : " ", 1989 (msr & CTS) ? "CTS" : " ", 1990 (msr & DSR) ? "DSR" : " ", 1991 (msr & RI) ? "RI " : " ", 1992 (msr & DCD) ? "DCD" : " "); 1993 } 1994 #endif 1995 if (async->async_ttycommon.t_cflag & CRTSCTS && !(msr & CTS)) { 1996 #ifdef DEBUG 1997 if (asydebug & ASY_DEBUG_HFLOW) 1998 printf("asy%d: hflow start\n", 1999 UNIT(async->async_dev)); 2000 #endif 2001 async->async_flags |= ASYNC_HW_OUT_FLW; 2002 } 2003 if (asy->asy_hwtype == ASY82510) 2004 OUTB(MSR, (msr & 0xF0)); 2005 2006 /* Handle PPS event */ 2007 if (asy->asy_flags & ASY_PPS) 2008 asy_ppsevent(asy, msr); 2009 2010 async->async_ext++; 2011 ASYSETSOFT(asy); 2012 } 2013 2014 /* 2015 * Handle a second-stage interrupt. 2016 */ 2017 uint_t 2018 asysoftintr(caddr_t intarg) 2019 { 2020 struct asycom *asy = (struct asycom *)intarg; 2021 struct asyncline *async; 2022 int rv; 2023 int cc; 2024 /* 2025 * Test and clear soft interrupt. 2026 */ 2027 mutex_enter(asy->asy_soft_lock); 2028 #ifdef DEBUG 2029 if (asydebug & ASY_DEBUG_PROCS) 2030 printf("softintr\n"); 2031 #endif 2032 rv = asy->asysoftpend; 2033 if (rv != 0) 2034 asy->asysoftpend = 0; 2035 mutex_exit(asy->asy_soft_lock); 2036 2037 if (rv) { 2038 if (asy->asy_priv == NULL) 2039 return (rv); 2040 async = (struct asyncline *)asy->asy_priv; 2041 mutex_enter(asy->asy_excl_hi); 2042 if (asy->asy_flags & ASY_NEEDSOFT) { 2043 asy->asy_flags &= ~ASY_NEEDSOFT; 2044 mutex_exit(asy->asy_excl_hi); 2045 (void) async_softint(asy); 2046 mutex_enter(asy->asy_excl_hi); 2047 } 2048 /* 2049 * There are some instances where the softintr is not 2050 * scheduled and hence not called. It so happened that makes 2051 * the last few characters to be stuck in ringbuffer. 2052 * Hence, call once again the handler so that the last few 2053 * characters are cleared. 2054 */ 2055 cc = RING_CNT(async); 2056 mutex_exit(asy->asy_excl_hi); 2057 if (cc > 0) { 2058 (void) async_softint(asy); 2059 } 2060 } 2061 return (rv); 2062 } 2063 2064 /* 2065 * Handle a software interrupt. 2066 */ 2067 static int 2068 async_softint(struct asycom *asy) 2069 { 2070 struct asyncline *async = (struct asyncline *)asy->asy_priv; 2071 uint_t cc; 2072 mblk_t *bp; 2073 queue_t *q; 2074 uchar_t val; 2075 uchar_t c; 2076 tty_common_t *tp; 2077 2078 #ifdef DEBUG 2079 if (asydebug & ASY_DEBUG_PROCS) 2080 printf("process\n"); 2081 #endif 2082 mutex_enter(asy->asy_excl); 2083 if (asy->asy_flags & ASY_DOINGSOFT) { 2084 mutex_exit(asy->asy_excl); 2085 return (0); 2086 } 2087 tp = &async->async_ttycommon; 2088 q = tp->t_readq; 2089 if (q != NULL) { 2090 mutex_exit(asy->asy_excl); 2091 enterq(q); 2092 mutex_enter(asy->asy_excl); 2093 } 2094 mutex_enter(asy->asy_excl_hi); 2095 asy->asy_flags |= ASY_DOINGSOFT; 2096 2097 if (INB(ICR) & MIEN) 2098 val = asy->asy_cached_msr & 0xFF; 2099 else 2100 val = INB(MSR) & 0xFF; 2101 2102 if (async->async_ttycommon.t_cflag & CRTSCTS) { 2103 if ((val & CTS) && (async->async_flags & ASYNC_HW_OUT_FLW)) { 2104 #ifdef DEBUG 2105 if (asydebug & ASY_DEBUG_HFLOW) 2106 printf("asy%d: hflow start\n", 2107 UNIT(async->async_dev)); 2108 #endif 2109 async->async_flags &= ~ASYNC_HW_OUT_FLW; 2110 mutex_exit(asy->asy_excl_hi); 2111 if (async->async_ocnt > 0) { 2112 mutex_enter(asy->asy_excl_hi); 2113 async_resume(async); 2114 mutex_exit(asy->asy_excl_hi); 2115 } else { 2116 async_start(async); 2117 } 2118 mutex_enter(asy->asy_excl_hi); 2119 } 2120 } 2121 if (async->async_ext) { 2122 async->async_ext = 0; 2123 /* check for carrier up */ 2124 if ((val & DCD) || (tp->t_flags & TS_SOFTCAR)) { 2125 /* carrier present */ 2126 if ((async->async_flags & ASYNC_CARR_ON) == 0) { 2127 async->async_flags |= ASYNC_CARR_ON; 2128 mutex_exit(asy->asy_excl_hi); 2129 mutex_exit(asy->asy_excl); 2130 if (async->async_flags & ASYNC_ISOPEN) 2131 (void) putctl(q, M_UNHANGUP); 2132 cv_broadcast(&async->async_flags_cv); 2133 mutex_enter(asy->asy_excl); 2134 mutex_enter(asy->asy_excl_hi); 2135 } 2136 } else { 2137 if ((async->async_flags & ASYNC_CARR_ON) && 2138 !(tp->t_cflag & CLOCAL)) { 2139 int flushflag; 2140 2141 /* 2142 * Carrier went away. 2143 * Drop DTR, abort any output in 2144 * progress, indicate that output is 2145 * not stopped, and send a hangup 2146 * notification upstream. 2147 * 2148 * If we're in the midst of close, then flush 2149 * everything. Don't leave stale ioctls lying 2150 * about. 2151 */ 2152 val = INB(MCR); 2153 OUTB(MCR, (val & ~DTR)); 2154 flushflag = (async->async_flags & 2155 ASYNC_CLOSING) ? FLUSHALL : FLUSHDATA; 2156 flushq(tp->t_writeq, flushflag); 2157 if (async->async_xmitblk != NULL) { 2158 freeb(async->async_xmitblk); 2159 async->async_xmitblk = NULL; 2160 } 2161 if (async->async_flags & ASYNC_BUSY) { 2162 async->async_ocnt = 0; 2163 async->async_flags &= ~ASYNC_BUSY; 2164 } 2165 async->async_flags &= ~ASYNC_STOPPED; 2166 if (async->async_flags & ASYNC_ISOPEN) { 2167 mutex_exit(asy->asy_excl_hi); 2168 mutex_exit(asy->asy_excl); 2169 (void) putctl(q, M_HANGUP); 2170 mutex_enter(asy->asy_excl); 2171 mutex_enter(asy->asy_excl_hi); 2172 } 2173 async->async_flags &= ~ASYNC_CARR_ON; 2174 mutex_exit(asy->asy_excl_hi); 2175 cv_broadcast(&async->async_flags_cv); 2176 mutex_enter(asy->asy_excl_hi); 2177 } 2178 } 2179 } 2180 2181 /* 2182 * If data has been added to the circular buffer, remove 2183 * it from the buffer, and send it up the stream if there's 2184 * somebody listening. Try to do it 16 bytes at a time. If we 2185 * have more than 16 bytes to move, move 16 byte chunks and 2186 * leave the rest for next time around (maybe it will grow). 2187 */ 2188 if (!(async->async_flags & ASYNC_ISOPEN)) { 2189 RING_INIT(async); 2190 goto rv; 2191 } 2192 if ((cc = RING_CNT(async)) == 0) { 2193 goto rv; 2194 } 2195 mutex_exit(asy->asy_excl_hi); 2196 2197 if (!canput(q)) { 2198 if ((async->async_flags & ASYNC_HW_IN_FLOW) == 0) { 2199 #ifdef DEBUG 2200 if (!(asydebug & ASY_DEBUG_HFLOW)) { 2201 printf("asy%d: hflow stop input.\n", 2202 UNIT(async->async_dev)); 2203 if (canputnext(q)) 2204 printf("asy%d: next queue is " 2205 "ready\n", 2206 UNIT(async->async_dev)); 2207 } 2208 #endif 2209 mutex_enter(asy->asy_excl_hi); 2210 async->async_flags |= ASYNC_HW_IN_FLOW; 2211 async->async_flowc = async->async_stopc; 2212 } else mutex_enter(asy->asy_excl_hi); 2213 goto rv; 2214 } 2215 2216 if (async->async_ringbuf_overflow) { 2217 if ((async->async_flags & ASYNC_HW_IN_FLOW) && 2218 ((int)(RING_CNT(async)) < (RINGSIZE/4))) { 2219 #ifdef DEBUG 2220 if (asydebug & ASY_DEBUG_HFLOW) 2221 printf("asy%d: hflow start input.\n", 2222 UNIT(async->async_dev)); 2223 #endif 2224 mutex_enter(asy->asy_excl_hi); 2225 async->async_flags &= ~ASYNC_HW_IN_FLOW; 2226 async->async_flowc = async->async_startc; 2227 async->async_ringbuf_overflow = 0; 2228 goto rv; 2229 } 2230 } 2231 #ifdef DEBUG 2232 if (asydebug & ASY_DEBUG_INPUT) 2233 printf("asy%d: %d char(s) in queue.\n", 2234 UNIT(async->async_dev), cc); 2235 #endif 2236 /* 2237 * Before you pull the characters from the RING BUF 2238 * Check whether you can put into the queue again 2239 */ 2240 if ((!canputnext(q)) || (!canput(q))) { 2241 mutex_enter(asy->asy_excl_hi); 2242 if ((async->async_flags & ASYNC_HW_IN_FLOW) == 0) { 2243 async->async_flags |= ASYNC_HW_IN_FLOW; 2244 async->async_flowc = async->async_stopc; 2245 async->async_queue_full = 1; 2246 } 2247 goto rv; 2248 } 2249 mutex_enter(asy->asy_excl_hi); 2250 if (async->async_queue_full) { 2251 /* 2252 * Last time the Stream queue didnot allow 2253 * now it allows so, relax, the flow control 2254 */ 2255 if (async->async_flags & ASYNC_HW_IN_FLOW) { 2256 async->async_flags &= ~ASYNC_HW_IN_FLOW; 2257 async->async_queue_full = 0; 2258 async->async_flowc = async->async_startc; 2259 goto rv; 2260 } else 2261 async->async_queue_full = 0; 2262 } 2263 mutex_exit(asy->asy_excl_hi); 2264 if (!(bp = allocb(cc, BPRI_MED))) { 2265 ttycommon_qfull(&async->async_ttycommon, q); 2266 mutex_enter(asy->asy_excl_hi); 2267 goto rv; 2268 } 2269 mutex_enter(asy->asy_excl_hi); 2270 do { 2271 if (RING_ERR(async, S_ERRORS)) { 2272 RING_UNMARK(async); 2273 c = RING_GET(async); 2274 break; 2275 } else { 2276 *bp->b_wptr++ = RING_GET(async); 2277 } 2278 } while (--cc); 2279 2280 mutex_exit(asy->asy_excl_hi); 2281 mutex_exit(asy->asy_excl); 2282 if (bp->b_wptr > bp->b_rptr) { 2283 if (!canputnext(q)) { 2284 if (!canput(q)) { 2285 /* 2286 * Even after taking all precautions that 2287 * Still we are unable to queue, then we 2288 * cannot do anything, just drop the block 2289 */ 2290 cmn_err(CE_NOTE, 2291 "su%d: local queue full\n", 2292 UNIT(async->async_dev)); 2293 freemsg(bp); 2294 mutex_enter(asy->asy_excl_hi); 2295 if ((async->async_flags & 2296 ASYNC_HW_IN_FLOW) == 0) { 2297 async->async_flags |= 2298 ASYNC_HW_IN_FLOW; 2299 async->async_flowc = 2300 async->async_stopc; 2301 async->async_queue_full = 1; 2302 } 2303 mutex_exit(asy->asy_excl_hi); 2304 } else { 2305 (void) putq(q, bp); 2306 } 2307 } else { 2308 putnext(q, bp); 2309 } 2310 } else { 2311 freemsg(bp); 2312 } 2313 /* 2314 * If we have a parity error, then send 2315 * up an M_BREAK with the "bad" 2316 * character as an argument. Let ldterm 2317 * figure out what to do with the error. 2318 */ 2319 if (cc) 2320 (void) putctl1(q, M_BREAK, c); 2321 mutex_enter(asy->asy_excl); 2322 mutex_enter(asy->asy_excl_hi); 2323 rv: 2324 /* 2325 * If a transmission has finished, indicate that it's finished, 2326 * and start that line up again. 2327 */ 2328 if (async->async_break) { 2329 async->async_break = 0; 2330 if (async->async_flags & ASYNC_ISOPEN) { 2331 mutex_exit(asy->asy_excl_hi); 2332 mutex_exit(asy->asy_excl); 2333 (void) putctl(q, M_BREAK); 2334 mutex_enter(asy->asy_excl); 2335 mutex_enter(asy->asy_excl_hi); 2336 } 2337 } 2338 if ((async->async_ocnt <= 0 && (async->async_flags & ASYNC_BUSY)) || 2339 (async->async_flowc != '\0')) { 2340 async->async_flags &= ~ASYNC_BUSY; 2341 mutex_exit(asy->asy_excl_hi); 2342 if (async->async_xmitblk) 2343 freeb(async->async_xmitblk); 2344 async->async_xmitblk = NULL; 2345 if (async->async_flags & ASYNC_ISOPEN) { 2346 asy->inperim = B_TRUE; 2347 mutex_exit(asy->asy_excl); 2348 enterq(async->async_ttycommon.t_writeq); 2349 mutex_enter(asy->asy_excl); 2350 } 2351 async_start(async); 2352 /* 2353 * We need to check for inperim and ISOPEN due to 2354 * multi-threading implications; it's possible to close the 2355 * port and nullify async_flags while completing the software 2356 * interrupt. If the port is closed, leaveq() will have already 2357 * been called. We don't want to call it twice. 2358 */ 2359 if ((asy->inperim) && (async->async_flags & ASYNC_ISOPEN)) { 2360 mutex_exit(asy->asy_excl); 2361 leaveq(async->async_ttycommon.t_writeq); 2362 mutex_enter(asy->asy_excl); 2363 asy->inperim = B_FALSE; 2364 } 2365 if (!(async->async_flags & ASYNC_BUSY)) 2366 cv_broadcast(&async->async_flags_cv); 2367 mutex_enter(asy->asy_excl_hi); 2368 } 2369 /* 2370 * A note about these overrun bits: all they do is *tell* someone 2371 * about an error- They do not track multiple errors. In fact, 2372 * you could consider them latched register bits if you like. 2373 * We are only interested in printing the error message once for 2374 * any cluster of overrun errrors. 2375 */ 2376 if (async->async_hw_overrun) { 2377 if (async->async_flags & ASYNC_ISOPEN) { 2378 if (su_log > 0) { 2379 mutex_exit(asy->asy_excl_hi); 2380 mutex_exit(asy->asy_excl); 2381 cmn_err(CE_NOTE, "su%d: silo overflow\n", 2382 UNIT(async->async_dev)); 2383 mutex_enter(asy->asy_excl); 2384 mutex_enter(asy->asy_excl_hi); 2385 } 2386 INC64_KSTAT(asy, siloover); 2387 } 2388 async->async_hw_overrun = 0; 2389 } 2390 if (async->async_sw_overrun) { 2391 if (async->async_flags & ASYNC_ISOPEN) { 2392 if (su_log > 0) { 2393 mutex_exit(asy->asy_excl_hi); 2394 mutex_exit(asy->asy_excl); 2395 cmn_err(CE_NOTE, "su%d: ring buffer overflow\n", 2396 UNIT(async->async_dev)); 2397 mutex_enter(asy->asy_excl); 2398 mutex_enter(asy->asy_excl_hi); 2399 } 2400 INC64_KSTAT(asy, ringover); 2401 } 2402 async->async_sw_overrun = 0; 2403 } 2404 asy->asy_flags &= ~ASY_DOINGSOFT; 2405 mutex_exit(asy->asy_excl_hi); 2406 mutex_exit(asy->asy_excl); 2407 if (q != NULL) 2408 leaveq(q); 2409 return (0); 2410 } 2411 2412 /* 2413 * Restart output on a line after a delay or break timer expired. 2414 */ 2415 static void 2416 async_restart(void *arg) 2417 { 2418 struct asyncline *async = arg; 2419 struct asycom *asy = async->async_common; 2420 queue_t *q; 2421 uchar_t lcr; 2422 2423 /* 2424 * If break timer expired, turn off the break bit. 2425 */ 2426 #ifdef DEBUG 2427 if (asydebug & ASY_DEBUG_PROCS) 2428 printf("restart\n"); 2429 #endif 2430 mutex_enter(asy->asy_excl); 2431 if (async->async_flags & ASYNC_BREAK) { 2432 unsigned int rate; 2433 2434 mutex_enter(asy->asy_excl_hi); 2435 lcr = INB(LCR); 2436 OUTB(LCR, (lcr & ~SETBREAK)); 2437 2438 /* 2439 * Go to sleep for the time it takes for at least one 2440 * stop bit to be received by the device at the other 2441 * end of the line as stated in the RS-232 specification. 2442 * The wait period is equal to: 2443 * 2 clock cycles * (1 MICROSEC / baud rate) 2444 */ 2445 rate = async->async_ttycommon.t_cflag & CBAUD; 2446 if (async->async_ttycommon.t_cflag & CBAUDEXT) 2447 rate += 16; 2448 if (rate >= N_SU_SPEEDS || rate == B0) { 2449 rate = B9600; 2450 } 2451 2452 mutex_exit(asy->asy_excl_hi); 2453 mutex_exit(asy->asy_excl); 2454 drv_usecwait(2 * MICROSEC / baudtable[rate]); 2455 mutex_enter(asy->asy_excl); 2456 } 2457 async->async_flags &= ~(ASYNC_DELAY|ASYNC_BREAK|ASYNC_DRAINING); 2458 if ((q = async->async_ttycommon.t_writeq) != NULL) { 2459 mutex_exit(asy->asy_excl); 2460 enterq(q); 2461 mutex_enter(asy->asy_excl); 2462 } 2463 async_start(async); 2464 mutex_exit(asy->asy_excl); 2465 if (q != NULL) 2466 leaveq(q); 2467 2468 /* cleared break or delay flag; may have made some output progress */ 2469 cv_broadcast(&async->async_flags_cv); 2470 } 2471 2472 static void 2473 async_start(struct asyncline *async) 2474 { 2475 async_nstart(async, 0); 2476 } 2477 2478 /* 2479 * Start output on a line, unless it's busy, frozen, or otherwise. 2480 */ 2481 static void 2482 async_nstart(struct asyncline *async, int mode) 2483 { 2484 register struct asycom *asy = async->async_common; 2485 register int cc; 2486 register queue_t *q; 2487 mblk_t *bp, *nbp; 2488 uchar_t *xmit_addr; 2489 uchar_t val; 2490 int fifo_len = 1; 2491 int xmit_progress; 2492 2493 #ifdef DEBUG 2494 if (asydebug & ASY_DEBUG_PROCS) 2495 printf("start\n"); 2496 #endif 2497 if (asy->asy_use_fifo == FIFO_ON) 2498 fifo_len = asy->asy_fifo_buf; /* with FIFO buffers */ 2499 2500 ASSERT(mutex_owned(asy->asy_excl)); 2501 mutex_enter(asy->asy_excl_hi); 2502 asycheckflowcontrol_hw(asy); 2503 2504 /* 2505 * If the chip is busy (i.e., we're waiting for a break timeout 2506 * to expire, or for the current transmission to finish, or for 2507 * output to finish draining from chip), don't grab anything new. 2508 */ 2509 if (async->async_flags & (ASYNC_BREAK|ASYNC_BUSY|ASYNC_DRAINING)) { 2510 mutex_exit(asy->asy_excl_hi); 2511 #ifdef DEBUG 2512 if (mode && asydebug & ASY_DEBUG_CLOSE) 2513 printf("asy%d: start %s.\n", 2514 UNIT(async->async_dev), 2515 async->async_flags & ASYNC_BREAK 2516 ? "break" : "busy"); 2517 #endif 2518 return; 2519 } 2520 2521 /* 2522 * If we have a flow-control character to transmit, do it now. 2523 */ 2524 if (asycheckflowcontrol_sw(asy)) { 2525 mutex_exit(asy->asy_excl_hi); 2526 return; 2527 } 2528 mutex_exit(asy->asy_excl_hi); 2529 /* 2530 * If we're waiting for a delay timeout to expire, don't grab 2531 * anything new. 2532 */ 2533 if (async->async_flags & ASYNC_DELAY) { 2534 #ifdef DEBUG 2535 if (mode && asydebug & ASY_DEBUG_CLOSE) 2536 printf("asy%d: start ASYNC_DELAY.\n", 2537 UNIT(async->async_dev)); 2538 #endif 2539 return; 2540 } 2541 2542 if ((q = async->async_ttycommon.t_writeq) == NULL) { 2543 #ifdef DEBUG 2544 if (mode && asydebug & ASY_DEBUG_CLOSE) 2545 printf("asy%d: start writeq is null.\n", 2546 UNIT(async->async_dev)); 2547 #endif 2548 return; /* not attached to a stream */ 2549 } 2550 2551 for (;;) { 2552 if ((bp = getq(q)) == NULL) 2553 return; /* no data to transmit */ 2554 2555 /* 2556 * We have a message block to work on. 2557 * Check whether it's a break, a delay, or an ioctl (the latter 2558 * occurs if the ioctl in question was waiting for the output 2559 * to drain). If it's one of those, process it immediately. 2560 */ 2561 switch (bp->b_datap->db_type) { 2562 2563 case M_BREAK: 2564 /* 2565 * Set the break bit, and arrange for "async_restart" 2566 * to be called in 1/4 second; it will turn the 2567 * break bit off, and call "async_start" to grab 2568 * the next message. 2569 */ 2570 mutex_enter(asy->asy_excl_hi); 2571 val = INB(LCR); 2572 OUTB(LCR, (val | SETBREAK)); 2573 mutex_exit(asy->asy_excl_hi); 2574 async->async_flags |= ASYNC_BREAK; 2575 (void) timeout(async_restart, async, hz / 4); 2576 freemsg(bp); 2577 return; /* wait for this to finish */ 2578 2579 case M_DELAY: 2580 /* 2581 * Arrange for "async_restart" to be called when the 2582 * delay expires; it will turn ASYNC_DELAY off, 2583 * and call "async_start" to grab the next message. 2584 */ 2585 (void) timeout(async_restart, async, 2586 (clock_t)(*(unsigned char *)bp->b_rptr + 6)); 2587 async->async_flags |= ASYNC_DELAY; 2588 freemsg(bp); 2589 return; /* wait for this to finish */ 2590 2591 case M_IOCTL: 2592 /* 2593 * This ioctl needs to wait for the output ahead of 2594 * it to drain. Try to do it, and then either 2595 * redo the ioctl at a later time or grab the next 2596 * message after it. 2597 */ 2598 2599 mutex_enter(asy->asy_excl_hi); 2600 if (asy_isbusy(asy)) { 2601 /* 2602 * Get the divisor by calculating the rate 2603 */ 2604 unsigned int rate; 2605 2606 mutex_exit(asy->asy_excl_hi); 2607 rate = async->async_ttycommon.t_cflag & CBAUD; 2608 if (async->async_ttycommon.t_cflag & CBAUDEXT) 2609 rate += 16; 2610 if (rate >= N_SU_SPEEDS || rate == B0) { 2611 rate = B9600; 2612 } 2613 2614 /* 2615 * We need to do a callback as the port will 2616 * be set to drain 2617 */ 2618 async->async_flags |= ASYNC_DRAINING; 2619 2620 /* 2621 * Put the message we just processed back onto 2622 * the end of the queue 2623 */ 2624 if (putq(q, bp) == 0) 2625 freemsg(bp); 2626 2627 /* 2628 * We need to delay until the TSR and THR 2629 * have been exhausted. We base the delay on 2630 * the amount of time it takes to transmit 2631 * 2 chars at the current baud rate in 2632 * microseconds. 2633 * 2634 * Therefore, the wait period is: 2635 * 2636 * (#TSR bits + #THR bits) * 2637 * 1 MICROSEC / baud rate 2638 */ 2639 (void) timeout(async_restart, async, 2640 drv_usectohz(16 * MICROSEC / 2641 baudtable[rate])); 2642 return; 2643 } 2644 mutex_exit(asy->asy_excl_hi); 2645 mutex_exit(asy->asy_excl); 2646 async_ioctl(async, q, bp, B_FALSE); 2647 mutex_enter(asy->asy_excl); 2648 continue; 2649 } 2650 2651 while (bp != NULL && (cc = bp->b_wptr - bp->b_rptr) == 0) { 2652 nbp = bp->b_cont; 2653 freeb(bp); 2654 bp = nbp; 2655 } 2656 if (bp != NULL) 2657 break; 2658 } 2659 2660 /* 2661 * We have data to transmit. If output is stopped, put 2662 * it back and try again later. 2663 */ 2664 if (async->async_flags & (ASYNC_HW_OUT_FLW|ASYNC_STOPPED)) { 2665 #ifdef DEBUG 2666 if (asydebug & ASY_DEBUG_HFLOW && 2667 async->async_flags & ASYNC_HW_OUT_FLW) 2668 printf("asy%d: output hflow in effect.\n", 2669 UNIT(async->async_dev)); 2670 #endif 2671 mutex_exit(asy->asy_excl); 2672 (void) putbq(q, bp); 2673 /* 2674 * We entered the routine owning the lock, we need to 2675 * exit the routine owning the lock. 2676 */ 2677 mutex_enter(asy->asy_excl); 2678 return; 2679 } 2680 2681 async->async_xmitblk = bp; 2682 xmit_addr = bp->b_rptr; 2683 bp = bp->b_cont; 2684 if (bp != NULL) { 2685 mutex_exit(asy->asy_excl); 2686 (void) putbq(q, bp); /* not done with this message yet */ 2687 mutex_enter(asy->asy_excl); 2688 } 2689 2690 /* 2691 * In 5-bit mode, the high order bits are used 2692 * to indicate character sizes less than five, 2693 * so we need to explicitly mask before transmitting 2694 */ 2695 if ((async->async_ttycommon.t_cflag & CSIZE) == CS5) { 2696 register unsigned char *p = xmit_addr; 2697 register int cnt = cc; 2698 2699 while (cnt--) 2700 *p++ &= (unsigned char) 0x1f; 2701 } 2702 2703 /* 2704 * Set up this block for pseudo-DMA. 2705 */ 2706 mutex_enter(asy->asy_excl_hi); 2707 async->async_optr = xmit_addr; 2708 async->async_ocnt = cc; 2709 /* 2710 * If the transmitter is ready, shove some 2711 * characters out. 2712 */ 2713 xmit_progress = 0; 2714 while (fifo_len-- && async->async_ocnt) { 2715 if (INB(LSR) & XHRE) { 2716 OUTB(DAT, *async->async_optr++); 2717 async->async_ocnt--; 2718 xmit_progress++; 2719 } 2720 } 2721 asy->asy_out_of_band_xmit = xmit_progress; 2722 if (xmit_progress > 0) 2723 async->async_flags |= ASYNC_PROGRESS; 2724 async->async_flags |= ASYNC_BUSY; 2725 mutex_exit(asy->asy_excl_hi); 2726 } 2727 2728 /* 2729 * Resume output by poking the transmitter. 2730 */ 2731 static void 2732 async_resume(struct asyncline *async) 2733 { 2734 register struct asycom *asy = async->async_common; 2735 2736 ASSERT(mutex_owned(asy->asy_excl_hi)); 2737 #ifdef DEBUG 2738 if (asydebug & ASY_DEBUG_PROCS) 2739 printf("resume\n"); 2740 #endif 2741 2742 asycheckflowcontrol_hw(asy); 2743 2744 if (INB(LSR) & XHRE) { 2745 if (asycheckflowcontrol_sw(asy)) { 2746 return; 2747 } else if (async->async_ocnt > 0) { 2748 OUTB(DAT, *async->async_optr++); 2749 async->async_ocnt--; 2750 async->async_flags |= ASYNC_PROGRESS; 2751 } 2752 } 2753 } 2754 2755 /* 2756 * Process an "ioctl" message sent down to us. 2757 * Note that we don't need to get any locks until we are ready to access 2758 * the hardware. Nothing we access until then is going to be altered 2759 * outside of the STREAMS framework, so we should be safe. 2760 */ 2761 static void 2762 async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp, boolean_t iswput) 2763 { 2764 register struct asycom *asy = async->async_common; 2765 register tty_common_t *tp = &async->async_ttycommon; 2766 register struct iocblk *iocp; 2767 register unsigned datasize; 2768 size_t ioc_count; 2769 mblk_t *datamp; 2770 int error = 0; 2771 uchar_t val, icr; 2772 #ifdef DEBUG 2773 if (asydebug & ASY_DEBUG_PROCS) 2774 printf("ioctl\n"); 2775 #endif 2776 2777 if (tp->t_iocpending != NULL) { 2778 /* 2779 * We were holding an "ioctl" response pending the 2780 * availability of an "mblk" to hold data to be passed up; 2781 * another "ioctl" came through, which means that "ioctl" 2782 * must have timed out or been aborted. 2783 */ 2784 freemsg(async->async_ttycommon.t_iocpending); 2785 async->async_ttycommon.t_iocpending = NULL; 2786 } 2787 2788 iocp = (struct iocblk *)mp->b_rptr; 2789 2790 /* 2791 * Save off the ioc count in case we need to restore it 2792 * because we are queuing a message block. 2793 */ 2794 ioc_count = iocp->ioc_count; 2795 2796 /* 2797 * For TIOCMGET, TIOCMBIC, TIOCMBIS, TIOCMSET, and PPS, do NOT call 2798 * ttycommon_ioctl() because this function frees up the message block 2799 * (mp->b_cont) that contains the address of the user variable where 2800 * we need to pass back the bit array. 2801 * 2802 * Similarly, ttycommon_ioctl() does not know about CONSOPENPOLLEDIO 2803 * and CONSCLOSEPOLLEDIO, so don't let ttycommon_ioctl() touch them. 2804 */ 2805 if (iocp->ioc_cmd == TIOCMGET || 2806 iocp->ioc_cmd == TIOCMBIC || 2807 iocp->ioc_cmd == TIOCMBIS || 2808 iocp->ioc_cmd == TIOCMSET || 2809 iocp->ioc_cmd == TIOCGPPS || 2810 iocp->ioc_cmd == TIOCSPPS || 2811 iocp->ioc_cmd == TIOCGPPSEV || 2812 iocp->ioc_cmd == CONSOPENPOLLEDIO || 2813 iocp->ioc_cmd == CONSCLOSEPOLLEDIO) 2814 error = -1; /* Do Nothing */ 2815 else 2816 2817 /* 2818 * The only way in which "ttycommon_ioctl" can fail is if the "ioctl" 2819 * requires a response containing data to be returned to the user, 2820 * and no mblk could be allocated for the data. 2821 * No such "ioctl" alters our state. Thus, we always go ahead and 2822 * do any state-changes the "ioctl" calls for. If we couldn't allocate 2823 * the data, "ttycommon_ioctl" has stashed the "ioctl" away safely, so 2824 * we just call "bufcall" to request that we be called back when we 2825 * stand a better chance of allocating the data. 2826 */ 2827 if ((datasize = ttycommon_ioctl(tp, wq, mp, &error)) != 0) { 2828 if (async->async_wbufcid) 2829 unbufcall(async->async_wbufcid); 2830 async->async_wbufcid = bufcall(datasize, BPRI_HI, async_reioctl, 2831 async); 2832 return; 2833 } 2834 2835 mutex_enter(asy->asy_excl); 2836 2837 if (error == 0) { 2838 /* 2839 * "ttycommon_ioctl" did most of the work; we just use the 2840 * data it set up. 2841 */ 2842 switch (iocp->ioc_cmd) { 2843 2844 case TCSETS: 2845 if (!(asy->asy_rsc_console || asy->asy_rsc_control || 2846 asy->asy_lom_console)) { 2847 mutex_enter(asy->asy_excl_hi); 2848 error = asy_program(asy, ASY_NOINIT); 2849 mutex_exit(asy->asy_excl_hi); 2850 } 2851 break; 2852 case TCSETSF: 2853 case TCSETSW: 2854 case TCSETA: 2855 case TCSETAW: 2856 case TCSETAF: 2857 if (!(asy->asy_rsc_console || asy->asy_rsc_control || 2858 asy->asy_lom_console)) { 2859 mutex_enter(asy->asy_excl_hi); 2860 if (iswput && asy_isbusy(asy)) { 2861 /* 2862 * ttycommon_ioctl sets the db_type to 2863 * M_IOCACK and ioc_count to zero 2864 * we need to undo this when we 2865 * queue a control message. This will 2866 * allow the control messages to be 2867 * processed again when the chip 2868 * becomes available. 2869 */ 2870 mp->b_datap->db_type = M_IOCTL; 2871 iocp->ioc_count = ioc_count; 2872 2873 if (putq(wq, mp) == 0) 2874 freemsg(mp); 2875 mutex_exit(asy->asy_excl_hi); 2876 mutex_exit(asy->asy_excl); 2877 return; 2878 } 2879 2880 /* 2881 * TCSETA, TCSETAW, and TCSETAF make use of 2882 * the termio structure and therefore have 2883 * no concept of any speed except what can 2884 * be represented by CBAUD. This is because 2885 * of legacy SVR4 code. Therefore, if we see 2886 * one of the aforementioned IOCTL commands 2887 * we should zero out CBAUDEXT, CIBAUD, and 2888 * CIBAUDEXT as to not break legacy 2889 * functionality. This is because CBAUDEXT, 2890 * CIBAUD, and CIBAUDEXT can't be stored in 2891 * an unsigned short. By zeroing out CBAUDEXT, 2892 * CIBAUD, and CIBAUDEXT in the t_cflag of the 2893 * termios structure asy_program() will set the 2894 * input baud rate to the output baud rate. 2895 */ 2896 if (iocp->ioc_cmd == TCSETA || 2897 iocp->ioc_cmd == TCSETAW || 2898 iocp->ioc_cmd == TCSETAF) 2899 tp->t_cflag &= ~(CIBAUD | 2900 CIBAUDEXT | CBAUDEXT); 2901 2902 error = asy_program(asy, ASY_NOINIT); 2903 mutex_exit(asy->asy_excl_hi); 2904 } 2905 break; 2906 case TIOCSSOFTCAR: 2907 /* Set the driver state appropriately */ 2908 mutex_enter(asy->asy_excl_hi); 2909 if (tp->t_flags & TS_SOFTCAR) 2910 asy->asy_flags |= ASY_IGNORE_CD; 2911 else 2912 asy->asy_flags &= ~ASY_IGNORE_CD; 2913 mutex_exit(asy->asy_excl_hi); 2914 break; 2915 } 2916 } else if (error < 0) { 2917 /* 2918 * "ttycommon_ioctl" didn't do anything; we process it here. 2919 */ 2920 error = 0; 2921 switch (iocp->ioc_cmd) { 2922 2923 case TIOCGPPS: 2924 /* 2925 * Get PPS on/off. 2926 */ 2927 if (mp->b_cont != NULL) 2928 freemsg(mp->b_cont); 2929 2930 mp->b_cont = allocb(sizeof (int), BPRI_HI); 2931 if (mp->b_cont == NULL) { 2932 error = ENOMEM; 2933 break; 2934 } 2935 if (asy->asy_flags & ASY_PPS) 2936 *(int *)mp->b_cont->b_wptr = 1; 2937 else 2938 *(int *)mp->b_cont->b_wptr = 0; 2939 mp->b_cont->b_wptr += sizeof (int); 2940 mp->b_datap->db_type = M_IOCACK; 2941 iocp->ioc_count = sizeof (int); 2942 break; 2943 2944 case TIOCSPPS: 2945 /* 2946 * Set PPS on/off. 2947 */ 2948 error = miocpullup(mp, sizeof (int)); 2949 if (error != 0) 2950 break; 2951 2952 mutex_enter(asy->asy_excl_hi); 2953 if (*(int *)mp->b_cont->b_rptr) 2954 asy->asy_flags |= ASY_PPS; 2955 else 2956 asy->asy_flags &= ~ASY_PPS; 2957 /* Reset edge sense */ 2958 asy->asy_flags &= ~ASY_PPS_EDGE; 2959 mutex_exit(asy->asy_excl_hi); 2960 mp->b_datap->db_type = M_IOCACK; 2961 break; 2962 2963 case TIOCGPPSEV: { 2964 /* 2965 * Get PPS event data. 2966 */ 2967 mblk_t *bp; 2968 void *buf; 2969 #ifdef _SYSCALL32_IMPL 2970 struct ppsclockev32 p32; 2971 #endif 2972 struct ppsclockev ppsclockev; 2973 2974 if (mp->b_cont != NULL) { 2975 freemsg(mp->b_cont); 2976 mp->b_cont = NULL; 2977 } 2978 2979 if ((asy->asy_flags & ASY_PPS) == 0) { 2980 error = ENXIO; 2981 break; 2982 } 2983 2984 /* Protect from incomplete asy_ppsev */ 2985 mutex_enter(asy->asy_excl_hi); 2986 ppsclockev = asy_ppsev; 2987 mutex_exit(asy->asy_excl_hi); 2988 2989 #ifdef _SYSCALL32_IMPL 2990 if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) { 2991 TIMEVAL_TO_TIMEVAL32(&p32.tv, &ppsclockev.tv); 2992 p32.serial = ppsclockev.serial; 2993 buf = &p32; 2994 iocp->ioc_count = sizeof (struct ppsclockev32); 2995 } else 2996 #endif 2997 { 2998 buf = &ppsclockev; 2999 iocp->ioc_count = sizeof (struct ppsclockev); 3000 } 3001 3002 if ((bp = allocb(iocp->ioc_count, BPRI_HI)) == NULL) { 3003 error = ENOMEM; 3004 break; 3005 } 3006 mp->b_cont = bp; 3007 3008 bcopy(buf, bp->b_wptr, iocp->ioc_count); 3009 bp->b_wptr += iocp->ioc_count; 3010 mp->b_datap->db_type = M_IOCACK; 3011 break; 3012 } 3013 3014 case TCSBRK: 3015 error = miocpullup(mp, sizeof (int)); 3016 if (error != 0) 3017 break; 3018 3019 mutex_enter(asy->asy_excl_hi); 3020 if (*(int *)mp->b_cont->b_rptr == 0) { 3021 /* 3022 * Get the divisor by calculating the rate 3023 */ 3024 unsigned int rate, divisor; 3025 rate = async->async_ttycommon.t_cflag & CBAUD; 3026 if (async->async_ttycommon.t_cflag & CBAUDEXT) 3027 rate += 16; 3028 if (rate >= N_SU_SPEEDS) rate = B9600; 3029 divisor = asyspdtab[rate] & 0xfff; 3030 3031 /* 3032 * To ensure that erroneous characters are 3033 * not sent out when the break is set, SB 3034 * recommends three steps: 3035 * 3036 * 1) pad the TSR with 0 bits 3037 * 2) When the TSR is full, set break 3038 * 3) When the TSR has been flushed, unset 3039 * the break when transmission must be 3040 * restored. 3041 * 3042 * We loop until the TSR is empty and then 3043 * set the break. ASYNC_BREAK has been set 3044 * to ensure that no characters are 3045 * transmitted while the TSR is being 3046 * flushed and SOUT is being used for the 3047 * break signal. 3048 * 3049 * The wait period is equal to 3050 * clock / (baud * 16) * 16 * 2. 3051 */ 3052 async->async_flags |= ASYNC_BREAK; 3053 while ((INB(LSR) & XSRE) == 0) { 3054 mutex_exit(asy->asy_excl_hi); 3055 mutex_exit(asy->asy_excl); 3056 drv_usecwait(32*divisor); 3057 mutex_enter(asy->asy_excl); 3058 mutex_enter(asy->asy_excl_hi); 3059 } 3060 3061 /* 3062 * Set the break bit, and arrange for 3063 * "async_restart" to be called in 1/4 second; 3064 * it will turn the break bit off, and call 3065 * "async_start" to grab the next message. 3066 */ 3067 val = INB(LCR); 3068 OUTB(LCR, (val | SETBREAK)); 3069 mutex_exit(asy->asy_excl_hi); 3070 (void) timeout(async_restart, async, hz / 4); 3071 } else { 3072 #ifdef DEBUG 3073 if (asydebug & ASY_DEBUG_CLOSE) 3074 printf("asy%d: wait for flush.\n", 3075 UNIT(async->async_dev)); 3076 #endif 3077 if (iswput && asy_isbusy(asy)) { 3078 if (putq(wq, mp) == 0) 3079 freemsg(mp); 3080 mutex_exit(asy->asy_excl_hi); 3081 mutex_exit(asy->asy_excl); 3082 return; 3083 } 3084 mutex_exit(asy->asy_excl_hi); 3085 #ifdef DEBUG 3086 if (asydebug & ASY_DEBUG_CLOSE) 3087 printf("asy%d: ldterm satisfied.\n", 3088 UNIT(async->async_dev)); 3089 #endif 3090 } 3091 break; 3092 3093 case TIOCSBRK: 3094 mutex_enter(asy->asy_excl_hi); 3095 val = INB(LCR); 3096 OUTB(LCR, (val | SETBREAK)); 3097 mutex_exit(asy->asy_excl_hi); 3098 mutex_exit(asy->asy_excl); 3099 miocack(wq, mp, 0, 0); 3100 return; 3101 3102 case TIOCCBRK: 3103 mutex_enter(asy->asy_excl_hi); 3104 val = INB(LCR); 3105 OUTB(LCR, (val & ~SETBREAK)); 3106 mutex_exit(asy->asy_excl_hi); 3107 mutex_exit(asy->asy_excl); 3108 miocack(wq, mp, 0, 0); 3109 return; 3110 3111 case TIOCMSET: 3112 case TIOCMBIS: 3113 case TIOCMBIC: 3114 if (iocp->ioc_count == TRANSPARENT) 3115 mcopyin(mp, NULL, sizeof (int), NULL); 3116 else { 3117 error = miocpullup(mp, sizeof (int)); 3118 if (error != 0) 3119 break; 3120 3121 mutex_enter(asy->asy_excl_hi); 3122 3123 (void) asymctl(asy, 3124 dmtoasy(*(int *)mp->b_cont->b_rptr), 3125 iocp->ioc_cmd); 3126 3127 mutex_exit(asy->asy_excl_hi); 3128 iocp->ioc_error = 0; 3129 mp->b_datap->db_type = M_IOCACK; 3130 } 3131 break; 3132 3133 case TIOCSILOOP: 3134 mutex_enter(asy->asy_excl_hi); 3135 /* 3136 * If somebody misues this Ioctl when used for 3137 * driving keyboard and mouse indicate not supported 3138 */ 3139 if ((asy->asy_device_type == ASY_KEYBOARD) || 3140 (asy->asy_device_type == ASY_MOUSE)) { 3141 mutex_exit(asy->asy_excl_hi); 3142 error = ENOTTY; 3143 break; 3144 } 3145 3146 /* should not use when we're the console */ 3147 if ((async->async_dev == kbddev) || 3148 (async->async_dev == rconsdev) || 3149 (async->async_dev == stdindev)) { 3150 mutex_exit(asy->asy_excl_hi); 3151 error = EINVAL; 3152 break; 3153 } 3154 3155 val = INB(MCR); 3156 icr = INB(ICR); 3157 /* 3158 * Disable the Modem Status Interrupt 3159 * The reason for disabling is the status of 3160 * modem signal are in the higher 4 bits instead of 3161 * lower four bits when in loopback mode, 3162 * so, donot worry about Modem interrupt when 3163 * you are planning to set 3164 * this in loopback mode until it is cleared by 3165 * another ioctl to get out of the loopback mode 3166 */ 3167 OUTB(ICR, icr & ~ MIEN); 3168 OUTB(MCR, val | ASY_LOOP); 3169 mutex_exit(asy->asy_excl_hi); 3170 iocp->ioc_error = 0; 3171 mp->b_datap->db_type = M_IOCACK; 3172 break; 3173 3174 case TIOCMGET: 3175 datamp = allocb(sizeof (int), BPRI_MED); 3176 if (datamp == NULL) { 3177 error = EAGAIN; 3178 break; 3179 } 3180 3181 mutex_enter(asy->asy_excl_hi); 3182 *(int *)datamp->b_rptr = asymctl(asy, 0, TIOCMGET); 3183 mutex_exit(asy->asy_excl_hi); 3184 3185 if (iocp->ioc_count == TRANSPARENT) { 3186 mcopyout(mp, NULL, sizeof (int), NULL, datamp); 3187 } else { 3188 if (mp->b_cont != NULL) 3189 freemsg(mp->b_cont); 3190 mp->b_cont = datamp; 3191 mp->b_cont->b_wptr += sizeof (int); 3192 mp->b_datap->db_type = M_IOCACK; 3193 iocp->ioc_count = sizeof (int); 3194 } 3195 break; 3196 3197 case CONSOPENPOLLEDIO: 3198 /* 3199 * If we are driving a keyboard there is nothing 3200 * upstream to translate the scan codes. Therefore, 3201 * set the error code to ENOTSUP and NAK the request 3202 */ 3203 if (asy->asy_device_type == ASY_KEYBOARD) { 3204 error = ENOTSUP; 3205 break; 3206 } 3207 3208 error = miocpullup(mp, sizeof (struct cons_polledio *)); 3209 if (error != 0) 3210 break; 3211 3212 /* 3213 * send up a message block containing the 3214 * cons_polledio structure. This provides 3215 * handles to the putchar, getchar, ischar, 3216 * polledio_enter and polledio_exit functions. 3217 */ 3218 *(struct cons_polledio **)mp->b_cont->b_rptr = 3219 &asy->polledio; 3220 3221 mp->b_datap->db_type = M_IOCACK; 3222 break; 3223 3224 case CONSCLOSEPOLLEDIO: 3225 /* 3226 * If we are driving a keyboard we never successfully 3227 * called CONSOPENPOLLEDIO so set the error to 3228 * ENOTSUP and NAK the request. 3229 */ 3230 if (asy->asy_device_type == ASY_KEYBOARD) { 3231 error = ENOTSUP; 3232 break; 3233 } 3234 3235 mp->b_datap->db_type = M_IOCACK; 3236 iocp->ioc_error = 0; 3237 iocp->ioc_rval = 0; 3238 break; 3239 3240 default: /* unexpected ioctl type */ 3241 /* 3242 * If we don't understand it, it's an error. NAK it. 3243 */ 3244 error = EINVAL; 3245 break; 3246 } 3247 } 3248 if (error != 0) { 3249 iocp->ioc_error = error; 3250 mp->b_datap->db_type = M_IOCNAK; 3251 } 3252 mutex_exit(asy->asy_excl); 3253 qreply(wq, mp); 3254 } 3255 3256 static void 3257 asyrsrv(queue_t *q) 3258 { 3259 mblk_t *bp; 3260 struct asyncline *async; 3261 3262 async = (struct asyncline *)q->q_ptr; 3263 3264 while (canputnext(q) && (bp = getq(q))) 3265 putnext(q, bp); 3266 ASYSETSOFT(async->async_common); 3267 async->async_polltid = 0; 3268 } 3269 3270 /* 3271 * Put procedure for write queue. 3272 * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here; 3273 * set the flow control character for M_STOPI and M_STARTI messages; 3274 * queue up M_BREAK, M_DELAY, and M_DATA messages for processing 3275 * by the start routine, and then call the start routine; discard 3276 * everything else. Note that this driver does not incorporate any 3277 * mechanism to negotiate to handle the canonicalization process. 3278 * It expects that these functions are handled in upper module(s), 3279 * as we do in ldterm. 3280 */ 3281 static void 3282 asywput(queue_t *q, mblk_t *mp) 3283 { 3284 register struct asyncline *async; 3285 register struct asycom *asy; 3286 int error; 3287 3288 async = (struct asyncline *)q->q_ptr; 3289 asy = async->async_common; 3290 3291 switch (mp->b_datap->db_type) { 3292 3293 case M_STOP: 3294 /* 3295 * Since we don't do real DMA, we can just let the 3296 * chip coast to a stop after applying the brakes. 3297 */ 3298 mutex_enter(asy->asy_excl); 3299 async->async_flags |= ASYNC_STOPPED; 3300 mutex_exit(asy->asy_excl); 3301 freemsg(mp); 3302 break; 3303 3304 case M_START: 3305 mutex_enter(asy->asy_excl); 3306 if (async->async_flags & ASYNC_STOPPED) { 3307 async->async_flags &= ~ASYNC_STOPPED; 3308 /* 3309 * If an output operation is in progress, 3310 * resume it. Otherwise, prod the start 3311 * routine. 3312 */ 3313 if (async->async_ocnt > 0) { 3314 mutex_enter(asy->asy_excl_hi); 3315 async_resume(async); 3316 mutex_exit(asy->asy_excl_hi); 3317 } else { 3318 async_start(async); 3319 } 3320 } 3321 mutex_exit(asy->asy_excl); 3322 freemsg(mp); 3323 break; 3324 3325 case M_IOCTL: 3326 switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 3327 3328 case TCSBRK: 3329 error = miocpullup(mp, sizeof (int)); 3330 if (error != 0) { 3331 miocnak(q, mp, 0, error); 3332 return; 3333 } 3334 3335 if (*(int *)mp->b_cont->b_rptr != 0) { 3336 #ifdef DEBUG 3337 if (asydebug & ASY_DEBUG_CLOSE) 3338 printf("asy%d: flush request.\n", 3339 UNIT(async->async_dev)); 3340 #endif 3341 (void) putq(q, mp); 3342 mutex_enter(asy->asy_excl); 3343 async_nstart(async, 1); 3344 mutex_exit(asy->asy_excl); 3345 break; 3346 } 3347 /*FALLTHROUGH*/ 3348 case TCSETSW: 3349 case TCSETSF: 3350 case TCSETAW: 3351 case TCSETAF: 3352 /* 3353 * The changes do not take effect until all 3354 * output queued before them is drained. 3355 * Put this message on the queue, so that 3356 * "async_start" will see it when it's done 3357 * with the output before it. Poke the 3358 * start routine, just in case. 3359 */ 3360 (void) putq(q, mp); 3361 mutex_enter(asy->asy_excl); 3362 async_start(async); 3363 mutex_exit(asy->asy_excl); 3364 break; 3365 3366 default: 3367 /* 3368 * Do it now. 3369 */ 3370 async_ioctl(async, q, mp, B_TRUE); 3371 break; 3372 } 3373 break; 3374 3375 case M_FLUSH: 3376 if (*mp->b_rptr & FLUSHW) { 3377 mutex_enter(asy->asy_excl); 3378 3379 /* 3380 * Abort any output in progress. 3381 */ 3382 mutex_enter(asy->asy_excl_hi); 3383 if (async->async_flags & ASYNC_BUSY) { 3384 async->async_ocnt = 0; 3385 async->async_flags &= ~ASYNC_BUSY; 3386 } 3387 mutex_exit(asy->asy_excl_hi); 3388 3389 /* Flush FIFO buffers */ 3390 if (asy->asy_use_fifo == FIFO_ON) { 3391 OUTB(FIFOR, FIFO_ON | FIFODMA | FIFOTXFLSH | 3392 (asy->asy_trig_level & 0xff)); 3393 } 3394 3395 /* 3396 * Flush our write queue. 3397 */ 3398 flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */ 3399 if (async->async_xmitblk != NULL) { 3400 freeb(async->async_xmitblk); 3401 async->async_xmitblk = NULL; 3402 } 3403 3404 mutex_exit(asy->asy_excl); 3405 *mp->b_rptr &= ~FLUSHW; /* it has been flushed */ 3406 } 3407 if (*mp->b_rptr & FLUSHR) { 3408 /* Flush FIFO buffers */ 3409 if (asy->asy_use_fifo == FIFO_ON) { 3410 OUTB(FIFOR, FIFO_ON | FIFODMA | FIFORXFLSH | 3411 (asy->asy_trig_level & 0xff)); 3412 } 3413 flushq(RD(q), FLUSHDATA); 3414 qreply(q, mp); /* give the read queues a crack at it */ 3415 } else { 3416 freemsg(mp); 3417 } 3418 3419 /* 3420 * We must make sure we process messages that survive the 3421 * write-side flush. Without this call, the close protocol 3422 * with ldterm can hang forever. (ldterm will have sent us a 3423 * TCSBRK ioctl that it expects a response to.) 3424 */ 3425 mutex_enter(asy->asy_excl); 3426 async_start(async); 3427 mutex_exit(asy->asy_excl); 3428 break; 3429 case M_BREAK: 3430 case M_DELAY: 3431 case M_DATA: 3432 /* 3433 * Queue the message up to be transmitted, 3434 * and poke the start routine. 3435 */ 3436 (void) putq(q, mp); 3437 mutex_enter(asy->asy_excl); 3438 async_start(async); 3439 mutex_exit(asy->asy_excl); 3440 break; 3441 3442 case M_STOPI: 3443 mutex_enter(asy->asy_excl); 3444 async->async_flowc = async->async_stopc; 3445 async_start(async); /* poke the start routine */ 3446 mutex_exit(asy->asy_excl); 3447 freemsg(mp); 3448 break; 3449 3450 case M_STARTI: 3451 mutex_enter(asy->asy_excl); 3452 async->async_flowc = async->async_startc; 3453 async_start(async); /* poke the start routine */ 3454 mutex_exit(asy->asy_excl); 3455 freemsg(mp); 3456 break; 3457 3458 case M_CTL: 3459 if (MBLKL(mp) >= sizeof (struct iocblk) && 3460 ((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_POSIXQUERY) { 3461 ((struct iocblk *)mp->b_rptr)->ioc_cmd = MC_HAS_POSIX; 3462 qreply(q, mp); 3463 } else { 3464 /* 3465 * These MC_SERVICE type messages are used by upper 3466 * modules to tell this driver to send input up 3467 * immediately, or that it can wait for normal 3468 * processing that may or may not be done. Sun 3469 * requires these for the mouse module. 3470 * (XXX - for x86?) 3471 */ 3472 mutex_enter(asy->asy_excl); 3473 switch (*mp->b_rptr) { 3474 3475 case MC_SERVICEIMM: 3476 async->async_flags |= ASYNC_SERVICEIMM; 3477 break; 3478 3479 case MC_SERVICEDEF: 3480 async->async_flags &= ~ASYNC_SERVICEIMM; 3481 break; 3482 } 3483 mutex_exit(asy->asy_excl); 3484 freemsg(mp); 3485 } 3486 break; 3487 3488 case M_IOCDATA: 3489 async_iocdata(q, mp); 3490 break; 3491 3492 default: 3493 freemsg(mp); 3494 break; 3495 } 3496 } 3497 3498 /* 3499 * Retry an "ioctl", now that "bufcall" claims we may be able to allocate 3500 * the buffer we need. 3501 */ 3502 static void 3503 async_reioctl(void *arg) 3504 { 3505 struct asyncline *async = arg; 3506 struct asycom *asy = async->async_common; 3507 queue_t *q; 3508 mblk_t *mp; 3509 3510 /* 3511 * The bufcall is no longer pending. 3512 */ 3513 mutex_enter(asy->asy_excl); 3514 async->async_wbufcid = 0; 3515 if ((q = async->async_ttycommon.t_writeq) == NULL) { 3516 mutex_exit(asy->asy_excl); 3517 return; 3518 } 3519 if ((mp = async->async_ttycommon.t_iocpending) != NULL) { 3520 /* not pending any more */ 3521 async->async_ttycommon.t_iocpending = NULL; 3522 mutex_exit(asy->asy_excl); 3523 /* not in STREAMS queue; we no longer know if we're in wput */ 3524 async_ioctl(async, q, mp, B_TRUE); 3525 } else 3526 mutex_exit(asy->asy_excl); 3527 } 3528 3529 static void 3530 async_iocdata(queue_t *q, mblk_t *mp) 3531 { 3532 struct asyncline *async = (struct asyncline *)q->q_ptr; 3533 struct asycom *asy; 3534 struct copyresp *csp; 3535 3536 asy = async->async_common; 3537 csp = (struct copyresp *)mp->b_rptr; 3538 3539 if (csp->cp_rval != 0) { 3540 freemsg(mp); 3541 return; 3542 } 3543 3544 mutex_enter(asy->asy_excl); 3545 3546 switch (csp->cp_cmd) { 3547 case TIOCMSET: 3548 case TIOCMBIS: 3549 case TIOCMBIC: 3550 if (mp->b_cont == NULL) { 3551 mutex_exit(asy->asy_excl); 3552 miocnak(q, mp, 0, EINVAL); 3553 break; 3554 } 3555 3556 mutex_enter(asy->asy_excl_hi); 3557 (void) asymctl(asy, dmtoasy(*(int *)mp->b_cont->b_rptr), 3558 csp->cp_cmd); 3559 mutex_exit(asy->asy_excl_hi); 3560 3561 freemsg(mp->b_cont); 3562 mp->b_cont = NULL; 3563 mutex_exit(asy->asy_excl); 3564 miocack(q, mp, 0, 0); 3565 break; 3566 3567 case TIOCMGET: 3568 if (mp->b_cont != NULL) { 3569 freemsg(mp->b_cont); 3570 mp->b_cont = NULL; 3571 } 3572 mutex_exit(asy->asy_excl); 3573 miocack(q, mp, 0, 0); 3574 break; 3575 3576 default: 3577 mutex_exit(asy->asy_excl); 3578 miocnak(q, mp, 0, EINVAL); 3579 break; 3580 } 3581 } 3582 3583 3584 /* 3585 * Set or get the modem control status. 3586 */ 3587 static int 3588 asymctl(struct asycom *asy, int bits, int how) 3589 { 3590 register int mcr_r, msr_r; 3591 3592 ASSERT(mutex_owned(asy->asy_excl_hi)); 3593 ASSERT(mutex_owned(asy->asy_excl)); 3594 3595 /* Read Modem Control Registers */ 3596 mcr_r = INB(MCR); 3597 3598 switch (how) { 3599 3600 case TIOCMSET: 3601 mcr_r = bits; 3602 break; 3603 3604 case TIOCMBIS: 3605 mcr_r |= bits; /* Set bits from input */ 3606 break; 3607 3608 case TIOCMBIC: 3609 mcr_r &= ~bits; /* Set ~bits from input */ 3610 break; 3611 3612 case TIOCMGET: 3613 /* Read Modem Status Registers */ 3614 if (INB(ICR) & MIEN) 3615 msr_r = asy->asy_cached_msr; 3616 else 3617 msr_r = INB(MSR); 3618 return (asytodm(mcr_r, msr_r)); 3619 } 3620 3621 OUTB(MCR, mcr_r); 3622 3623 return (mcr_r); 3624 } 3625 3626 static int 3627 asytodm(int mcr_r, int msr_r) 3628 { 3629 register int b = 0; 3630 3631 3632 /* MCR registers */ 3633 if (mcr_r & RTS) 3634 b |= TIOCM_RTS; 3635 3636 if (mcr_r & DTR) 3637 b |= TIOCM_DTR; 3638 3639 /* MSR registers */ 3640 if (msr_r & DCD) 3641 b |= TIOCM_CAR; 3642 3643 if (msr_r & CTS) 3644 b |= TIOCM_CTS; 3645 3646 if (msr_r & DSR) 3647 b |= TIOCM_DSR; 3648 3649 if (msr_r & RI) 3650 b |= TIOCM_RNG; 3651 3652 return (b); 3653 } 3654 3655 static int 3656 dmtoasy(int bits) 3657 { 3658 register int b = 0; 3659 3660 #ifdef CAN_NOT_SET /* only DTR and RTS can be set */ 3661 if (bits & TIOCM_CAR) 3662 b |= DCD; 3663 if (bits & TIOCM_CTS) 3664 b |= CTS; 3665 if (bits & TIOCM_DSR) 3666 b |= DSR; 3667 if (bits & TIOCM_RNG) 3668 b |= RI; 3669 #endif 3670 3671 if (bits & TIOCM_RTS) 3672 b |= RTS; 3673 if (bits & TIOCM_DTR) 3674 b |= DTR; 3675 3676 return (b); 3677 } 3678 3679 static void 3680 asycheckflowcontrol_hw(struct asycom *asy) 3681 { 3682 struct asyncline *async; 3683 uchar_t mcr, flag; 3684 3685 ASSERT(mutex_owned(asy->asy_excl_hi)); 3686 3687 async = (struct asyncline *)asy->asy_priv; 3688 ASSERT(async != NULL); 3689 3690 if (async->async_ttycommon.t_cflag & CRTSXOFF) { 3691 mcr = INB(MCR); 3692 flag = (async->async_flags & ASYNC_HW_IN_FLOW) ? 0 : RTS; 3693 if (((mcr ^ flag) & RTS) != 0) { 3694 OUTB(MCR, (mcr ^ RTS)); 3695 } 3696 } 3697 } 3698 3699 static boolean_t 3700 asycheckflowcontrol_sw(struct asycom *asy) 3701 { 3702 uchar_t ss; 3703 struct asyncline *async; 3704 int rval = B_FALSE; 3705 3706 ASSERT(mutex_owned(asy->asy_excl_hi)); 3707 3708 async = (struct asyncline *)asy->asy_priv; 3709 ASSERT(async != NULL); 3710 3711 if ((ss = async->async_flowc) != '\0' && (INB(LSR) & XHRE)) { 3712 /* 3713 * If we get this far, then we know that flowc is non-zero and 3714 * that there's transmit room available. We've "handled" the 3715 * request now, so clear it. If the user didn't ask for IXOFF, 3716 * then don't actually send anything, but wait for the next 3717 * opportunity. 3718 */ 3719 async->async_flowc = '\0'; 3720 if (async->async_ttycommon.t_iflag & IXOFF) { 3721 async->async_flags |= ASYNC_BUSY; 3722 OUTB(DAT, ss); 3723 rval = B_TRUE; 3724 } 3725 } 3726 3727 return (rval); 3728 } 3729 3730 /* 3731 * Check for abort character sequence 3732 */ 3733 static boolean_t 3734 abort_charseq_recognize(uchar_t ch) 3735 { 3736 static int state = 0; 3737 #define CNTRL(c) ((c)&037) 3738 static char sequence[] = { '\r', '~', CNTRL('b') }; 3739 3740 if (ch == sequence[state]) { 3741 if (++state >= sizeof (sequence)) { 3742 state = 0; 3743 return (B_TRUE); 3744 } 3745 } else { 3746 state = (ch == sequence[0]) ? 1 : 0; 3747 } 3748 return (B_FALSE); 3749 } 3750