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