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 22 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 23 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 24 /* All Rights Reserved */ 25 26 /* 27 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. 28 * Copyright 2012 Milan Jurik. All rights reserved. 29 * Copyright (c) 2016 by Delphix. All rights reserved. 30 * Copyright 2025 Oxide Computer Company 31 * Copyright 2024 Hans Rosenfeld 32 */ 33 34 35 /* 36 * Serial I/O driver for 8250/16450/16550A/16650/16750/16950 chips. 37 */ 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/strtty.h> 50 #include <sys/debug.h> 51 #include <sys/kbio.h> 52 #include <sys/cred.h> 53 #include <sys/stat.h> 54 #include <sys/consdev.h> 55 #include <sys/mkdev.h> 56 #include <sys/kmem.h> 57 #include <sys/cred.h> 58 #include <sys/strsun.h> 59 #ifdef DEBUG 60 #include <sys/promif.h> 61 #endif 62 #include <sys/modctl.h> 63 #include <sys/ddi.h> 64 #include <sys/sunddi.h> 65 #include <sys/pci.h> 66 #include <sys/asy.h> 67 #include <sys/policy.h> 68 #include <sys/sysmacros.h> 69 70 /* 71 * set the RX FIFO trigger_level to half the RX FIFO size for now 72 * we may want to make this configurable later. 73 */ 74 static int asy_trig_level = ASY_FCR_RHR_TRIG_8; 75 76 int asy_drain_check = 15000000; /* tunable: exit drain check time */ 77 int asy_min_dtr_low = 500000; /* tunable: minimum DTR down time */ 78 int asy_min_utbrk = 100000; /* tunable: minumum untimed brk time */ 79 80 int asymaxchip = ASY_MAXCHIP; /* tunable: limit chip support we look for */ 81 82 /* 83 * Just in case someone has a chip with broken loopback mode, we provide a 84 * means to disable the loopback test. By default, we only loopback test 85 * UARTs which look like they have FIFOs bigger than 16 bytes. 86 * Set to 0 to suppress test, or to 2 to enable test on any size FIFO. 87 */ 88 int asy_fifo_test = 1; /* tunable: set to 0, 1, or 2 */ 89 90 /* 91 * Allow ability to switch off testing of the scratch register. 92 * Some UART emulators might not have it. This will also disable the test 93 * for Exar/Startech ST16C650, as that requires use of the SCR register. 94 */ 95 int asy_scr_test = 1; /* tunable: set to 0 to disable SCR reg test */ 96 97 /* 98 * As we don't yet support on-chip flow control, it's a bad idea to put a 99 * large number of characters in the TX FIFO, since if other end tells us 100 * to stop transmitting, we can only stop filling the TX FIFO, but it will 101 * still carry on draining by itself, so remote end still gets what's left 102 * in the FIFO. 103 */ 104 int asy_max_tx_fifo = 16; /* tunable: max fill of TX FIFO */ 105 106 #define async_stopc async_ttycommon.t_stopc 107 #define async_startc async_ttycommon.t_startc 108 109 #define ASY_INIT 1 110 #define ASY_NOINIT 0 111 112 /* enum value for sw and hw flow control action */ 113 typedef enum { 114 FLOW_CHECK, 115 FLOW_STOP, 116 FLOW_START 117 } async_flowc_action; 118 119 #ifdef DEBUG 120 #define ASY_DEBUG_INIT 0x0001 /* Output msgs during driver initialization. */ 121 #define ASY_DEBUG_INPUT 0x0002 /* Report characters received during int. */ 122 #define ASY_DEBUG_EOT 0x0004 /* Output msgs when wait for xmit to finish. */ 123 #define ASY_DEBUG_CLOSE 0x0008 /* Output msgs when driver open/close called */ 124 #define ASY_DEBUG_HFLOW 0x0010 /* Output msgs when H/W flowcontrol is active */ 125 #define ASY_DEBUG_PROCS 0x0020 /* Output each proc name as it is entered. */ 126 #define ASY_DEBUG_STATE 0x0040 /* Output value of Interrupt Service Reg. */ 127 #define ASY_DEBUG_INTR 0x0080 /* Output value of Interrupt Service Reg. */ 128 #define ASY_DEBUG_OUT 0x0100 /* Output msgs about output events. */ 129 #define ASY_DEBUG_BUSY 0x0200 /* Output msgs when xmit is enabled/disabled */ 130 #define ASY_DEBUG_MODEM 0x0400 /* Output msgs about modem status & control. */ 131 #define ASY_DEBUG_MODM2 0x0800 /* Output msgs about modem status & control. */ 132 #define ASY_DEBUG_IOCTL 0x1000 /* Output msgs about ioctl messages. */ 133 #define ASY_DEBUG_CHIP 0x2000 /* Output msgs about chip identification. */ 134 #define ASY_DEBUG_SFLOW 0x4000 /* Output msgs when S/W flowcontrol is active */ 135 136 static int debug = 0; 137 138 #define ASY_DEBUG(asy, x) (asy->asy_debug & (x)) 139 #define ASY_DPRINTF(asy, fac, format, ...) \ 140 if (ASY_DEBUG(asy, fac)) \ 141 asyerror(asy, CE_CONT, "!%s: " format, __func__, ##__VA_ARGS__) 142 #else 143 #define ASY_DEBUG(asy, x) B_FALSE 144 #define ASY_DPRINTF(asy, fac, format, ...) 145 #endif 146 147 /* 148 * PPS (Pulse Per Second) support. 149 */ 150 void ddi_hardpps(struct timeval *, int); 151 /* 152 * This is protected by the asy_excl_hi of the port on which PPS event 153 * handling is enabled. Note that only one port should have this enabled at 154 * any one time. Enabling PPS handling on multiple ports will result in 155 * unpredictable (but benign) results. 156 */ 157 static struct ppsclockev asy_ppsev; 158 159 #ifdef PPSCLOCKLED 160 /* XXX Use these to observe PPS latencies and jitter on a scope */ 161 #define LED_ON 162 #define LED_OFF 163 #else 164 #define LED_ON 165 #define LED_OFF 166 #endif 167 168 static void asy_put_idx(const struct asycom *, asy_reg_t, uint8_t); 169 static uint8_t asy_get_idx(const struct asycom *, asy_reg_t); 170 171 static void asy_put_add(const struct asycom *, asy_reg_t, uint8_t); 172 static uint8_t asy_get_add(const struct asycom *, asy_reg_t); 173 174 static void asy_put_ext(const struct asycom *, asy_reg_t, uint8_t); 175 static uint8_t asy_get_ext(const struct asycom *, asy_reg_t); 176 177 static void asy_put_reg(const struct asycom *, asy_reg_t, uint8_t); 178 static uint8_t asy_get_reg(const struct asycom *, asy_reg_t); 179 180 static void asy_put(const struct asycom *, asy_reg_t, uint8_t); 181 static uint8_t asy_get(const struct asycom *, asy_reg_t); 182 183 static void asy_set(const struct asycom *, asy_reg_t, uint8_t); 184 static void asy_clr(const struct asycom *, asy_reg_t, uint8_t); 185 186 static void asy_enable_interrupts(const struct asycom *, uint8_t); 187 static void asy_disable_interrupts(const struct asycom *, uint8_t); 188 static void asy_set_baudrate(const struct asycom *, int); 189 static void asy_wait_baudrate(struct asycom *); 190 191 #define BAUDINDEX(cflg) (((cflg) & CBAUDEXT) ? \ 192 (((cflg) & CBAUD) + CBAUD + 1) : ((cflg) & CBAUD)) 193 194 static void asysetsoft(struct asycom *); 195 static uint_t asysoftintr(caddr_t, caddr_t); 196 static uint_t asyintr(caddr_t, caddr_t); 197 198 static boolean_t abort_charseq_recognize(uchar_t ch); 199 200 /* The async interrupt entry points */ 201 static void async_txint(struct asycom *asy); 202 static void async_rxint(struct asycom *asy, uchar_t lsr); 203 static void async_msint(struct asycom *asy); 204 static void async_softint(struct asycom *asy); 205 206 static void async_ioctl(struct asyncline *async, queue_t *q, mblk_t *mp); 207 static void async_reioctl(void *unit); 208 static void async_iocdata(queue_t *q, mblk_t *mp); 209 static void async_restart(void *arg); 210 static void async_start(struct asyncline *async); 211 static void async_resume(struct asyncline *async); 212 static void asy_program(struct asycom *asy, int mode); 213 static void asyinit(struct asycom *asy); 214 static void asy_waiteot(struct asycom *asy); 215 static void asyputchar(cons_polledio_arg_t, uchar_t c); 216 static int asygetchar(cons_polledio_arg_t); 217 static boolean_t asyischar(cons_polledio_arg_t); 218 219 static int asymctl(struct asycom *, int, int); 220 static int asytodm(int, int); 221 static int dmtoasy(struct asycom *, int); 222 static void asyerror(const struct asycom *, int, const char *, ...) 223 __KPRINTFLIKE(3); 224 static void asy_parse_mode(dev_info_t *devi, struct asycom *asy); 225 static void asy_soft_state_free(struct asycom *); 226 static char *asy_hw_name(struct asycom *asy); 227 static void async_hold_utbrk(void *arg); 228 static void async_resume_utbrk(struct asyncline *async); 229 static void async_dtr_free(struct asyncline *async); 230 static int asy_identify_chip(dev_info_t *devi, struct asycom *asy); 231 static void asy_reset_fifo(struct asycom *asy, uchar_t flags); 232 static void asy_carrier_check(struct asycom *); 233 static int asy_getproperty(dev_info_t *devi, struct asycom *asy, 234 const char *property); 235 static boolean_t async_flowcontrol_sw_input(struct asycom *asy, 236 async_flowc_action onoff, int type); 237 static void async_flowcontrol_sw_output(struct asycom *asy, 238 async_flowc_action onoff); 239 static void async_flowcontrol_hw_input(struct asycom *asy, 240 async_flowc_action onoff, int type); 241 static void async_flowcontrol_hw_output(struct asycom *asy, 242 async_flowc_action onoff); 243 244 #define GET_PROP(devi, pname, pflag, pval, plen) \ 245 (ddi_prop_op(DDI_DEV_T_ANY, (devi), PROP_LEN_AND_VAL_BUF, \ 246 (pflag), (pname), (caddr_t)(pval), (plen))) 247 248 kmutex_t asy_glob_lock; /* lock protecting global data manipulation */ 249 void *asy_soft_state; 250 251 /* Standard COM port I/O addresses */ 252 static const int standard_com_ports[] = { 253 COM1_IOADDR, COM2_IOADDR, COM3_IOADDR, COM4_IOADDR 254 }; 255 256 static int *com_ports; 257 static uint_t num_com_ports; 258 259 #ifdef DEBUG 260 /* 261 * Set this to true to make the driver pretend to do a suspend. Useful 262 * for debugging suspend/resume code with a serial debugger. 263 */ 264 boolean_t asy_nosuspend = B_FALSE; 265 #endif 266 267 268 /* 269 * Baud rate table. Indexed by #defines found in sys/termios.h 270 * 271 * The default crystal frequency is 1.8432 MHz. The 8250A used a fixed /16 272 * prescaler and a 16bit divisor, split in two registers (DLH and DLL). 273 * 274 * The 16950 adds TCR and CKS registers. The TCR can be used to set the 275 * prescaler from /4 to /16. The CKS can be used, among other things, to 276 * select a isochronous 1x mode, effectively disabling the prescaler. 277 * This would theoretically allow a baud rate of 1843200 driven directly 278 * by the default crystal frequency, although the highest termios.h-defined 279 * baud rate we can support is half of that, 921600 baud. 280 */ 281 #define UNSUPPORTED 0x00, 0x00, 0x00 282 static struct { 283 uint8_t asy_dlh; 284 uint8_t asy_dll; 285 uint8_t asy_tcr; 286 } asy_baud_tab[] = { 287 [B0] = { UNSUPPORTED }, /* 0 baud */ 288 [B50] = { 0x09, 0x00, 0x00 }, /* 50 baud */ 289 [B75] = { 0x06, 0x00, 0x00 }, /* 75 baud */ 290 [B110] = { 0x04, 0x17, 0x00 }, /* 110 baud (0.026% error) */ 291 [B134] = { 0x03, 0x59, 0x00 }, /* 134 baud (0.058% error) */ 292 [B150] = { 0x03, 0x00, 0x00 }, /* 150 baud */ 293 [B200] = { 0x02, 0x40, 0x00 }, /* 200 baud */ 294 [B300] = { 0x01, 0x80, 0x00 }, /* 300 baud */ 295 [B600] = { 0x00, 0xc0, 0x00 }, /* 600 baud */ 296 [B1200] = { 0x00, 0x60, 0x00 }, /* 1200 baud */ 297 [B1800] = { 0x00, 0x40, 0x00 }, /* 1800 baud */ 298 [B2400] = { 0x00, 0x30, 0x00 }, /* 2400 baud */ 299 [B4800] = { 0x00, 0x18, 0x00 }, /* 4800 baud */ 300 [B9600] = { 0x00, 0x0c, 0x00 }, /* 9600 baud */ 301 [B19200] = { 0x00, 0x06, 0x00 }, /* 19200 baud */ 302 [B38400] = { 0x00, 0x03, 0x00 }, /* 38400 baud */ 303 [B57600] = { 0x00, 0x02, 0x00 }, /* 57600 baud */ 304 [B76800] = { 0x00, 0x06, 0x04 }, /* 76800 baud (16950) */ 305 [B115200] = { 0x00, 0x01, 0x00 }, /* 115200 baud */ 306 [B153600] = { 0x00, 0x03, 0x04 }, /* 153600 baud (16950) */ 307 [B230400] = { 0x00, 0x02, 0x04 }, /* 230400 baud (16950) */ 308 [B307200] = { 0x00, 0x01, 0x06 }, /* 307200 baud (16950) */ 309 [B460800] = { 0x00, 0x01, 0x04 }, /* 460800 baud (16950) */ 310 [B921600] = { 0x00, 0x02, 0x01 }, /* 921600 baud (16950) */ 311 [B1000000] = { UNSUPPORTED }, /* 1000000 baud */ 312 [B1152000] = { UNSUPPORTED }, /* 1152000 baud */ 313 [B1500000] = { UNSUPPORTED }, /* 1500000 baud */ 314 [B2000000] = { UNSUPPORTED }, /* 2000000 baud */ 315 [B2500000] = { UNSUPPORTED }, /* 2500000 baud */ 316 [B3000000] = { UNSUPPORTED }, /* 3000000 baud */ 317 [B3500000] = { UNSUPPORTED }, /* 3500000 baud */ 318 [B4000000] = { UNSUPPORTED }, /* 4000000 baud */ 319 }; 320 321 /* 322 * Register table. For each logical register, we define the minimum hwtype, the 323 * register offset, and function pointers for reading and writing the register. 324 * A NULL pointer indicates the register cannot be read from or written to, 325 * respectively. 326 */ 327 static struct { 328 int asy_min_hwtype; 329 int8_t asy_reg_off; 330 uint8_t (*asy_get_reg)(const struct asycom *, asy_reg_t); 331 void (*asy_put_reg)(const struct asycom *, asy_reg_t, uint8_t); 332 } asy_reg_table[] = { 333 [ASY_ILLEGAL] = { 0, -1, NULL, NULL }, 334 /* 8250 / 16450 / 16550 registers */ 335 [ASY_THR] = { ASY_8250A, 0, NULL, asy_put_reg }, 336 [ASY_RHR] = { ASY_8250A, 0, asy_get_reg, NULL }, 337 [ASY_IER] = { ASY_8250A, 1, asy_get_reg, asy_put_reg }, 338 [ASY_FCR] = { ASY_16550, 2, NULL, asy_put_reg }, 339 [ASY_ISR] = { ASY_8250A, 2, asy_get_reg, NULL }, 340 [ASY_LCR] = { ASY_8250A, 3, asy_get_reg, asy_put_reg }, 341 [ASY_MCR] = { ASY_8250A, 4, asy_get_reg, asy_put_reg }, 342 [ASY_LSR] = { ASY_8250A, 5, asy_get_reg, NULL }, 343 [ASY_MSR] = { ASY_8250A, 6, asy_get_reg, NULL }, 344 [ASY_SPR] = { ASY_8250A, 7, asy_get_reg, asy_put_reg }, 345 [ASY_DLL] = { ASY_8250A, 0, asy_get_reg, asy_put_reg }, 346 [ASY_DLH] = { ASY_8250A, 1, asy_get_reg, asy_put_reg }, 347 /* 16750 extended register */ 348 [ASY_EFR] = { ASY_16750, 2, asy_get_ext, asy_put_ext }, 349 /* 16650 extended registers */ 350 [ASY_XON1] = { ASY_16650, 4, asy_get_ext, asy_put_ext }, 351 [ASY_XON2] = { ASY_16650, 5, asy_get_ext, asy_put_ext }, 352 [ASY_XOFF1] = { ASY_16650, 6, asy_get_ext, asy_put_ext }, 353 [ASY_XOFF2] = { ASY_16650, 7, asy_get_ext, asy_put_ext }, 354 /* 16950 additional registers */ 355 [ASY_ASR] = { ASY_16950, 1, asy_get_add, asy_put_add }, 356 [ASY_RFL] = { ASY_16950, 3, asy_get_add, NULL }, 357 [ASY_TFL] = { ASY_16950, 4, asy_get_add, NULL }, 358 [ASY_ICR] = { ASY_16950, 5, asy_get_reg, asy_put_reg }, 359 /* 16950 indexed registers */ 360 [ASY_ACR] = { ASY_16950, 0, asy_get_idx, asy_put_idx }, 361 [ASY_CPR] = { ASY_16950, 1, asy_get_idx, asy_put_idx }, 362 [ASY_TCR] = { ASY_16950, 2, asy_get_idx, asy_put_idx }, 363 [ASY_CKS] = { ASY_16950, 3, asy_get_idx, asy_put_idx }, 364 [ASY_TTL] = { ASY_16950, 4, asy_get_idx, asy_put_idx }, 365 [ASY_RTL] = { ASY_16950, 5, asy_get_idx, asy_put_idx }, 366 [ASY_FCL] = { ASY_16950, 6, asy_get_idx, asy_put_idx }, 367 [ASY_FCH] = { ASY_16950, 7, asy_get_idx, asy_put_idx }, 368 [ASY_ID1] = { ASY_16950, 8, asy_get_idx, NULL }, 369 [ASY_ID2] = { ASY_16950, 9, asy_get_idx, NULL }, 370 [ASY_ID3] = { ASY_16950, 10, asy_get_idx, NULL }, 371 [ASY_REV] = { ASY_16950, 11, asy_get_idx, NULL }, 372 [ASY_CSR] = { ASY_16950, 12, NULL, asy_put_idx }, 373 [ASY_NMR] = { ASY_16950, 13, asy_get_idx, asy_put_idx }, 374 }; 375 376 377 static int asyrsrv(queue_t *q); 378 static int asyopen(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); 379 static int asyclose(queue_t *q, int flag, cred_t *credp); 380 static int asywputdo(queue_t *q, mblk_t *mp, boolean_t); 381 static int asywput(queue_t *q, mblk_t *mp); 382 383 struct module_info asy_info = { 384 0, 385 "asy", 386 0, 387 INFPSZ, 388 4096, 389 128 390 }; 391 392 static struct qinit asy_rint = { 393 putq, 394 asyrsrv, 395 asyopen, 396 asyclose, 397 NULL, 398 &asy_info, 399 NULL 400 }; 401 402 static struct qinit asy_wint = { 403 asywput, 404 NULL, 405 NULL, 406 NULL, 407 NULL, 408 &asy_info, 409 NULL 410 }; 411 412 struct streamtab asy_str_info = { 413 &asy_rint, 414 &asy_wint, 415 NULL, 416 NULL 417 }; 418 419 static void asy_intr_free(struct asycom *); 420 static int asy_intr_setup(struct asycom *, int); 421 422 static void asy_softintr_free(struct asycom *); 423 static int asy_softintr_setup(struct asycom *); 424 425 static int asy_suspend(struct asycom *); 426 static int asy_resume(dev_info_t *); 427 428 static int asyinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 429 void **result); 430 static int asyprobe(dev_info_t *); 431 static int asyattach(dev_info_t *, ddi_attach_cmd_t); 432 static int asydetach(dev_info_t *, ddi_detach_cmd_t); 433 static int asyquiesce(dev_info_t *); 434 435 static struct cb_ops cb_asy_ops = { 436 nodev, /* cb_open */ 437 nodev, /* cb_close */ 438 nodev, /* cb_strategy */ 439 nodev, /* cb_print */ 440 nodev, /* cb_dump */ 441 nodev, /* cb_read */ 442 nodev, /* cb_write */ 443 nodev, /* cb_ioctl */ 444 nodev, /* cb_devmap */ 445 nodev, /* cb_mmap */ 446 nodev, /* cb_segmap */ 447 nochpoll, /* cb_chpoll */ 448 ddi_prop_op, /* cb_prop_op */ 449 &asy_str_info, /* cb_stream */ 450 D_MP /* cb_flag */ 451 }; 452 453 struct dev_ops asy_ops = { 454 DEVO_REV, /* devo_rev */ 455 0, /* devo_refcnt */ 456 asyinfo, /* devo_getinfo */ 457 nulldev, /* devo_identify */ 458 asyprobe, /* devo_probe */ 459 asyattach, /* devo_attach */ 460 asydetach, /* devo_detach */ 461 nodev, /* devo_reset */ 462 &cb_asy_ops, /* devo_cb_ops */ 463 NULL, /* devo_bus_ops */ 464 NULL, /* power */ 465 asyquiesce, /* quiesce */ 466 }; 467 468 static struct modldrv modldrv = { 469 &mod_driverops, /* Type of module. This one is a driver */ 470 "ASY driver", 471 &asy_ops, /* driver ops */ 472 }; 473 474 static struct modlinkage modlinkage = { 475 MODREV_1, 476 (void *)&modldrv, 477 NULL 478 }; 479 480 int 481 _init(void) 482 { 483 int i; 484 485 i = ddi_soft_state_init(&asy_soft_state, sizeof (struct asycom), 2); 486 if (i == 0) { 487 mutex_init(&asy_glob_lock, NULL, MUTEX_DRIVER, NULL); 488 if ((i = mod_install(&modlinkage)) != 0) { 489 mutex_destroy(&asy_glob_lock); 490 ddi_soft_state_fini(&asy_soft_state); 491 #ifdef DEBUG 492 } else { 493 if (debug & ASY_DEBUG_INIT) 494 cmn_err(CE_NOTE, "!%s, debug = %x", 495 modldrv.drv_linkinfo, debug); 496 #endif 497 } 498 } 499 return (i); 500 } 501 502 int 503 _fini(void) 504 { 505 int i; 506 507 if ((i = mod_remove(&modlinkage)) == 0) { 508 #ifdef DEBUG 509 if (debug & ASY_DEBUG_INIT) 510 cmn_err(CE_NOTE, "!%s unloading", 511 modldrv.drv_linkinfo); 512 #endif 513 mutex_destroy(&asy_glob_lock); 514 /* free "motherboard-serial-ports" property if allocated */ 515 if (com_ports != NULL && com_ports != (int *)standard_com_ports) 516 ddi_prop_free(com_ports); 517 com_ports = NULL; 518 ddi_soft_state_fini(&asy_soft_state); 519 } 520 return (i); 521 } 522 523 int 524 _info(struct modinfo *modinfop) 525 { 526 return (mod_info(&modlinkage, modinfop)); 527 } 528 529 static void 530 asy_put_idx(const struct asycom *asy, asy_reg_t reg, uint8_t val) 531 { 532 ASSERT(asy->asy_hwtype >= ASY_16950); 533 534 ASSERT(reg >= ASY_ACR); 535 ASSERT(reg <= ASY_NREG); 536 537 /* 538 * The last value written to LCR must not have been the magic value for 539 * EFR access. Every time the driver writes that magic value to access 540 * EFR, XON1, XON2, XOFF1, and XOFF2, the driver restores the original 541 * value of LCR, so we should be good here. 542 * 543 * I'd prefer to ASSERT this, but I'm not sure it's worth the hassle. 544 */ 545 546 /* Write indexed register offset to SPR. */ 547 asy_put(asy, ASY_SPR, asy_reg_table[reg].asy_reg_off); 548 549 /* Write value to ICR. */ 550 asy_put(asy, ASY_ICR, val); 551 } 552 553 static uint8_t 554 asy_get_idx(const struct asycom *asy, asy_reg_t reg) 555 { 556 uint8_t val; 557 558 ASSERT(asy->asy_hwtype >= ASY_16950); 559 560 ASSERT(reg >= ASY_ACR); 561 ASSERT(reg <= ASY_NREG); 562 563 /* Enable access to ICR in ACR. */ 564 asy_put(asy, ASY_ACR, ASY_ACR_ICR | asy->asy_acr); 565 566 /* Write indexed register offset to SPR. */ 567 asy_put(asy, ASY_SPR, asy_reg_table[reg].asy_reg_off); 568 569 /* Read value from ICR. */ 570 val = asy_get(asy, ASY_ICR); 571 572 /* Restore ACR. */ 573 asy_put(asy, ASY_ACR, asy->asy_acr); 574 575 return (val); 576 } 577 578 static void 579 asy_put_add(const struct asycom *asy, asy_reg_t reg, uint8_t val) 580 { 581 ASSERT(asy->asy_hwtype >= ASY_16950); 582 583 /* Only ASR is writable, RFL and TFL are read-only. */ 584 ASSERT(reg == ASY_ASR); 585 586 /* 587 * Only ASR[0] (Transmitter Disabled) and ASR[1] (Remote Transmitter 588 * Disabled) are writable. 589 */ 590 ASSERT((val & ~(ASY_ASR_TD | ASY_ASR_RTD)) == 0); 591 592 /* Enable access to ASR in ACR. */ 593 asy_put(asy, ASY_ACR, ASY_ACR_ASR | asy->asy_acr); 594 595 /* Write value to ASR. */ 596 asy_put_reg(asy, reg, val); 597 598 /* Restore ACR. */ 599 asy_put(asy, ASY_ACR, asy->asy_acr); 600 } 601 602 static uint8_t 603 asy_get_add(const struct asycom *asy, asy_reg_t reg) 604 { 605 uint8_t val; 606 607 ASSERT(asy->asy_hwtype >= ASY_16950); 608 609 ASSERT(reg >= ASY_ASR); 610 ASSERT(reg <= ASY_TFL); 611 612 /* 613 * The last value written to LCR must not have been the magic value for 614 * EFR access. Every time the driver writes that magic value to access 615 * EFR, XON1, XON2, XOFF1, and XOFF2, the driver restores the original 616 * value of LCR, so we should be good here. 617 * 618 * I'd prefer to ASSERT this, but I'm not sure it's worth the hassle. 619 */ 620 621 /* Enable access to ASR in ACR. */ 622 asy_put(asy, ASY_ACR, ASY_ACR_ASR | asy->asy_acr); 623 624 /* Read value from register. */ 625 val = asy_get_reg(asy, reg); 626 627 /* Restore ACR. */ 628 asy_put(asy, ASY_ACR, 0 | asy->asy_acr); 629 630 return (val); 631 } 632 633 static void 634 asy_put_ext(const struct asycom *asy, asy_reg_t reg, uint8_t val) 635 { 636 uint8_t lcr; 637 638 /* 639 * On the 16750, EFR can be accessed when LCR[7]=1 (DLAB). 640 * Only two bits are assigned for auto RTS/CTS, which we don't support 641 * yet. 642 * 643 * So insist we have a 16650 or up. 644 */ 645 ASSERT(asy->asy_hwtype >= ASY_16650); 646 647 ASSERT(reg >= ASY_EFR); 648 ASSERT(reg <= ASY_XOFF2); 649 650 /* Save LCR contents. */ 651 lcr = asy_get(asy, ASY_LCR); 652 653 /* Enable extended register access. */ 654 asy_put(asy, ASY_LCR, ASY_LCR_EFRACCESS); 655 656 /* Write extended register */ 657 asy_put_reg(asy, reg, val); 658 659 /* Restore previous LCR contents, disabling extended register access. */ 660 asy_put(asy, ASY_LCR, lcr); 661 } 662 663 static uint8_t 664 asy_get_ext(const struct asycom *asy, asy_reg_t reg) 665 { 666 uint8_t lcr, val; 667 668 /* 669 * On the 16750, EFR can be accessed when LCR[7]=1 (DLAB). 670 * Only two bits are assigned for auto RTS/CTS, which we don't support 671 * yet. 672 * 673 * So insist we have a 16650 or up. 674 */ 675 ASSERT(asy->asy_hwtype >= ASY_16650); 676 677 ASSERT(reg >= ASY_EFR); 678 ASSERT(reg <= ASY_XOFF2); 679 680 /* Save LCR contents. */ 681 lcr = asy_get(asy, ASY_LCR); 682 683 /* Enable extended register access. */ 684 asy_put(asy, ASY_LCR, ASY_LCR_EFRACCESS); 685 686 /* Read extended register */ 687 val = asy_get_reg(asy, reg); 688 689 /* Restore previous LCR contents, disabling extended register access. */ 690 asy_put(asy, ASY_LCR, lcr); 691 692 return (val); 693 } 694 695 static void 696 asy_put_reg(const struct asycom *asy, asy_reg_t reg, uint8_t val) 697 { 698 ASSERT(asy->asy_hwtype >= asy_reg_table[reg].asy_min_hwtype); 699 700 ddi_put8(asy->asy_iohandle, 701 asy->asy_ioaddr + asy_reg_table[reg].asy_reg_off, val); 702 } 703 704 static uint8_t 705 asy_get_reg(const struct asycom *asy, asy_reg_t reg) 706 { 707 ASSERT(asy->asy_hwtype >= asy_reg_table[reg].asy_min_hwtype); 708 709 return (ddi_get8(asy->asy_iohandle, 710 asy->asy_ioaddr + asy_reg_table[reg].asy_reg_off)); 711 } 712 713 static void 714 asy_put(const struct asycom *asy, asy_reg_t reg, uint8_t val) 715 { 716 ASSERT(mutex_owned(&asy->asy_excl_hi)); 717 718 ASSERT(reg > ASY_ILLEGAL); 719 ASSERT(reg < ASY_NREG); 720 721 ASSERT(asy->asy_hwtype >= asy_reg_table[reg].asy_min_hwtype); 722 ASSERT(asy_reg_table[reg].asy_put_reg != NULL); 723 724 asy_reg_table[reg].asy_put_reg(asy, reg, val); 725 } 726 727 static uint8_t 728 asy_get(const struct asycom *asy, asy_reg_t reg) 729 { 730 uint8_t val; 731 732 ASSERT(mutex_owned(&asy->asy_excl_hi)); 733 734 ASSERT(reg > ASY_ILLEGAL); 735 ASSERT(reg < ASY_NREG); 736 737 ASSERT(asy->asy_hwtype >= asy_reg_table[reg].asy_min_hwtype); 738 ASSERT(asy_reg_table[reg].asy_get_reg != NULL); 739 740 val = asy_reg_table[reg].asy_get_reg(asy, reg); 741 742 return (val); 743 } 744 745 static void 746 asy_set(const struct asycom *asy, asy_reg_t reg, uint8_t bits) 747 { 748 uint8_t val = asy_get(asy, reg); 749 750 asy_put(asy, reg, val | bits); 751 } 752 753 static void 754 asy_clr(const struct asycom *asy, asy_reg_t reg, uint8_t bits) 755 { 756 uint8_t val = asy_get(asy, reg); 757 758 asy_put(asy, reg, val & ~bits); 759 } 760 761 static void 762 asy_enable_interrupts(const struct asycom *asy, uint8_t intr) 763 { 764 /* Don't touch any IER bits we don't support. */ 765 intr &= ASY_IER_ALL; 766 767 asy_set(asy, ASY_IER, intr); 768 } 769 770 static void 771 asy_disable_interrupts(const struct asycom *asy, uint8_t intr) 772 { 773 /* Don't touch any IER bits we don't support. */ 774 intr &= ASY_IER_ALL; 775 776 asy_clr(asy, ASY_IER, intr); 777 } 778 779 static void 780 asy_set_baudrate(const struct asycom *asy, int baudrate) 781 { 782 uint8_t tcr; 783 784 if (baudrate == 0) 785 return; 786 787 if (baudrate >= ARRAY_SIZE(asy_baud_tab)) 788 return; 789 790 tcr = asy_baud_tab[baudrate].asy_tcr; 791 792 if (tcr != 0 && asy->asy_hwtype < ASY_16950) 793 return; 794 795 if (asy->asy_hwtype >= ASY_16950) { 796 if (tcr == 0x01) { 797 /* Isochronous 1x mode is selected in CKS, not TCR. */ 798 asy_put(asy, ASY_CKS, 799 ASY_CKS_RCLK_1X | ASY_CKS_TCLK_1X); 800 asy_put(asy, ASY_TCR, 0); 801 } else { 802 /* Reset CKS in case it was set to 1x mode. */ 803 asy_put(asy, ASY_CKS, 0); 804 805 ASSERT(tcr == 0x00 || tcr >= 0x04 || tcr <= 0x0f); 806 asy_put(asy, ASY_TCR, tcr); 807 } 808 ASY_DPRINTF(asy, ASY_DEBUG_IOCTL, 809 "setting baudrate %d, CKS 0x%02x, TCR 0x%02x", 810 baudrate, asy_get(asy, ASY_CKS), asy_get(asy, ASY_TCR)); 811 } 812 813 ASY_DPRINTF(asy, ASY_DEBUG_IOCTL, 814 "setting baudrate %d, divisor 0x%02x%02x", 815 baudrate, asy_baud_tab[baudrate].asy_dlh, 816 asy_baud_tab[baudrate].asy_dll); 817 818 asy_set(asy, ASY_LCR, ASY_LCR_DLAB); 819 820 asy_put(asy, ASY_DLL, asy_baud_tab[baudrate].asy_dll); 821 asy_put(asy, ASY_DLH, asy_baud_tab[baudrate].asy_dlh); 822 823 asy_clr(asy, ASY_LCR, ASY_LCR_DLAB); 824 } 825 826 /* 827 * Loop until the TSR is empty. 828 * 829 * The wait period is clock / (baud * 16) * 16 * 2. 830 */ 831 static void 832 asy_wait_baudrate(struct asycom *asy) 833 { 834 struct asyncline *async = asy->asy_priv; 835 int rate = BAUDINDEX(async->async_ttycommon.t_cflag); 836 clock_t usec = 837 ((((clock_t)asy_baud_tab[rate].asy_dlh) << 8) | 838 ((clock_t)asy_baud_tab[rate].asy_dll)) * 16 * 2; 839 840 ASSERT(mutex_owned(&asy->asy_excl)); 841 ASSERT(mutex_owned(&asy->asy_excl_hi)); 842 843 while ((asy_get(asy, ASY_LSR) & ASY_LSR_TEMT) == 0) { 844 mutex_exit(&asy->asy_excl_hi); 845 mutex_exit(&asy->asy_excl); 846 drv_usecwait(usec); 847 mutex_enter(&asy->asy_excl); 848 mutex_enter(&asy->asy_excl_hi); 849 } 850 asy_set(asy, ASY_LCR, ASY_LCR_SETBRK); 851 } 852 853 void 854 async_put_suspq(struct asycom *asy, mblk_t *mp) 855 { 856 struct asyncline *async = asy->asy_priv; 857 858 ASSERT(mutex_owned(&asy->asy_excl)); 859 860 if (async->async_suspqf == NULL) 861 async->async_suspqf = mp; 862 else 863 async->async_suspqb->b_next = mp; 864 865 async->async_suspqb = mp; 866 } 867 868 static mblk_t * 869 async_get_suspq(struct asycom *asy) 870 { 871 struct asyncline *async = asy->asy_priv; 872 mblk_t *mp; 873 874 ASSERT(mutex_owned(&asy->asy_excl)); 875 876 if ((mp = async->async_suspqf) != NULL) { 877 async->async_suspqf = mp->b_next; 878 mp->b_next = NULL; 879 } else { 880 async->async_suspqb = NULL; 881 } 882 return (mp); 883 } 884 885 static void 886 async_process_suspq(struct asycom *asy) 887 { 888 struct asyncline *async = asy->asy_priv; 889 mblk_t *mp; 890 891 ASSERT(mutex_owned(&asy->asy_excl)); 892 893 while ((mp = async_get_suspq(asy)) != NULL) { 894 queue_t *q; 895 896 q = async->async_ttycommon.t_writeq; 897 ASSERT(q != NULL); 898 mutex_exit(&asy->asy_excl); 899 (void) asywputdo(q, mp, B_FALSE); 900 mutex_enter(&asy->asy_excl); 901 } 902 async->async_flags &= ~ASYNC_DDI_SUSPENDED; 903 cv_broadcast(&async->async_flags_cv); 904 } 905 906 static int 907 asy_get_bus_type(dev_info_t *devinfo) 908 { 909 char *prop; 910 int bustype; 911 912 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devinfo, 0, "device_type", 913 &prop) != DDI_PROP_SUCCESS && 914 ddi_prop_lookup_string(DDI_DEV_T_ANY, devinfo, 0, "bus-type", 915 &prop) != DDI_PROP_SUCCESS) { 916 dev_err(devinfo, CE_WARN, 917 "!%s: can't figure out device type for parent \"%s\"", 918 __func__, ddi_get_name(ddi_get_parent(devinfo))); 919 return (ASY_BUS_UNKNOWN); 920 } 921 922 if (strcmp(prop, "isa") == 0) 923 bustype = ASY_BUS_ISA; 924 else if (strcmp(prop, "pci") == 0) 925 bustype = ASY_BUS_PCI; 926 else if (strcmp(prop, "pciex") == 0) 927 return (ASY_BUS_PCI); 928 else 929 bustype = ASY_BUS_UNKNOWN; 930 931 ddi_prop_free(prop); 932 return (bustype); 933 } 934 935 static int 936 asy_get_io_regnum_pci(dev_info_t *devi, struct asycom *asy) 937 { 938 int reglen, nregs; 939 int regnum, i; 940 uint64_t size; 941 struct pci_phys_spec *reglist; 942 943 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 944 "reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) { 945 dev_err(devi, CE_WARN, "!%s: reg property" 946 " not found in devices property list", __func__); 947 return (-1); 948 } 949 950 regnum = -1; 951 nregs = reglen / sizeof (*reglist); 952 for (i = 0; i < nregs; i++) { 953 switch (reglist[i].pci_phys_hi & PCI_ADDR_MASK) { 954 case PCI_ADDR_IO: /* I/O bus reg property */ 955 if (regnum == -1) /* use only the first one */ 956 regnum = i; 957 break; 958 959 default: 960 break; 961 } 962 } 963 964 /* check for valid count of registers */ 965 if (regnum >= 0) { 966 size = ((uint64_t)reglist[regnum].pci_size_low) | 967 ((uint64_t)reglist[regnum].pci_size_hi) << 32; 968 if (size < 8) 969 regnum = -1; 970 } 971 kmem_free(reglist, reglen); 972 return (regnum); 973 } 974 975 static int 976 asy_get_io_regnum_isa(dev_info_t *devi, struct asycom *asy) 977 { 978 int regnum = -1; 979 int reglen, nregs; 980 struct { 981 uint_t bustype; 982 int base; 983 int size; 984 } *reglist; 985 986 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 987 "reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) { 988 dev_err(devi, CE_WARN, "!%s: reg property not found " 989 "in devices property list", __func__); 990 return (-1); 991 } 992 993 nregs = reglen / sizeof (*reglist); 994 995 /* 996 * Find the first I/O bus in the "reg" property. 997 */ 998 for (int i = 0; i < nregs && regnum == -1; i++) { 999 if (reglist[i].bustype == 1) { 1000 regnum = i; 1001 break; 1002 } 1003 } 1004 1005 /* check for valid count of registers */ 1006 if ((regnum < 0) || (reglist[regnum].size < 8)) 1007 regnum = -1; 1008 1009 kmem_free(reglist, reglen); 1010 1011 return (regnum); 1012 } 1013 1014 static int 1015 asy_get_io_regnum(dev_info_t *devinfo, struct asycom *asy) 1016 { 1017 switch (asy_get_bus_type(devinfo)) { 1018 case ASY_BUS_ISA: 1019 return (asy_get_io_regnum_isa(devinfo, asy)); 1020 case ASY_BUS_PCI: 1021 return (asy_get_io_regnum_pci(devinfo, asy)); 1022 default: 1023 return (-1); 1024 } 1025 } 1026 1027 static void 1028 asy_intr_free(struct asycom *asy) 1029 { 1030 int i; 1031 1032 for (i = 0; i < asy->asy_intr_cnt; i++) { 1033 if (asy->asy_inth[i] == NULL) 1034 break; 1035 1036 if ((asy->asy_intr_cap & DDI_INTR_FLAG_BLOCK) != 0) 1037 (void) ddi_intr_block_disable(&asy->asy_inth[i], 1); 1038 else 1039 (void) ddi_intr_disable(asy->asy_inth[i]); 1040 1041 (void) ddi_intr_remove_handler(asy->asy_inth[i]); 1042 (void) ddi_intr_free(asy->asy_inth[i]); 1043 } 1044 1045 kmem_free(asy->asy_inth, asy->asy_inth_sz); 1046 asy->asy_inth = NULL; 1047 asy->asy_inth_sz = 0; 1048 } 1049 1050 static int 1051 asy_intr_setup(struct asycom *asy, int intr_type) 1052 { 1053 int nintrs, navail, count; 1054 int ret; 1055 int i; 1056 1057 if (asy->asy_intr_types == 0) { 1058 ret = ddi_intr_get_supported_types(asy->asy_dip, 1059 &asy->asy_intr_types); 1060 if (ret != DDI_SUCCESS) { 1061 asyerror(asy, CE_WARN, 1062 "ddi_intr_get_supported_types failed"); 1063 return (ret); 1064 } 1065 } 1066 1067 if ((asy->asy_intr_types & intr_type) == 0) 1068 return (DDI_FAILURE); 1069 1070 ret = ddi_intr_get_nintrs(asy->asy_dip, intr_type, &nintrs); 1071 if (ret != DDI_SUCCESS) { 1072 asyerror(asy, CE_WARN, "ddi_intr_get_nintrs failed, type %d", 1073 intr_type); 1074 return (ret); 1075 } 1076 1077 if (nintrs < 1) { 1078 asyerror(asy, CE_WARN, "no interrupts of type %d", intr_type); 1079 return (DDI_FAILURE); 1080 } 1081 1082 ret = ddi_intr_get_navail(asy->asy_dip, intr_type, &navail); 1083 if (ret != DDI_SUCCESS) { 1084 asyerror(asy, CE_WARN, "ddi_intr_get_navail failed, type %d", 1085 intr_type); 1086 return (ret); 1087 } 1088 1089 if (navail < 1) { 1090 asyerror(asy, CE_WARN, "no available interrupts, type %d", 1091 intr_type); 1092 return (DDI_FAILURE); 1093 } 1094 1095 /* 1096 * Some PCI(e) RS232 adapters seem to support more than one interrupt, 1097 * but the asy driver really doesn't. 1098 */ 1099 asy->asy_inth_sz = sizeof (ddi_intr_handle_t); 1100 asy->asy_inth = kmem_zalloc(asy->asy_inth_sz, KM_SLEEP); 1101 ret = ddi_intr_alloc(asy->asy_dip, asy->asy_inth, intr_type, 0, 1, 1102 &count, 0); 1103 if (ret != DDI_SUCCESS) { 1104 asyerror(asy, CE_WARN, "ddi_intr_alloc failed, count %d, " 1105 "type %d", navail, intr_type); 1106 goto fail; 1107 } 1108 1109 if (count != 1) { 1110 asyerror(asy, CE_WARN, "ddi_intr_alloc returned not 1 but %d " 1111 "interrupts of type %d", count, intr_type); 1112 goto fail; 1113 } 1114 1115 asy->asy_intr_cnt = count; 1116 1117 ret = ddi_intr_get_pri(asy->asy_inth[0], &asy->asy_intr_pri); 1118 if (ret != DDI_SUCCESS) { 1119 asyerror(asy, CE_WARN, "ddi_intr_get_pri failed, type %d", 1120 intr_type); 1121 goto fail; 1122 } 1123 1124 for (i = 0; i < count; i++) { 1125 ret = ddi_intr_add_handler(asy->asy_inth[i], asyintr, 1126 (void *)asy, (void *)(uintptr_t)i); 1127 if (ret != DDI_SUCCESS) { 1128 asyerror(asy, CE_WARN, "ddi_intr_add_handler failed, " 1129 "int %d, type %d", i, intr_type); 1130 goto fail; 1131 } 1132 } 1133 1134 (void) ddi_intr_get_cap(asy->asy_inth[0], &asy->asy_intr_cap); 1135 1136 for (i = 0; i < count; i++) { 1137 if (asy->asy_intr_cap & DDI_INTR_FLAG_BLOCK) 1138 ret = ddi_intr_block_enable(&asy->asy_inth[i], 1); 1139 else 1140 ret = ddi_intr_enable(asy->asy_inth[i]); 1141 1142 if (ret != DDI_SUCCESS) { 1143 asyerror(asy, CE_WARN, 1144 "enabling interrupt %d failed, type %d", 1145 i, intr_type); 1146 goto fail; 1147 } 1148 } 1149 1150 asy->asy_intr_type = intr_type; 1151 return (DDI_SUCCESS); 1152 1153 fail: 1154 asy_intr_free(asy); 1155 return (ret); 1156 } 1157 1158 static void 1159 asy_softintr_free(struct asycom *asy) 1160 { 1161 (void) ddi_intr_remove_softint(asy->asy_soft_inth); 1162 } 1163 1164 static int 1165 asy_softintr_setup(struct asycom *asy) 1166 { 1167 int ret; 1168 1169 ret = ddi_intr_add_softint(asy->asy_dip, &asy->asy_soft_inth, 1170 ASY_SOFT_INT_PRI, asysoftintr, asy); 1171 if (ret != DDI_SUCCESS) { 1172 asyerror(asy, CE_WARN, "ddi_intr_add_softint failed"); 1173 return (ret); 1174 } 1175 1176 /* 1177 * This may seem pointless since we specified ASY_SOFT_INT_PRI above, 1178 * but then it's probably a good idea to consider the soft interrupt 1179 * priority an opaque value and don't hardcode any assumptions about 1180 * its actual value here. 1181 */ 1182 ret = ddi_intr_get_softint_pri(asy->asy_soft_inth, 1183 &asy->asy_soft_intr_pri); 1184 if (ret != DDI_SUCCESS) { 1185 asyerror(asy, CE_WARN, "ddi_intr_get_softint_pri failed"); 1186 return (ret); 1187 } 1188 1189 return (DDI_SUCCESS); 1190 } 1191 1192 1193 static int 1194 asy_resume(dev_info_t *devi) 1195 { 1196 struct asyncline *async; 1197 struct asycom *asy; 1198 int instance = ddi_get_instance(devi); /* find out which unit */ 1199 1200 #ifdef DEBUG 1201 if (asy_nosuspend) 1202 return (DDI_SUCCESS); 1203 #endif 1204 asy = ddi_get_soft_state(asy_soft_state, instance); 1205 if (asy == NULL) 1206 return (DDI_FAILURE); 1207 1208 mutex_enter(&asy->asy_soft_sr); 1209 mutex_enter(&asy->asy_excl); 1210 mutex_enter(&asy->asy_excl_hi); 1211 1212 async = asy->asy_priv; 1213 asy_disable_interrupts(asy, ASY_IER_ALL); 1214 if (asy_identify_chip(devi, asy) != DDI_SUCCESS) { 1215 mutex_exit(&asy->asy_excl_hi); 1216 mutex_exit(&asy->asy_excl); 1217 mutex_exit(&asy->asy_soft_sr); 1218 asyerror(asy, CE_WARN, "Cannot identify UART chip at %p", 1219 (void *)asy->asy_ioaddr); 1220 return (DDI_FAILURE); 1221 } 1222 asy->asy_flags &= ~ASY_DDI_SUSPENDED; 1223 if (async->async_flags & ASYNC_ISOPEN) { 1224 asy_program(asy, ASY_INIT); 1225 /* Kick off output */ 1226 if (async->async_ocnt > 0) { 1227 async_resume(async); 1228 } else { 1229 mutex_exit(&asy->asy_excl_hi); 1230 if (async->async_xmitblk) 1231 freeb(async->async_xmitblk); 1232 async->async_xmitblk = NULL; 1233 async_start(async); 1234 mutex_enter(&asy->asy_excl_hi); 1235 } 1236 asysetsoft(asy); 1237 } 1238 mutex_exit(&asy->asy_excl_hi); 1239 mutex_exit(&asy->asy_excl); 1240 mutex_exit(&asy->asy_soft_sr); 1241 1242 mutex_enter(&asy->asy_excl); 1243 if (async->async_flags & ASYNC_RESUME_BUFCALL) { 1244 async->async_wbufcid = bufcall(async->async_wbufcds, 1245 BPRI_HI, (void (*)(void *)) async_reioctl, 1246 (void *)(intptr_t)async->async_common->asy_unit); 1247 async->async_flags &= ~ASYNC_RESUME_BUFCALL; 1248 } 1249 async_process_suspq(asy); 1250 mutex_exit(&asy->asy_excl); 1251 return (DDI_SUCCESS); 1252 } 1253 1254 static int 1255 asy_suspend(struct asycom *asy) 1256 { 1257 struct asyncline *async = asy->asy_priv; 1258 unsigned i; 1259 uchar_t lsr; 1260 1261 #ifdef DEBUG 1262 if (asy_nosuspend) 1263 return (DDI_SUCCESS); 1264 #endif 1265 mutex_enter(&asy->asy_excl); 1266 1267 ASSERT(async->async_ops >= 0); 1268 while (async->async_ops > 0) 1269 cv_wait(&async->async_ops_cv, &asy->asy_excl); 1270 1271 async->async_flags |= ASYNC_DDI_SUSPENDED; 1272 1273 /* Wait for timed break and delay to complete */ 1274 while ((async->async_flags & (ASYNC_BREAK|ASYNC_DELAY))) { 1275 if (cv_wait_sig(&async->async_flags_cv, &asy->asy_excl) == 0) { 1276 async_process_suspq(asy); 1277 mutex_exit(&asy->asy_excl); 1278 return (DDI_FAILURE); 1279 } 1280 } 1281 1282 /* Clear untimed break */ 1283 if (async->async_flags & ASYNC_OUT_SUSPEND) 1284 async_resume_utbrk(async); 1285 1286 mutex_exit(&asy->asy_excl); 1287 1288 mutex_enter(&asy->asy_soft_sr); 1289 mutex_enter(&asy->asy_excl); 1290 if (async->async_wbufcid != 0) { 1291 bufcall_id_t bcid = async->async_wbufcid; 1292 async->async_wbufcid = 0; 1293 async->async_flags |= ASYNC_RESUME_BUFCALL; 1294 mutex_exit(&asy->asy_excl); 1295 unbufcall(bcid); 1296 mutex_enter(&asy->asy_excl); 1297 } 1298 mutex_enter(&asy->asy_excl_hi); 1299 1300 asy_disable_interrupts(asy, ASY_IER_ALL); 1301 asy->asy_flags |= ASY_DDI_SUSPENDED; 1302 1303 /* 1304 * Hardware interrupts are disabled we can drop our high level 1305 * lock and proceed. 1306 */ 1307 mutex_exit(&asy->asy_excl_hi); 1308 1309 /* Process remaining RX characters and RX errors, if any */ 1310 lsr = asy_get(asy, ASY_LSR); 1311 async_rxint(asy, lsr); 1312 1313 /* Wait for TX to drain */ 1314 for (i = 1000; i > 0; i--) { 1315 lsr = asy_get(asy, ASY_LSR); 1316 if ((lsr & (ASY_LSR_TEMT | ASY_LSR_THRE)) == 1317 (ASY_LSR_TEMT | ASY_LSR_THRE)) 1318 break; 1319 delay(drv_usectohz(10000)); 1320 } 1321 if (i == 0) 1322 asyerror(asy, CE_WARN, "transmitter wasn't drained before " 1323 "driver was suspended"); 1324 1325 mutex_exit(&asy->asy_excl); 1326 mutex_exit(&asy->asy_soft_sr); 1327 1328 return (DDI_SUCCESS); 1329 } 1330 1331 static int 1332 asydetach(dev_info_t *devi, ddi_detach_cmd_t cmd) 1333 { 1334 int instance; 1335 struct asycom *asy; 1336 1337 instance = ddi_get_instance(devi); /* find out which unit */ 1338 1339 asy = ddi_get_soft_state(asy_soft_state, instance); 1340 if (asy == NULL) 1341 return (DDI_FAILURE); 1342 1343 switch (cmd) { 1344 case DDI_DETACH: 1345 break; 1346 1347 case DDI_SUSPEND: 1348 return (asy_suspend(asy)); 1349 1350 default: 1351 return (DDI_FAILURE); 1352 } 1353 1354 ASY_DPRINTF(asy, ASY_DEBUG_INIT, "%s shutdown", asy_hw_name(asy)); 1355 1356 /* 1357 * Ensure that interrupts are disabled prior to destroying data and 1358 * mutexes that they depend on. 1359 */ 1360 if ((asy->asy_progress & ASY_PROGRESS_INT) != 0) 1361 asy_intr_free(asy); 1362 1363 if ((asy->asy_progress & ASY_PROGRESS_SOFTINT) != 0) 1364 asy_softintr_free(asy); 1365 1366 if ((asy->asy_progress & ASY_PROGRESS_ASYNC) != 0) { 1367 struct asyncline *async = asy->asy_priv; 1368 1369 asy->asy_priv = NULL; 1370 /* cancel DTR hold timeout */ 1371 if (async->async_dtrtid != 0) { 1372 (void) untimeout(async->async_dtrtid); 1373 async->async_dtrtid = 0; 1374 } 1375 cv_destroy(&async->async_flags_cv); 1376 kmem_free(async, sizeof (struct asyncline)); 1377 } 1378 1379 if ((asy->asy_progress & ASY_PROGRESS_MINOR) != 0) 1380 ddi_remove_minor_node(devi, NULL); 1381 1382 if ((asy->asy_progress & ASY_PROGRESS_MUTEX) != 0) { 1383 mutex_destroy(&asy->asy_excl); 1384 mutex_destroy(&asy->asy_excl_hi); 1385 mutex_destroy(&asy->asy_soft_lock); 1386 } 1387 1388 if ((asy->asy_progress & ASY_PROGRESS_REGS) != 0) 1389 ddi_regs_map_free(&asy->asy_iohandle); 1390 1391 ASY_DPRINTF(asy, ASY_DEBUG_INIT, "shutdown complete"); 1392 asy_soft_state_free(asy); 1393 1394 return (DDI_SUCCESS); 1395 } 1396 1397 /* 1398 * asyprobe 1399 * We don't bother probing for the hardware, as since Solaris 2.6, device 1400 * nodes are only created for auto-detected hardware or nodes explicitly 1401 * created by the user, e.g. via the DCA. However, we should check the 1402 * device node is at least vaguely usable, i.e. we have a block of 8 i/o 1403 * ports. This prevents attempting to attach to bogus serial ports which 1404 * some BIOSs still partially report when they are disabled in the BIOS. 1405 */ 1406 static int 1407 asyprobe(dev_info_t *devi) 1408 { 1409 return ((asy_get_io_regnum(devi, NULL) < 0) ? 1410 DDI_PROBE_FAILURE : DDI_PROBE_DONTCARE); 1411 } 1412 1413 static int 1414 asyattach(dev_info_t *devi, ddi_attach_cmd_t cmd) 1415 { 1416 int instance; 1417 int mcr; 1418 int ret; 1419 int regnum = 0; 1420 int i; 1421 struct asycom *asy; 1422 char name[ASY_MINOR_LEN]; 1423 int status; 1424 static ddi_device_acc_attr_t ioattr = { 1425 .devacc_attr_version = DDI_DEVICE_ATTR_V1, 1426 .devacc_attr_endian_flags = DDI_NEVERSWAP_ACC, 1427 .devacc_attr_dataorder = DDI_STRICTORDER_ACC, 1428 .devacc_attr_access = DDI_DEFAULT_ACC 1429 }; 1430 1431 switch (cmd) { 1432 case DDI_ATTACH: 1433 break; 1434 1435 case DDI_RESUME: 1436 return (asy_resume(devi)); 1437 1438 default: 1439 return (DDI_FAILURE); 1440 } 1441 1442 mutex_enter(&asy_glob_lock); 1443 if (com_ports == NULL) { /* need to initialize com_ports */ 1444 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, devi, 0, 1445 "motherboard-serial-ports", &com_ports, &num_com_ports) != 1446 DDI_PROP_SUCCESS) { 1447 /* Use our built-in COM[1234] values */ 1448 com_ports = (int *)standard_com_ports; 1449 num_com_ports = sizeof (standard_com_ports) / 1450 sizeof (standard_com_ports[0]); 1451 } 1452 if (num_com_ports > 10) { 1453 /* We run out of single digits for device properties */ 1454 num_com_ports = 10; 1455 cmn_err(CE_WARN, 1456 "%s: more than %d motherboard-serial-ports", 1457 asy_info.mi_idname, num_com_ports); 1458 } 1459 } 1460 mutex_exit(&asy_glob_lock); 1461 1462 instance = ddi_get_instance(devi); /* find out which unit */ 1463 ret = ddi_soft_state_zalloc(asy_soft_state, instance); 1464 if (ret != DDI_SUCCESS) 1465 return (DDI_FAILURE); 1466 asy = ddi_get_soft_state(asy_soft_state, instance); 1467 1468 asy->asy_dip = devi; 1469 #ifdef DEBUG 1470 asy->asy_debug = debug; 1471 #endif 1472 asy->asy_unit = instance; 1473 1474 regnum = asy_get_io_regnum(devi, asy); 1475 1476 if (regnum < 0 || 1477 ddi_regs_map_setup(devi, regnum, (caddr_t *)&asy->asy_ioaddr, 1478 (offset_t)0, (offset_t)0, &ioattr, &asy->asy_iohandle) 1479 != DDI_SUCCESS) { 1480 asyerror(asy, CE_WARN, "could not map UART registers @ %p", 1481 (void *)asy->asy_ioaddr); 1482 goto fail; 1483 } 1484 1485 asy->asy_progress |= ASY_PROGRESS_REGS; 1486 1487 ASY_DPRINTF(asy, ASY_DEBUG_INIT, "UART @ %p", (void *)asy->asy_ioaddr); 1488 1489 /* 1490 * Lookup the i/o address to see if this is a standard COM port 1491 * in which case we assign it the correct tty[a-d] to match the 1492 * COM port number, or some other i/o address in which case it 1493 * will be assigned /dev/term/[0123...] in some rather arbitrary 1494 * fashion. 1495 */ 1496 for (i = 0; i < num_com_ports; i++) { 1497 if (asy->asy_ioaddr == (uint8_t *)(uintptr_t)com_ports[i]) { 1498 asy->asy_com_port = i + 1; 1499 break; 1500 } 1501 } 1502 1503 /* 1504 * It appears that there was async hardware that on reset did not clear 1505 * IER. Hence when we enable interrupts, this hardware would cause the 1506 * system to hang if there was input available. 1507 * 1508 * Don't use asy_disable_interrupts() as the mutexes haven't been 1509 * initialized yet. 1510 */ 1511 ddi_put8(asy->asy_iohandle, 1512 asy->asy_ioaddr + asy_reg_table[ASY_IER].asy_reg_off, 0); 1513 1514 /* 1515 * Establish default settings: 1516 * - use RTS/DTR after open 1517 * - 8N1 data format 1518 * - 9600 baud 1519 */ 1520 asy->asy_mcr |= ASY_MCR_RTS | ASY_MCR_DTR; 1521 asy->asy_lcr = ASY_LCR_STOP1 | ASY_LCR_BITS8; 1522 asy->asy_bidx = B9600; 1523 asy->asy_fifo_buf = 1; 1524 asy->asy_use_fifo = ASY_FCR_FIFO_OFF; 1525 1526 #ifdef DEBUG 1527 asy->asy_msint_cnt = 0; /* # of times in async_msint */ 1528 #endif 1529 mcr = 0; /* don't enable until open */ 1530 1531 if (asy->asy_com_port != 0) { 1532 /* 1533 * For motherboard ports, emulate tty eeprom properties. 1534 * Actually, we can't tell if a port is motherboard or not, 1535 * so for "motherboard ports", read standard DOS COM ports. 1536 */ 1537 switch (asy_getproperty(devi, asy, "ignore-cd")) { 1538 case 0: /* *-ignore-cd=False */ 1539 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 1540 "clear ASY_IGNORE_CD"); 1541 asy->asy_flags &= ~ASY_IGNORE_CD; /* wait for cd */ 1542 break; 1543 case 1: /* *-ignore-cd=True */ 1544 /*FALLTHRU*/ 1545 default: /* *-ignore-cd not defined */ 1546 /* 1547 * We set rather silly defaults of soft carrier on 1548 * and DTR/RTS raised here because it might be that 1549 * one of the motherboard ports is the system console. 1550 */ 1551 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 1552 "set ASY_IGNORE_CD, set RTS & DTR"); 1553 mcr = asy->asy_mcr; /* rts/dtr on */ 1554 asy->asy_flags |= ASY_IGNORE_CD; /* ignore cd */ 1555 break; 1556 } 1557 1558 /* Property for not raising DTR/RTS */ 1559 switch (asy_getproperty(devi, asy, "rts-dtr-off")) { 1560 case 0: /* *-rts-dtr-off=False */ 1561 asy->asy_flags |= ASY_RTS_DTR_OFF; /* OFF */ 1562 mcr = asy->asy_mcr; /* rts/dtr on */ 1563 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 1564 "ASY_RTS_DTR_OFF set and DTR & RTS set"); 1565 break; 1566 case 1: /* *-rts-dtr-off=True */ 1567 /*FALLTHRU*/ 1568 default: /* *-rts-dtr-off undefined */ 1569 break; 1570 } 1571 1572 /* Parse property for tty modes */ 1573 asy_parse_mode(devi, asy); 1574 } else { 1575 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 1576 "clear ASY_IGNORE_CD, clear RTS & DTR"); 1577 asy->asy_flags &= ~ASY_IGNORE_CD; /* wait for cd */ 1578 } 1579 1580 /* 1581 * Install per instance software interrupt handler. 1582 */ 1583 if (asy_softintr_setup(asy) != DDI_SUCCESS) { 1584 asyerror(asy, CE_WARN, "Cannot set soft interrupt"); 1585 goto fail; 1586 } 1587 1588 asy->asy_progress |= ASY_PROGRESS_SOFTINT; 1589 1590 /* 1591 * Install interrupt handler for this device. 1592 */ 1593 if ((asy_intr_setup(asy, DDI_INTR_TYPE_MSIX) != DDI_SUCCESS) && 1594 (asy_intr_setup(asy, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) && 1595 (asy_intr_setup(asy, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS)) { 1596 asyerror(asy, CE_WARN, "Cannot set device interrupt"); 1597 goto fail; 1598 } 1599 1600 asy->asy_progress |= ASY_PROGRESS_INT; 1601 1602 /* 1603 * Initialize mutexes before accessing the hardware 1604 */ 1605 mutex_init(&asy->asy_soft_lock, NULL, MUTEX_DRIVER, 1606 DDI_INTR_PRI(asy->asy_soft_intr_pri)); 1607 mutex_init(&asy->asy_soft_sr, NULL, MUTEX_DRIVER, 1608 DDI_INTR_PRI(asy->asy_soft_intr_pri)); 1609 1610 mutex_init(&asy->asy_excl, NULL, MUTEX_DRIVER, NULL); 1611 mutex_init(&asy->asy_excl_hi, NULL, MUTEX_DRIVER, 1612 DDI_INTR_PRI(asy->asy_intr_pri)); 1613 1614 asy->asy_progress |= ASY_PROGRESS_MUTEX; 1615 1616 mutex_enter(&asy->asy_excl); 1617 mutex_enter(&asy->asy_excl_hi); 1618 1619 if (asy_identify_chip(devi, asy) != DDI_SUCCESS) { 1620 asyerror(asy, CE_WARN, "Cannot identify UART chip at %p", 1621 (void *)asy->asy_ioaddr); 1622 goto fail; 1623 } 1624 1625 asy_disable_interrupts(asy, ASY_IER_ALL); 1626 asy_put(asy, ASY_LCR, asy->asy_lcr); 1627 asy_set_baudrate(asy, asy->asy_bidx); 1628 asy_put(asy, ASY_MCR, mcr); 1629 1630 mutex_exit(&asy->asy_excl_hi); 1631 mutex_exit(&asy->asy_excl); 1632 1633 asyinit(asy); /* initialize the asyncline structure */ 1634 asy->asy_progress |= ASY_PROGRESS_ASYNC; 1635 1636 /* create minor device nodes for this device */ 1637 if (asy->asy_com_port != 0) { 1638 /* 1639 * For DOS COM ports, add letter suffix so 1640 * devfsadm can create correct link names. 1641 */ 1642 name[0] = asy->asy_com_port + 'a' - 1; 1643 name[1] = '\0'; 1644 } else { 1645 /* 1646 * asy port which isn't a standard DOS COM 1647 * port gets a numeric name based on instance 1648 */ 1649 (void) snprintf(name, ASY_MINOR_LEN, "%d", instance); 1650 } 1651 status = ddi_create_minor_node(devi, name, S_IFCHR, instance, 1652 asy->asy_com_port != 0 ? DDI_NT_SERIAL_MB : DDI_NT_SERIAL, 0); 1653 if (status == DDI_SUCCESS) { 1654 (void) strcat(name, ",cu"); 1655 status = ddi_create_minor_node(devi, name, S_IFCHR, 1656 OUTLINE | instance, 1657 asy->asy_com_port != 0 ? DDI_NT_SERIAL_MB_DO : 1658 DDI_NT_SERIAL_DO, 0); 1659 } 1660 1661 if (status != DDI_SUCCESS) 1662 goto fail; 1663 1664 asy->asy_progress |= ASY_PROGRESS_MINOR; 1665 1666 /* 1667 * Fill in the polled I/O structure. 1668 */ 1669 asy->polledio.cons_polledio_version = CONSPOLLEDIO_V0; 1670 asy->polledio.cons_polledio_argument = (cons_polledio_arg_t)asy; 1671 asy->polledio.cons_polledio_putchar = asyputchar; 1672 asy->polledio.cons_polledio_getchar = asygetchar; 1673 asy->polledio.cons_polledio_ischar = asyischar; 1674 asy->polledio.cons_polledio_enter = NULL; 1675 asy->polledio.cons_polledio_exit = NULL; 1676 1677 ddi_report_dev(devi); 1678 ASY_DPRINTF(asy, ASY_DEBUG_INIT, "done"); 1679 return (DDI_SUCCESS); 1680 1681 fail: 1682 (void) asydetach(devi, DDI_DETACH); 1683 return (DDI_FAILURE); 1684 } 1685 1686 static int 1687 asyinfo(dev_info_t *dip __unused, ddi_info_cmd_t infocmd, void *arg, 1688 void **result) 1689 { 1690 dev_t dev = (dev_t)arg; 1691 int instance, error; 1692 struct asycom *asy; 1693 1694 instance = UNIT(dev); 1695 1696 switch (infocmd) { 1697 case DDI_INFO_DEVT2DEVINFO: 1698 asy = ddi_get_soft_state(asy_soft_state, instance); 1699 if ((asy == NULL) || (asy->asy_dip == NULL)) 1700 error = DDI_FAILURE; 1701 else { 1702 *result = (void *) asy->asy_dip; 1703 error = DDI_SUCCESS; 1704 } 1705 break; 1706 case DDI_INFO_DEVT2INSTANCE: 1707 *result = (void *)(intptr_t)instance; 1708 error = DDI_SUCCESS; 1709 break; 1710 default: 1711 error = DDI_FAILURE; 1712 } 1713 return (error); 1714 } 1715 1716 /* asy_getproperty -- walk through all name variants until we find a match */ 1717 1718 static int 1719 asy_getproperty(dev_info_t *devi, struct asycom *asy, const char *property) 1720 { 1721 int len; 1722 int ret; 1723 char letter = asy->asy_com_port + 'a' - 1; /* for ttya */ 1724 char number = asy->asy_com_port + '0'; /* for COM1 */ 1725 char val[40]; 1726 char name[40]; 1727 1728 /* Property for ignoring DCD */ 1729 (void) sprintf(name, "tty%c-%s", letter, property); 1730 len = sizeof (val); 1731 ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len); 1732 if (ret != DDI_PROP_SUCCESS) { 1733 (void) sprintf(name, "com%c-%s", number, property); 1734 len = sizeof (val); 1735 ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len); 1736 } 1737 if (ret != DDI_PROP_SUCCESS) { 1738 (void) sprintf(name, "tty0%c-%s", number, property); 1739 len = sizeof (val); 1740 ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len); 1741 } 1742 if (ret != DDI_PROP_SUCCESS) { 1743 (void) sprintf(name, "port-%c-%s", letter, property); 1744 len = sizeof (val); 1745 ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len); 1746 } 1747 if (ret != DDI_PROP_SUCCESS) 1748 return (-1); /* property non-existant */ 1749 if (val[0] == 'f' || val[0] == 'F' || val[0] == '0') 1750 return (0); /* property false/0 */ 1751 return (1); /* property true/!0 */ 1752 } 1753 1754 /* asy_soft_state_free - local wrapper for ddi_soft_state_free(9F) */ 1755 1756 static void 1757 asy_soft_state_free(struct asycom *asy) 1758 { 1759 if (asy->asy_priv != NULL) { 1760 kmem_free(asy->asy_priv, sizeof (struct asyncline)); 1761 asy->asy_priv = NULL; 1762 } 1763 ddi_soft_state_free(asy_soft_state, asy->asy_unit); 1764 } 1765 1766 static char * 1767 asy_hw_name(struct asycom *asy) 1768 { 1769 switch (asy->asy_hwtype) { 1770 case ASY_8250A: 1771 return ("8250A/16450"); 1772 case ASY_16550: 1773 return ("16550"); 1774 case ASY_16550A: 1775 return ("16550A"); 1776 case ASY_16650: 1777 return ("16650"); 1778 case ASY_16750: 1779 return ("16750"); 1780 case ASY_16950: 1781 return ("16950"); 1782 } 1783 1784 ASY_DPRINTF(asy, ASY_DEBUG_INIT, "unknown asy_hwtype: %d", 1785 asy->asy_hwtype); 1786 return ("?"); 1787 } 1788 1789 static boolean_t 1790 asy_is_devid(struct asycom *asy, char *venprop, char *devprop, 1791 int venid, int devid) 1792 { 1793 if (ddi_prop_get_int(DDI_DEV_T_ANY, asy->asy_dip, DDI_PROP_DONTPASS, 1794 venprop, 0) != venid) { 1795 return (B_FALSE); 1796 } 1797 1798 if (ddi_prop_get_int(DDI_DEV_T_ANY, asy->asy_dip, DDI_PROP_DONTPASS, 1799 devprop, 0) != devid) { 1800 return (B_FALSE); 1801 } 1802 1803 return (B_FALSE); 1804 } 1805 1806 static void 1807 asy_check_loopback(struct asycom *asy) 1808 { 1809 if (asy_get_bus_type(asy->asy_dip) != ASY_BUS_PCI) 1810 return; 1811 1812 /* Check if this is a Agere/Lucent Venus PCI modem chipset. */ 1813 if (asy_is_devid(asy, "vendor-id", "device-id", 0x11c1, 0x0480) || 1814 asy_is_devid(asy, "subsystem-vendor-id", "subsystem-id", 0x11c1, 1815 0x0480)) 1816 asy->asy_flags2 |= ASY2_NO_LOOPBACK; 1817 } 1818 1819 static int 1820 asy_identify_chip(dev_info_t *devi, struct asycom *asy) 1821 { 1822 int isr, lsr, mcr, spr; 1823 dev_t dev; 1824 uint_t hwtype; 1825 1826 /* 1827 * Initially, we'll assume we have the highest supported chip model 1828 * until we find out what we actually have. 1829 */ 1830 asy->asy_hwtype = ASY_MAXCHIP; 1831 1832 /* 1833 * First, see if we can even do the loopback check, which may not work 1834 * on certain hardware. 1835 */ 1836 asy_check_loopback(asy); 1837 1838 if (asy_scr_test) { 1839 /* Check that the scratch register works. */ 1840 1841 /* write to scratch register */ 1842 asy_put(asy, ASY_SPR, ASY_SPR_TEST); 1843 /* make sure that pattern doesn't just linger on the bus */ 1844 asy_put(asy, ASY_FCR, 0x00); 1845 /* read data back from scratch register */ 1846 spr = asy_get(asy, ASY_SPR); 1847 if (spr != ASY_SPR_TEST) { 1848 /* 1849 * Scratch register not working. 1850 * Probably not an async chip. 1851 * 8250 and 8250B don't have scratch registers, 1852 * but only worked in ancient PC XT's anyway. 1853 */ 1854 asyerror(asy, CE_WARN, "UART @ %p " 1855 "scratch register: expected 0x5a, got 0x%02x", 1856 (void *)asy->asy_ioaddr, spr); 1857 return (DDI_FAILURE); 1858 } 1859 } 1860 /* 1861 * Use 16550 fifo reset sequence specified in NS application 1862 * note. Disable fifos until chip is initialized. 1863 */ 1864 asy_put(asy, ASY_FCR, 0x00); /* disable */ 1865 asy_put(asy, ASY_FCR, ASY_FCR_FIFO_EN); /* enable */ 1866 asy_put(asy, ASY_FCR, ASY_FCR_FIFO_EN | ASY_FCR_RHR_FL); /* reset */ 1867 if (asymaxchip >= ASY_16650 && asy_scr_test) { 1868 /* 1869 * Reset 16650 enhanced regs also, in case we have one of these 1870 */ 1871 asy_put(asy, ASY_EFR, 0); 1872 } 1873 1874 /* 1875 * See what sort of FIFO we have. 1876 * Try enabling it and see what chip makes of this. 1877 */ 1878 1879 asy->asy_fifor = 0; 1880 if (asymaxchip >= ASY_16550A) 1881 asy->asy_fifor |= 1882 ASY_FCR_FIFO_EN | ASY_FCR_DMA | (asy_trig_level & 0xff); 1883 1884 /* 1885 * On the 16750, FCR[5] enables the 64 byte FIFO. FCR[5] can only be set 1886 * while LCR[7] = 1 (DLAB), which is taken care of by asy_reset_fifo(). 1887 */ 1888 if (asymaxchip >= ASY_16750) 1889 asy->asy_fifor |= ASY_FCR_FIFO64; 1890 1891 asy_reset_fifo(asy, ASY_FCR_THR_FL | ASY_FCR_RHR_FL); 1892 1893 mcr = asy_get(asy, ASY_MCR); 1894 isr = asy_get(asy, ASY_ISR); 1895 1896 /* 1897 * Note we get 0xff if chip didn't return us anything, 1898 * e.g. if there's no chip there. 1899 */ 1900 if (isr == 0xff) { 1901 asyerror(asy, CE_WARN, "UART @ %p interrupt register: got 0xff", 1902 (void *)asy->asy_ioaddr); 1903 return (DDI_FAILURE); 1904 } 1905 1906 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, 1907 "probe fifo FIFOR=0x%02x ISR=0x%02x MCR=0x%02x", 1908 asy->asy_fifor | ASY_FCR_THR_FL | ASY_FCR_RHR_FL, isr, mcr); 1909 1910 /* 1911 * Detect the chip type by comparing ISR[7,6] and ISR[5]. 1912 * 1913 * When the FIFOs are enabled by setting FCR[0], ISR[7,6] read as 1. 1914 * Additionally on a 16750, the 64 byte FIFOs are enabled by setting 1915 * FCR[5], and ISR[5] will read as 1, too. 1916 * 1917 * We will check later whether we have a 16650, which requires EFR[4]=1 1918 * to enable its deeper FIFOs and extra features. It does not use FCR[5] 1919 * and ISR[5] to enable deeper FIFOs like the 16750 does. 1920 */ 1921 switch (isr & (ASY_ISR_FIFOEN | ASY_ISR_FIFO64)) { 1922 case 0x40: /* 16550 with broken FIFOs */ 1923 hwtype = ASY_16550; 1924 asy->asy_fifor = 0; 1925 break; 1926 1927 case ASY_ISR_FIFOEN: /* 16550A with working FIFOs */ 1928 hwtype = ASY_16550A; 1929 asy->asy_fifo_buf = 16; 1930 asy->asy_use_fifo = ASY_FCR_FIFO_EN; 1931 asy->asy_fifor &= ~ASY_FCR_FIFO64; 1932 break; 1933 1934 case ASY_ISR_FIFOEN | ASY_ISR_FIFO64: /* 16750 with 64byte FIFOs */ 1935 hwtype = ASY_16750; 1936 asy->asy_fifo_buf = 64; 1937 asy->asy_use_fifo = ASY_FCR_FIFO_EN; 1938 break; 1939 1940 default: /* 8250A/16450 without FIFOs */ 1941 hwtype = ASY_8250A; 1942 asy->asy_fifor = 0; 1943 } 1944 1945 if (hwtype > asymaxchip) { 1946 asyerror(asy, CE_WARN, "UART @ %p " 1947 "unexpected probe result: " 1948 "FCR=0x%02x ISR=0x%02x MCR=0x%02x", 1949 (void *)asy->asy_ioaddr, 1950 asy->asy_fifor | ASY_FCR_THR_FL | ASY_FCR_RHR_FL, isr, mcr); 1951 return (DDI_FAILURE); 1952 } 1953 1954 /* 1955 * Now reset the FIFO operation appropriate for the chip type. 1956 * Note we must call asy_reset_fifo() before any possible 1957 * downgrade of the asy->asy_hwtype, or it may not disable 1958 * the more advanced features we specifically want downgraded. 1959 */ 1960 asy_reset_fifo(asy, 0); 1961 1962 /* 1963 * Check for Exar/Startech ST16C650 or newer, which will still look like 1964 * a 16550A until we enable its enhanced mode. 1965 */ 1966 if (hwtype >= ASY_16550A && asymaxchip >= ASY_16650 && 1967 asy_scr_test) { 1968 /* 1969 * Write the XOFF2 register, which shadows SPR on the 16650. 1970 * On other chips, SPR will be overwritten. 1971 */ 1972 asy_put(asy, ASY_XOFF2, 0); 1973 1974 /* read back scratch register */ 1975 spr = asy_get(asy, ASY_SPR); 1976 1977 if (spr == ASY_SPR_TEST) { 1978 /* looks like we have an ST16650 -- enable it */ 1979 hwtype = ASY_16650; 1980 asy_put(asy, ASY_EFR, ASY_EFR_ENH_EN); 1981 1982 /* 1983 * Some 16650-compatible chips are also compatible with 1984 * the 16750 and have deeper FIFOs, which we may have 1985 * detected above. Don't downgrade the FIFO size. 1986 */ 1987 if (asy->asy_fifo_buf < 32) 1988 asy->asy_fifo_buf = 32; 1989 1990 /* 1991 * Use a 24 byte transmit FIFO trigger only if were 1992 * allowed to use >16 transmit FIFO depth by the 1993 * global tunable. 1994 */ 1995 if (asy_max_tx_fifo >= asy->asy_fifo_buf) 1996 asy->asy_fifor |= ASY_FCR_THR_TRIG_24; 1997 asy_reset_fifo(asy, 0); 1998 } 1999 } 2000 2001 /* 2002 * If we think we got a 16650, we may actually have a 16950, so check 2003 * for that. 2004 */ 2005 if (hwtype >= ASY_16650 && asymaxchip >= ASY_16950) { 2006 uint8_t ier, asr; 2007 2008 /* 2009 * First, clear IER and read it back. That should be a no-op as 2010 * either asyattach() or asy_resume() disabled all interrupts 2011 * before we were called. 2012 */ 2013 asy_put(asy, ASY_IER, 0); 2014 ier = asy_get(asy, ASY_IER); 2015 if (ier != 0) { 2016 dev_err(asy->asy_dip, CE_WARN, "!%s: UART @ %p " 2017 "interrupt enable register: got 0x%02x", __func__, 2018 (void *)asy->asy_ioaddr, ier); 2019 return (DDI_FAILURE); 2020 } 2021 2022 /* 2023 * Next, try to read ASR, which shares the register offset with 2024 * IER. ASR can only be read if the ASR enable bit is set in 2025 * ACR, which itself is an indexed registers. This is taken care 2026 * of by asy_get(). 2027 * 2028 * There are a few bits in ASR which should be 1 at this point, 2029 * definitely the TX idle bit (ASR[7]) and also the FIFO size 2030 * bit (ASR[6]) since we've done everything we can to enable any 2031 * deeper FIFO support. 2032 * 2033 * Thus if we read back ASR as 0, we failed to read it, and this 2034 * isn't the chip we're looking for. 2035 */ 2036 asr = asy_get(asy, ASY_ASR); 2037 2038 if (asr != ier) { 2039 hwtype = ASY_16950; 2040 2041 if ((asr & ASY_ASR_FIFOSZ) != 0) 2042 asy->asy_fifo_buf = 128; 2043 else 2044 asy->asy_fifo_buf = 16; 2045 2046 asy_reset_fifo(asy, 0); 2047 2048 /* 2049 * Enable 16950 specific trigger level registers. Set 2050 * DTR pin to be compatible to 16450, 16550, and 16750. 2051 */ 2052 asy->asy_acr = ASY_ACR_TRIG | ASY_ACR_DTR_NORM; 2053 asy_put(asy, ASY_ACR, asy->asy_acr); 2054 2055 /* Set half the FIFO size as receive trigger level. */ 2056 asy_put(asy, ASY_RTL, asy->asy_fifo_buf/2); 2057 2058 /* 2059 * Set the transmit trigger level to 1. 2060 * 2061 * While one would expect that any transmit trigger 2062 * level would work (the 16550 uses a hardwired level 2063 * of 16), in my tests with a 16950 compatible chip 2064 * (MosChip 9912) I would never see a TX interrupt 2065 * on any transmit trigger level > 1. 2066 */ 2067 asy_put(asy, ASY_TTL, 1); 2068 2069 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "ASR 0x%02x", asr); 2070 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "RFL 0x%02x", 2071 asy_get(asy, ASY_RFL)); 2072 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "TFL 0x%02x", 2073 asy_get(asy, ASY_TFL)); 2074 2075 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "ACR 0x%02x", 2076 asy_get(asy, ASY_ACR)); 2077 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "CPR 0x%02x", 2078 asy_get(asy, ASY_CPR)); 2079 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "TCR 0x%02x", 2080 asy_get(asy, ASY_TCR)); 2081 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "CKS 0x%02x", 2082 asy_get(asy, ASY_CKS)); 2083 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "TTL 0x%02x", 2084 asy_get(asy, ASY_TTL)); 2085 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "RTL 0x%02x", 2086 asy_get(asy, ASY_RTL)); 2087 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "FCL 0x%02x", 2088 asy_get(asy, ASY_FCL)); 2089 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "FCH 0x%02x", 2090 asy_get(asy, ASY_FCH)); 2091 2092 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, 2093 "Chip ID: %02x%02x%02x,%02x", 2094 asy_get(asy, ASY_ID1), asy_get(asy, ASY_ID2), 2095 asy_get(asy, ASY_ID3), asy_get(asy, ASY_REV)); 2096 2097 } 2098 } 2099 2100 asy->asy_hwtype = hwtype; 2101 2102 /* 2103 * If we think we might have a FIFO larger than 16 characters, 2104 * measure FIFO size and check it against expected. 2105 */ 2106 if (asy_fifo_test > 0 && 2107 !(asy->asy_flags2 & ASY2_NO_LOOPBACK) && 2108 (asy->asy_fifo_buf > 16 || 2109 (asy_fifo_test > 1 && asy->asy_use_fifo == ASY_FCR_FIFO_EN) || 2110 ASY_DEBUG(asy, ASY_DEBUG_CHIP))) { 2111 int i; 2112 2113 /* Set baud rate to 57600 (fairly arbitrary choice) */ 2114 asy_set_baudrate(asy, B57600); 2115 /* Set 8 bits, 1 stop bit */ 2116 asy_put(asy, ASY_LCR, ASY_LCR_STOP1 | ASY_LCR_BITS8); 2117 /* Set loopback mode */ 2118 asy_put(asy, ASY_MCR, ASY_MCR_LOOPBACK); 2119 2120 /* Overfill fifo */ 2121 for (i = 0; i < asy->asy_fifo_buf * 2; i++) { 2122 asy_put(asy, ASY_THR, i); 2123 } 2124 /* 2125 * Now there's an interesting question here about which 2126 * FIFO we're testing the size of, RX or TX. We just 2127 * filled the TX FIFO much faster than it can empty, 2128 * although it is possible one or two characters may 2129 * have gone from it to the TX shift register. 2130 * We wait for enough time for all the characters to 2131 * move into the RX FIFO and any excess characters to 2132 * have been lost, and then read all the RX FIFO. So 2133 * the answer we finally get will be the size which is 2134 * the MIN(RX FIFO,(TX FIFO + 1 or 2)). The critical 2135 * one is actually the TX FIFO, because if we overfill 2136 * it in normal operation, the excess characters are 2137 * lost with no warning. 2138 */ 2139 /* 2140 * Wait for characters to move into RX FIFO. 2141 * In theory, 200 * asy->asy_fifo_buf * 2 should be 2142 * enough. However, in practice it isn't always, so we 2143 * increase to 400 so some slow 16550A's finish, and we 2144 * increase to 3 so we spot more characters coming back 2145 * than we sent, in case that should ever happen. 2146 */ 2147 delay(drv_usectohz(400 * asy->asy_fifo_buf * 3)); 2148 2149 /* Now see how many characters we can read back */ 2150 for (i = 0; i < asy->asy_fifo_buf * 3; i++) { 2151 lsr = asy_get(asy, ASY_LSR); 2152 if (!(lsr & ASY_LSR_DR)) 2153 break; /* FIFO emptied */ 2154 (void) asy_get(asy, ASY_RHR); /* lose another */ 2155 } 2156 2157 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, 2158 "FIFO size: expected=%d, measured=%d", 2159 asy->asy_fifo_buf, i); 2160 2161 hwtype = asy->asy_hwtype; 2162 if (i < asy->asy_fifo_buf) { 2163 /* 2164 * FIFO is somewhat smaller than we anticipated. 2165 * If we have 16 characters usable, then this 2166 * UART will probably work well enough in 2167 * 16550A mode. If less than 16 characters, 2168 * then we'd better not use it at all. 2169 * UARTs with busted FIFOs do crop up. 2170 */ 2171 if (i >= 16 && asy->asy_fifo_buf >= 16) { 2172 /* fall back to a 16550A */ 2173 hwtype = ASY_16550A; 2174 asy->asy_fifo_buf = 16; 2175 asy->asy_fifor &= 2176 ~(ASY_FCR_THR_TR0 | ASY_FCR_THR_TR1); 2177 } else { 2178 /* fall back to no FIFO at all */ 2179 hwtype = ASY_16550; 2180 asy->asy_fifo_buf = 1; 2181 asy->asy_use_fifo = ASY_FCR_FIFO_OFF; 2182 asy->asy_fifor = 0; 2183 } 2184 } else if (i > asy->asy_fifo_buf) { 2185 /* 2186 * The FIFO is larger than expected. Use it if it is 2187 * a power of 2. 2188 */ 2189 if (ISP2(i)) 2190 asy->asy_fifo_buf = i; 2191 } 2192 2193 /* 2194 * We will need to reprogram the FIFO if we changed 2195 * our mind about how to drive it above, and in any 2196 * case, it would be a good idea to flush any garbage 2197 * out incase the loopback test left anything behind. 2198 * Again as earlier above, we must call asy_reset_fifo() 2199 * before any possible downgrade of asy->asy_hwtype. 2200 */ 2201 if (asy->asy_hwtype >= ASY_16650 && hwtype < ASY_16650) { 2202 /* Disable 16650 enhanced mode */ 2203 asy_put(asy, ASY_EFR, 0); 2204 } 2205 asy_reset_fifo(asy, ASY_FCR_THR_FL | ASY_FCR_RHR_FL); 2206 asy->asy_hwtype = hwtype; 2207 2208 /* Clear loopback mode and restore DTR/RTS */ 2209 asy_put(asy, ASY_MCR, mcr); 2210 } 2211 2212 ASY_DPRINTF(asy, ASY_DEBUG_CHIP, "%s @ %p", 2213 asy_hw_name(asy), (void *)asy->asy_ioaddr); 2214 2215 /* Make UART type visible in device tree for prtconf, etc */ 2216 dev = makedevice(DDI_MAJOR_T_UNKNOWN, asy->asy_unit); 2217 (void) ddi_prop_update_string(dev, devi, "uart", asy_hw_name(asy)); 2218 2219 if (asy->asy_hwtype == ASY_16550) /* for broken 16550's, */ 2220 asy->asy_hwtype = ASY_8250A; /* drive them as 8250A */ 2221 2222 return (DDI_SUCCESS); 2223 } 2224 2225 /* 2226 * asyinit() initializes the TTY protocol-private data for this channel 2227 * before enabling the interrupts. 2228 */ 2229 static void 2230 asyinit(struct asycom *asy) 2231 { 2232 struct asyncline *async; 2233 2234 asy->asy_priv = kmem_zalloc(sizeof (struct asyncline), KM_SLEEP); 2235 async = asy->asy_priv; 2236 mutex_enter(&asy->asy_excl); 2237 async->async_common = asy; 2238 cv_init(&async->async_flags_cv, NULL, CV_DRIVER, NULL); 2239 mutex_exit(&asy->asy_excl); 2240 } 2241 2242 static int 2243 asyopen(queue_t *rq, dev_t *dev, int flag, int sflag __unused, cred_t *cr) 2244 { 2245 struct asycom *asy; 2246 struct asyncline *async; 2247 int unit; 2248 int len; 2249 struct termios *termiosp; 2250 2251 unit = UNIT(*dev); 2252 asy = ddi_get_soft_state(asy_soft_state, unit); 2253 if (asy == NULL) 2254 return (ENXIO); /* unit not configured */ 2255 ASY_DPRINTF(asy, ASY_DEBUG_INIT, "enter"); 2256 async = asy->asy_priv; 2257 mutex_enter(&asy->asy_excl); 2258 2259 again: 2260 mutex_enter(&asy->asy_excl_hi); 2261 2262 /* 2263 * Block waiting for carrier to come up, unless this is a no-delay open. 2264 */ 2265 if (!(async->async_flags & ASYNC_ISOPEN)) { 2266 /* 2267 * Set the default termios settings (cflag). 2268 * Others are set in ldterm. 2269 */ 2270 mutex_exit(&asy->asy_excl_hi); 2271 2272 if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 2273 0, "ttymodes", 2274 (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS && 2275 len == sizeof (struct termios)) { 2276 async->async_ttycommon.t_cflag = termiosp->c_cflag; 2277 kmem_free(termiosp, len); 2278 } else { 2279 asyerror(asy, CE_WARN, 2280 "couldn't get ttymodes property"); 2281 } 2282 mutex_enter(&asy->asy_excl_hi); 2283 2284 /* eeprom mode support - respect properties */ 2285 if (asy->asy_cflag) 2286 async->async_ttycommon.t_cflag = asy->asy_cflag; 2287 2288 async->async_ttycommon.t_iflag = 0; 2289 async->async_ttycommon.t_iocpending = NULL; 2290 async->async_ttycommon.t_size.ws_row = 0; 2291 async->async_ttycommon.t_size.ws_col = 0; 2292 async->async_ttycommon.t_size.ws_xpixel = 0; 2293 async->async_ttycommon.t_size.ws_ypixel = 0; 2294 async->async_dev = *dev; 2295 async->async_wbufcid = 0; 2296 2297 async->async_startc = CSTART; 2298 async->async_stopc = CSTOP; 2299 asy_program(asy, ASY_INIT); 2300 } else if ((async->async_ttycommon.t_flags & TS_XCLUDE) && 2301 secpolicy_excl_open(cr) != 0) { 2302 mutex_exit(&asy->asy_excl_hi); 2303 mutex_exit(&asy->asy_excl); 2304 return (EBUSY); 2305 } else if ((*dev & OUTLINE) && !(async->async_flags & ASYNC_OUT)) { 2306 mutex_exit(&asy->asy_excl_hi); 2307 mutex_exit(&asy->asy_excl); 2308 return (EBUSY); 2309 } 2310 2311 if (*dev & OUTLINE) 2312 async->async_flags |= ASYNC_OUT; 2313 2314 /* Raise DTR on every open, but delay if it was just lowered. */ 2315 while (async->async_flags & ASYNC_DTR_DELAY) { 2316 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 2317 "waiting for the ASYNC_DTR_DELAY to be clear"); 2318 mutex_exit(&asy->asy_excl_hi); 2319 if (cv_wait_sig(&async->async_flags_cv, 2320 &asy->asy_excl) == 0) { 2321 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 2322 "interrupted by signal, exiting"); 2323 mutex_exit(&asy->asy_excl); 2324 return (EINTR); 2325 } 2326 mutex_enter(&asy->asy_excl_hi); 2327 } 2328 2329 asy_set(asy, ASY_MCR, asy->asy_mcr & ASY_MCR_DTR); 2330 2331 ASY_DPRINTF(asy, ASY_DEBUG_INIT, "\"Raise DTR on every open\": " 2332 "make mcr = %x, make TS_SOFTCAR = %s", asy_get(asy, ASY_MCR), 2333 (asy->asy_flags & ASY_IGNORE_CD) ? "ON" : "OFF"); 2334 2335 if (asy->asy_flags & ASY_IGNORE_CD) { 2336 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 2337 "ASY_IGNORE_CD set, set TS_SOFTCAR"); 2338 async->async_ttycommon.t_flags |= TS_SOFTCAR; 2339 } else { 2340 async->async_ttycommon.t_flags &= ~TS_SOFTCAR; 2341 } 2342 2343 /* 2344 * Check carrier. 2345 */ 2346 asy->asy_msr = asy_get(asy, ASY_MSR); 2347 ASY_DPRINTF(asy, ASY_DEBUG_INIT, "TS_SOFTCAR is %s, MSR & DCD is %s", 2348 (async->async_ttycommon.t_flags & TS_SOFTCAR) ? "set" : "clear", 2349 (asy->asy_msr & ASY_MSR_DCD) ? "set" : "clear"); 2350 2351 if (asy->asy_msr & ASY_MSR_DCD) 2352 async->async_flags |= ASYNC_CARR_ON; 2353 else 2354 async->async_flags &= ~ASYNC_CARR_ON; 2355 mutex_exit(&asy->asy_excl_hi); 2356 2357 /* 2358 * If FNDELAY and FNONBLOCK are clear, block until carrier up. 2359 * Quit on interrupt. 2360 */ 2361 if (!(flag & (FNDELAY|FNONBLOCK)) && 2362 !(async->async_ttycommon.t_cflag & CLOCAL)) { 2363 if ((!(async->async_flags & (ASYNC_CARR_ON|ASYNC_OUT)) && 2364 !(async->async_ttycommon.t_flags & TS_SOFTCAR)) || 2365 ((async->async_flags & ASYNC_OUT) && 2366 !(*dev & OUTLINE))) { 2367 async->async_flags |= ASYNC_WOPEN; 2368 if (cv_wait_sig(&async->async_flags_cv, 2369 &asy->asy_excl) == B_FALSE) { 2370 async->async_flags &= ~ASYNC_WOPEN; 2371 mutex_exit(&asy->asy_excl); 2372 return (EINTR); 2373 } 2374 async->async_flags &= ~ASYNC_WOPEN; 2375 goto again; 2376 } 2377 } else if ((async->async_flags & ASYNC_OUT) && !(*dev & OUTLINE)) { 2378 mutex_exit(&asy->asy_excl); 2379 return (EBUSY); 2380 } 2381 2382 async->async_ttycommon.t_readq = rq; 2383 async->async_ttycommon.t_writeq = WR(rq); 2384 rq->q_ptr = WR(rq)->q_ptr = (caddr_t)async; 2385 mutex_exit(&asy->asy_excl); 2386 /* 2387 * Caution here -- qprocson sets the pointers that are used by canput 2388 * called by async_softint. ASYNC_ISOPEN must *not* be set until those 2389 * pointers are valid. 2390 */ 2391 qprocson(rq); 2392 async->async_flags |= ASYNC_ISOPEN; 2393 async->async_polltid = 0; 2394 ASY_DPRINTF(asy, ASY_DEBUG_INIT, "done"); 2395 return (0); 2396 } 2397 2398 static void 2399 async_progress_check(void *arg) 2400 { 2401 struct asyncline *async = arg; 2402 struct asycom *asy = async->async_common; 2403 mblk_t *bp; 2404 2405 /* 2406 * We define "progress" as either waiting on a timed break or delay, or 2407 * having had at least one transmitter interrupt. If none of these are 2408 * true, then just terminate the output and wake up that close thread. 2409 */ 2410 mutex_enter(&asy->asy_excl); 2411 mutex_enter(&asy->asy_excl_hi); 2412 if (!(async->async_flags & (ASYNC_BREAK|ASYNC_DELAY|ASYNC_PROGRESS))) { 2413 async->async_ocnt = 0; 2414 async->async_flags &= ~ASYNC_BUSY; 2415 async->async_timer = 0; 2416 bp = async->async_xmitblk; 2417 async->async_xmitblk = NULL; 2418 mutex_exit(&asy->asy_excl_hi); 2419 if (bp != NULL) 2420 freeb(bp); 2421 /* 2422 * Since this timer is running, we know that we're in exit(2). 2423 * That means that the user can't possibly be waiting on any 2424 * valid ioctl(2) completion anymore, and we should just flush 2425 * everything. 2426 */ 2427 flushq(async->async_ttycommon.t_writeq, FLUSHALL); 2428 cv_broadcast(&async->async_flags_cv); 2429 } else { 2430 async->async_flags &= ~ASYNC_PROGRESS; 2431 async->async_timer = timeout(async_progress_check, async, 2432 drv_usectohz(asy_drain_check)); 2433 mutex_exit(&asy->asy_excl_hi); 2434 } 2435 mutex_exit(&asy->asy_excl); 2436 } 2437 2438 /* 2439 * Release DTR so that asyopen() can raise it. 2440 */ 2441 static void 2442 async_dtr_free(struct asyncline *async) 2443 { 2444 struct asycom *asy = async->async_common; 2445 2446 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 2447 "async_dtr_free, clearing ASYNC_DTR_DELAY"); 2448 mutex_enter(&asy->asy_excl); 2449 async->async_flags &= ~ASYNC_DTR_DELAY; 2450 async->async_dtrtid = 0; 2451 cv_broadcast(&async->async_flags_cv); 2452 mutex_exit(&asy->asy_excl); 2453 } 2454 2455 /* 2456 * Close routine. 2457 */ 2458 static int 2459 asyclose(queue_t *q, int flag, cred_t *credp __unused) 2460 { 2461 struct asyncline *async; 2462 struct asycom *asy; 2463 2464 async = (struct asyncline *)q->q_ptr; 2465 ASSERT(async != NULL); 2466 2467 asy = async->async_common; 2468 2469 ASY_DPRINTF(asy, ASY_DEBUG_CLOSE, "enter"); 2470 2471 mutex_enter(&asy->asy_excl); 2472 async->async_flags |= ASYNC_CLOSING; 2473 2474 /* 2475 * Turn off PPS handling early to avoid events occuring during 2476 * close. Also reset the DCD edge monitoring bit. 2477 */ 2478 mutex_enter(&asy->asy_excl_hi); 2479 asy->asy_flags &= ~(ASY_PPS | ASY_PPS_EDGE); 2480 mutex_exit(&asy->asy_excl_hi); 2481 2482 /* 2483 * There are two flavors of break -- timed (M_BREAK or TCSBRK) and 2484 * untimed (TIOCSBRK). For the timed case, these are enqueued on our 2485 * write queue and there's a timer running, so we don't have to worry 2486 * about them. For the untimed case, though, the user obviously made a 2487 * mistake, because these are handled immediately. We'll terminate the 2488 * break now and honor their implicit request by discarding the rest of 2489 * the data. 2490 */ 2491 if (async->async_flags & ASYNC_OUT_SUSPEND) { 2492 if (async->async_utbrktid != 0) { 2493 (void) untimeout(async->async_utbrktid); 2494 async->async_utbrktid = 0; 2495 } 2496 mutex_enter(&asy->asy_excl_hi); 2497 (void) asy_clr(asy, ASY_LCR, ASY_LCR_SETBRK); 2498 mutex_exit(&asy->asy_excl_hi); 2499 async->async_flags &= ~ASYNC_OUT_SUSPEND; 2500 goto nodrain; 2501 } 2502 2503 /* 2504 * If the user told us not to delay the close ("non-blocking"), then 2505 * don't bother trying to drain. 2506 * 2507 * If the user did M_STOP (ASYNC_STOPPED), there's no hope of ever 2508 * getting an M_START (since these messages aren't enqueued), and the 2509 * only other way to clear the stop condition is by loss of DCD, which 2510 * would discard the queue data. Thus, we drop the output data if 2511 * ASYNC_STOPPED is set. 2512 */ 2513 if ((flag & (FNDELAY|FNONBLOCK)) || 2514 (async->async_flags & ASYNC_STOPPED)) { 2515 goto nodrain; 2516 } 2517 2518 /* 2519 * If there's any pending output, then we have to try to drain it. 2520 * There are two main cases to be handled: 2521 * - called by close(2): need to drain until done or until 2522 * a signal is received. No timeout. 2523 * - called by exit(2): need to drain while making progress 2524 * or until a timeout occurs. No signals. 2525 * 2526 * If we can't rely on receiving a signal to get us out of a hung 2527 * session, then we have to use a timer. In this case, we set a timer 2528 * to check for progress in sending the output data -- all that we ask 2529 * (at each interval) is that there's been some progress made. Since 2530 * the interrupt routine grabs buffers from the write queue, we can't 2531 * trust changes in async_ocnt. Instead, we use a progress flag. 2532 * 2533 * Note that loss of carrier will cause the output queue to be flushed, 2534 * and we'll wake up again and finish normally. 2535 */ 2536 if (!ddi_can_receive_sig() && asy_drain_check != 0) { 2537 async->async_flags &= ~ASYNC_PROGRESS; 2538 async->async_timer = timeout(async_progress_check, async, 2539 drv_usectohz(asy_drain_check)); 2540 } 2541 while (async->async_ocnt > 0 || 2542 async->async_ttycommon.t_writeq->q_first != NULL || 2543 (async->async_flags & (ASYNC_BUSY|ASYNC_BREAK|ASYNC_DELAY))) { 2544 if (cv_wait_sig(&async->async_flags_cv, &asy->asy_excl) == 0) 2545 break; 2546 } 2547 if (async->async_timer != 0) { 2548 (void) untimeout(async->async_timer); 2549 async->async_timer = 0; 2550 } 2551 2552 nodrain: 2553 async->async_ocnt = 0; 2554 if (async->async_xmitblk != NULL) 2555 freeb(async->async_xmitblk); 2556 async->async_xmitblk = NULL; 2557 2558 /* 2559 * If line has HUPCL set or is incompletely opened fix up the modem 2560 * lines. 2561 */ 2562 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "next check HUPCL flag"); 2563 mutex_enter(&asy->asy_excl_hi); 2564 if ((async->async_ttycommon.t_cflag & HUPCL) || 2565 (async->async_flags & ASYNC_WOPEN)) { 2566 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 2567 "HUPCL flag = %x, ASYNC_WOPEN flag = %x", 2568 async->async_ttycommon.t_cflag & HUPCL, 2569 async->async_ttycommon.t_cflag & ASYNC_WOPEN); 2570 async->async_flags |= ASYNC_DTR_DELAY; 2571 2572 /* turn off DTR, RTS but NOT interrupt to 386 */ 2573 if (asy->asy_flags & (ASY_IGNORE_CD|ASY_RTS_DTR_OFF)) { 2574 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 2575 "ASY_IGNORE_CD flag = %x, " 2576 "ASY_RTS_DTR_OFF flag = %x", 2577 asy->asy_flags & ASY_IGNORE_CD, 2578 asy->asy_flags & ASY_RTS_DTR_OFF); 2579 2580 asy_put(asy, ASY_MCR, asy->asy_mcr | ASY_MCR_OUT2); 2581 } else { 2582 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 2583 "Dropping DTR and RTS"); 2584 asy_put(asy, ASY_MCR, ASY_MCR_OUT2); 2585 } 2586 async->async_dtrtid = 2587 timeout((void (*)())async_dtr_free, 2588 (caddr_t)async, drv_usectohz(asy_min_dtr_low)); 2589 } 2590 /* 2591 * If nobody's using it now, turn off receiver interrupts. 2592 */ 2593 if ((async->async_flags & (ASYNC_WOPEN|ASYNC_ISOPEN)) == 0) 2594 asy_disable_interrupts(asy, ASY_IER_RIEN); 2595 2596 mutex_exit(&asy->asy_excl_hi); 2597 2598 ttycommon_close(&async->async_ttycommon); 2599 2600 /* 2601 * Cancel outstanding "bufcall" request. 2602 */ 2603 if (async->async_wbufcid != 0) { 2604 unbufcall(async->async_wbufcid); 2605 async->async_wbufcid = 0; 2606 } 2607 2608 /* Note that qprocsoff can't be done until after interrupts are off */ 2609 qprocsoff(q); 2610 q->q_ptr = WR(q)->q_ptr = NULL; 2611 async->async_ttycommon.t_readq = NULL; 2612 async->async_ttycommon.t_writeq = NULL; 2613 2614 /* 2615 * Clear out device state, except persistant device property flags. 2616 */ 2617 async->async_flags &= (ASYNC_DTR_DELAY|ASY_RTS_DTR_OFF); 2618 cv_broadcast(&async->async_flags_cv); 2619 mutex_exit(&asy->asy_excl); 2620 2621 ASY_DPRINTF(asy, ASY_DEBUG_CLOSE, "done"); 2622 return (0); 2623 } 2624 2625 static boolean_t 2626 asy_isbusy(struct asycom *asy) 2627 { 2628 struct asyncline *async; 2629 2630 ASY_DPRINTF(asy, ASY_DEBUG_EOT, "enter"); 2631 async = asy->asy_priv; 2632 ASSERT(mutex_owned(&asy->asy_excl)); 2633 ASSERT(mutex_owned(&asy->asy_excl_hi)); 2634 /* 2635 * XXXX this should be recoded 2636 */ 2637 return ((async->async_ocnt > 0) || 2638 ((asy_get(asy, ASY_LSR) & (ASY_LSR_TEMT | ASY_LSR_THRE)) == 0)); 2639 } 2640 2641 static void 2642 asy_waiteot(struct asycom *asy) 2643 { 2644 /* 2645 * Wait for the current transmission block and the 2646 * current fifo data to transmit. Once this is done 2647 * we may go on. 2648 */ 2649 ASY_DPRINTF(asy, ASY_DEBUG_EOT, "enter"); 2650 ASSERT(mutex_owned(&asy->asy_excl)); 2651 ASSERT(mutex_owned(&asy->asy_excl_hi)); 2652 while (asy_isbusy(asy)) { 2653 mutex_exit(&asy->asy_excl_hi); 2654 mutex_exit(&asy->asy_excl); 2655 drv_usecwait(10000); /* wait .01 */ 2656 mutex_enter(&asy->asy_excl); 2657 mutex_enter(&asy->asy_excl_hi); 2658 } 2659 } 2660 2661 /* asy_reset_fifo -- flush fifos and [re]program fifo control register */ 2662 static void 2663 asy_reset_fifo(struct asycom *asy, uchar_t flush) 2664 { 2665 ASSERT(mutex_owned(&asy->asy_excl_hi)); 2666 2667 /* On a 16750, we have to set DLAB in order to set ASY_FCR_FIFO64. */ 2668 if (asy->asy_hwtype >= ASY_16750) 2669 asy_set(asy, ASY_LCR, ASY_LCR_DLAB); 2670 2671 asy_put(asy, ASY_FCR, asy->asy_fifor | flush); 2672 2673 /* Clear DLAB */ 2674 if (asy->asy_hwtype >= ASY_16750) 2675 asy_clr(asy, ASY_LCR, ASY_LCR_DLAB); 2676 } 2677 2678 /* 2679 * Program the ASY port. Most of the async operation is based on the values 2680 * of 'c_iflag' and 'c_cflag'. 2681 */ 2682 static void 2683 asy_program(struct asycom *asy, int mode) 2684 { 2685 struct asyncline *async; 2686 int baudrate, c_flag; 2687 uint8_t ier; 2688 int flush_reg; 2689 int ocflags; 2690 2691 ASSERT(mutex_owned(&asy->asy_excl)); 2692 ASSERT(mutex_owned(&asy->asy_excl_hi)); 2693 2694 async = asy->asy_priv; 2695 ASY_DPRINTF(asy, ASY_DEBUG_PROCS, "mode = 0x%08X, enter", mode); 2696 2697 baudrate = BAUDINDEX(async->async_ttycommon.t_cflag); 2698 2699 async->async_ttycommon.t_cflag &= ~(CIBAUD); 2700 2701 if (baudrate > CBAUD) { 2702 async->async_ttycommon.t_cflag |= CIBAUDEXT; 2703 async->async_ttycommon.t_cflag |= 2704 (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD); 2705 } else { 2706 async->async_ttycommon.t_cflag &= ~CIBAUDEXT; 2707 async->async_ttycommon.t_cflag |= 2708 ((baudrate << IBSHIFT) & CIBAUD); 2709 } 2710 2711 c_flag = async->async_ttycommon.t_cflag & 2712 (CLOCAL|CREAD|CSTOPB|CSIZE|PARENB|PARODD|CBAUD|CBAUDEXT); 2713 2714 asy_disable_interrupts(asy, ASY_IER_ALL); 2715 2716 ocflags = asy->asy_ocflag; 2717 2718 /* flush/reset the status registers */ 2719 (void) asy_get(asy, ASY_ISR); 2720 (void) asy_get(asy, ASY_LSR); 2721 asy->asy_msr = flush_reg = asy_get(asy, ASY_MSR); 2722 /* 2723 * The device is programmed in the open sequence, if we 2724 * have to hardware handshake, then this is a good time 2725 * to check if the device can receive any data. 2726 */ 2727 2728 if ((CRTSCTS & async->async_ttycommon.t_cflag) && 2729 !(flush_reg & ASY_MSR_CTS)) { 2730 async_flowcontrol_hw_output(asy, FLOW_STOP); 2731 } else { 2732 /* 2733 * We can not use async_flowcontrol_hw_output(asy, FLOW_START) 2734 * here, because if CRTSCTS is clear, we need clear 2735 * ASYNC_HW_OUT_FLW bit. 2736 */ 2737 async->async_flags &= ~ASYNC_HW_OUT_FLW; 2738 } 2739 2740 /* 2741 * If IXON is not set, clear ASYNC_SW_OUT_FLW; 2742 * If IXON is set, no matter what IXON flag is before this 2743 * function call to asy_program, 2744 * we will use the old ASYNC_SW_OUT_FLW status. 2745 * Because of handling IXON in the driver, we also should re-calculate 2746 * the value of ASYNC_OUT_FLW_RESUME bit, but in fact, 2747 * the TCSET* commands which call asy_program 2748 * are put into the write queue, so there is no output needed to 2749 * be resumed at this point. 2750 */ 2751 if (!(IXON & async->async_ttycommon.t_iflag)) 2752 async->async_flags &= ~ASYNC_SW_OUT_FLW; 2753 2754 /* manually flush receive buffer or fifo (workaround for buggy fifos) */ 2755 if (mode == ASY_INIT) { 2756 if (asy->asy_use_fifo == ASY_FCR_FIFO_EN) { 2757 for (flush_reg = asy->asy_fifo_buf; flush_reg-- > 0; ) { 2758 (void) asy_get(asy, ASY_RHR); 2759 } 2760 } else { 2761 flush_reg = asy_get(asy, ASY_RHR); 2762 } 2763 } 2764 2765 if (ocflags != (c_flag & ~CLOCAL) || mode == ASY_INIT) { 2766 /* Set line control */ 2767 uint8_t lcr = 0; 2768 2769 if (c_flag & CSTOPB) 2770 lcr |= ASY_LCR_STOP2; /* 2 stop bits */ 2771 2772 if (c_flag & PARENB) 2773 lcr |= ASY_LCR_PEN; 2774 2775 if ((c_flag & PARODD) == 0) 2776 lcr |= ASY_LCR_EPS; 2777 2778 switch (c_flag & CSIZE) { 2779 case CS5: 2780 lcr |= ASY_LCR_BITS5; 2781 break; 2782 case CS6: 2783 lcr |= ASY_LCR_BITS6; 2784 break; 2785 case CS7: 2786 lcr |= ASY_LCR_BITS7; 2787 break; 2788 case CS8: 2789 lcr |= ASY_LCR_BITS8; 2790 break; 2791 } 2792 2793 asy_clr(asy, ASY_LCR, ASY_LCR_WLS0 | ASY_LCR_WLS1 | 2794 ASY_LCR_STB | ASY_LCR_PEN | ASY_LCR_EPS); 2795 asy_set(asy, ASY_LCR, lcr); 2796 asy_set_baudrate(asy, baudrate); 2797 2798 /* 2799 * If we have a FIFO buffer, enable/flush 2800 * at intialize time, flush if transitioning from 2801 * CREAD off to CREAD on. 2802 */ 2803 if (((ocflags & CREAD) == 0 && (c_flag & CREAD)) || 2804 mode == ASY_INIT) { 2805 if (asy->asy_use_fifo == ASY_FCR_FIFO_EN) 2806 asy_reset_fifo(asy, ASY_FCR_RHR_FL); 2807 } 2808 2809 /* remember the new cflags */ 2810 asy->asy_ocflag = c_flag & ~CLOCAL; 2811 } 2812 2813 if (baudrate == 0) 2814 asy_put(asy, ASY_MCR, 2815 (asy->asy_mcr & ASY_MCR_RTS) | ASY_MCR_OUT2); 2816 else 2817 asy_put(asy, ASY_MCR, asy->asy_mcr | ASY_MCR_OUT2); 2818 2819 /* 2820 * Call the modem status interrupt handler to check for the carrier 2821 * in case CLOCAL was turned off after the carrier came on. 2822 * (Note: Modem status interrupt is not enabled if CLOCAL is ON.) 2823 */ 2824 async_msint(asy); 2825 2826 /* Set interrupt control */ 2827 ASY_DPRINTF(asy, ASY_DEBUG_MODM2, 2828 "c_flag & CLOCAL = %x t_cflag & CRTSCTS = %x", 2829 c_flag & CLOCAL, async->async_ttycommon.t_cflag & CRTSCTS); 2830 2831 2832 /* Always enable transmit and line status interrupts. */ 2833 ier = ASY_IER_TIEN | ASY_IER_SIEN; 2834 2835 /* 2836 * Enable Modem status interrupt if hardware flow control is enabled or 2837 * this isn't a direct-wired (local) line, which ignores DCD. 2838 */ 2839 if (((c_flag & CLOCAL) == 0) || 2840 (async->async_ttycommon.t_cflag & CRTSCTS)) 2841 ier |= ASY_IER_MIEN; 2842 2843 if (c_flag & CREAD) 2844 ier |= ASY_IER_RIEN; 2845 2846 asy_enable_interrupts(asy, ier); 2847 ASY_DPRINTF(asy, ASY_DEBUG_PROCS, "done"); 2848 } 2849 2850 static boolean_t 2851 asy_baudok(struct asycom *asy) 2852 { 2853 struct asyncline *async = asy->asy_priv; 2854 int baudrate; 2855 2856 2857 baudrate = BAUDINDEX(async->async_ttycommon.t_cflag); 2858 2859 if (baudrate >= ARRAY_SIZE(asy_baud_tab)) 2860 return (0); 2861 2862 return (baudrate == 0 || 2863 asy_baud_tab[baudrate].asy_dll != 0 || 2864 asy_baud_tab[baudrate].asy_dlh != 0); 2865 } 2866 2867 /* 2868 * asyintr() is the High Level Interrupt Handler. 2869 * 2870 * There are four different interrupt types indexed by ISR register values: 2871 * 0: modem 2872 * 1: Tx holding register is empty, ready for next char 2873 * 2: Rx register now holds a char to be picked up 2874 * 3: error or break on line 2875 * This routine checks the Bit 0 (interrupt-not-pending) to determine if 2876 * the interrupt is from this port. 2877 */ 2878 uint_t 2879 asyintr(caddr_t argasy, caddr_t argunused __unused) 2880 { 2881 struct asycom *asy = (struct asycom *)argasy; 2882 struct asyncline *async; 2883 int ret_status = DDI_INTR_UNCLAIMED; 2884 2885 mutex_enter(&asy->asy_excl_hi); 2886 async = asy->asy_priv; 2887 if (async == NULL || 2888 (async->async_flags & (ASYNC_ISOPEN|ASYNC_WOPEN)) == 0) { 2889 const uint8_t intr_id = asy_get(asy, ASY_ISR); 2890 2891 ASY_DPRINTF(asy, ASY_DEBUG_INTR, 2892 "not open async=%p flags=0x%x interrupt_id=0x%x", 2893 async, async == NULL ? 0 : async->async_flags, intr_id); 2894 2895 if ((intr_id & ASY_ISR_NOINTR) == 0) { 2896 /* 2897 * reset the device by: 2898 * reading line status 2899 * reading any data from data status register 2900 * reading modem status 2901 */ 2902 (void) asy_get(asy, ASY_LSR); 2903 (void) asy_get(asy, ASY_RHR); 2904 asy->asy_msr = asy_get(asy, ASY_MSR); 2905 ret_status = DDI_INTR_CLAIMED; 2906 } 2907 mutex_exit(&asy->asy_excl_hi); 2908 return (ret_status); 2909 } 2910 2911 /* By this point we're sure this is for us. */ 2912 ret_status = DDI_INTR_CLAIMED; 2913 2914 /* 2915 * Before this flag was set, interrupts were disabled. We may still get 2916 * here if asyintr() waited on the mutex. 2917 */ 2918 if (asy->asy_flags & ASY_DDI_SUSPENDED) { 2919 mutex_exit(&asy->asy_excl_hi); 2920 return (ret_status); 2921 } 2922 2923 /* 2924 * We will loop until the interrupt line is pulled low. asy 2925 * interrupt is edge triggered. 2926 */ 2927 for (;;) { 2928 const uint8_t intr_id = asy_get(asy, ASY_ISR); 2929 /* 2930 * Reading LSR will clear any error bits (ASY_LSR_ERRORS) which 2931 * are set which is why the value is passed through to 2932 * async_rxint() and not re-read there. In the unexpected event 2933 * that we've ended up here without a pending interrupt, the 2934 * ASY_ISR_NOINTR case, it should do no harm to have cleared 2935 * the error bits, and it means we can get some additional 2936 * information in the debug message if it's enabled. 2937 */ 2938 const uint8_t lsr = asy_get(asy, ASY_LSR); 2939 2940 ASY_DPRINTF(asy, ASY_DEBUG_INTR, 2941 "interrupt_id=0x%x LSR=0x%x", 2942 intr_id, lsr); 2943 2944 if (intr_id & ASY_ISR_NOINTR) 2945 break; 2946 2947 switch (intr_id & ASY_ISR_MASK) { 2948 case ASY_ISR_ID_RLST: 2949 case ASY_ISR_ID_RDA: 2950 case ASY_ISR_ID_TMO: 2951 /* receiver interrupt or receiver errors */ 2952 async_rxint(asy, lsr); 2953 break; 2954 2955 case ASY_ISR_ID_THRE: 2956 /* 2957 * The transmit-ready interrupt implies an empty 2958 * transmit-hold register (or FIFO). Check that it is 2959 * present before attempting to transmit more data. 2960 */ 2961 if ((lsr & ASY_LSR_THRE) == 0) { 2962 /* 2963 * Taking a THRE interrupt only to find THRE 2964 * absent would be a surprise, except for a 2965 * racing asyputchar(), which ignores the 2966 * excl_hi mutex when writing to the device. 2967 */ 2968 continue; 2969 } 2970 async_txint(asy); 2971 /* 2972 * Unlike the other interrupts which fall through to 2973 * attempting to fill the output register/FIFO, THRE 2974 * has no need having just done so. 2975 */ 2976 continue; 2977 2978 case ASY_ISR_ID_MST: 2979 /* modem status interrupt */ 2980 async_msint(asy); 2981 break; 2982 } 2983 2984 /* Refill the output FIFO if it has gone empty */ 2985 if ((lsr & ASY_LSR_THRE) && (async->async_flags & ASYNC_BUSY) && 2986 async->async_ocnt > 0) 2987 async_txint(asy); 2988 } 2989 2990 mutex_exit(&asy->asy_excl_hi); 2991 return (ret_status); 2992 } 2993 2994 /* 2995 * Transmitter interrupt service routine. 2996 * If there is more data to transmit in the current pseudo-DMA block, 2997 * send the next character if output is not stopped or draining. 2998 * Otherwise, queue up a soft interrupt. 2999 * 3000 * XXX - Needs review for HW FIFOs. 3001 */ 3002 static void 3003 async_txint(struct asycom *asy) 3004 { 3005 struct asyncline *async = asy->asy_priv; 3006 int fifo_len; 3007 3008 ASSERT(MUTEX_HELD(&asy->asy_excl_hi)); 3009 3010 /* 3011 * If ASYNC_BREAK or ASYNC_OUT_SUSPEND has been set, return to 3012 * asyintr()'s context to claim the interrupt without performing 3013 * any action. No character will be loaded into FIFO/THR until 3014 * timed or untimed break is removed 3015 */ 3016 if (async->async_flags & (ASYNC_BREAK|ASYNC_OUT_SUSPEND)) 3017 return; 3018 3019 fifo_len = asy->asy_fifo_buf; /* with FIFO buffers */ 3020 if (fifo_len > asy_max_tx_fifo) 3021 fifo_len = asy_max_tx_fifo; 3022 3023 if (async_flowcontrol_sw_input(asy, FLOW_CHECK, IN_FLOW_NULL)) 3024 fifo_len--; 3025 3026 if (async->async_ocnt > 0 && fifo_len > 0 && 3027 !(async->async_flags & 3028 (ASYNC_HW_OUT_FLW|ASYNC_SW_OUT_FLW|ASYNC_STOPPED))) { 3029 while (fifo_len-- > 0 && async->async_ocnt-- > 0) { 3030 asy_put(asy, ASY_THR, *async->async_optr++); 3031 } 3032 async->async_flags |= ASYNC_PROGRESS; 3033 } 3034 3035 if (fifo_len <= 0) 3036 return; 3037 3038 asysetsoft(asy); 3039 } 3040 3041 /* 3042 * Interrupt on port: handle PPS event. This function is only called 3043 * for a port on which PPS event handling has been enabled. 3044 */ 3045 static void 3046 asy_ppsevent(struct asycom *asy, int msr) 3047 { 3048 ASSERT(MUTEX_HELD(&asy->asy_excl_hi)); 3049 3050 if (asy->asy_flags & ASY_PPS_EDGE) { 3051 /* Have seen leading edge, now look for and record drop */ 3052 if ((msr & ASY_MSR_DCD) == 0) 3053 asy->asy_flags &= ~ASY_PPS_EDGE; 3054 /* 3055 * Waiting for leading edge, look for rise; stamp event and 3056 * calibrate kernel clock. 3057 */ 3058 } else if (msr & ASY_MSR_DCD) { 3059 /* 3060 * This code captures a timestamp at the designated 3061 * transition of the PPS signal (DCD asserted). The 3062 * code provides a pointer to the timestamp, as well 3063 * as the hardware counter value at the capture. 3064 * 3065 * Note: the kernel has nano based time values while 3066 * NTP requires micro based, an in-line fast algorithm 3067 * to convert nsec to usec is used here -- see hrt2ts() 3068 * in common/os/timers.c for a full description. 3069 */ 3070 struct timeval *tvp = &asy_ppsev.tv; 3071 timestruc_t ts; 3072 long nsec, usec; 3073 3074 asy->asy_flags |= ASY_PPS_EDGE; 3075 LED_OFF; 3076 gethrestime(&ts); 3077 LED_ON; 3078 nsec = ts.tv_nsec; 3079 usec = nsec + (nsec >> 2); 3080 usec = nsec + (usec >> 1); 3081 usec = nsec + (usec >> 2); 3082 usec = nsec + (usec >> 4); 3083 usec = nsec - (usec >> 3); 3084 usec = nsec + (usec >> 2); 3085 usec = nsec + (usec >> 3); 3086 usec = nsec + (usec >> 4); 3087 usec = nsec + (usec >> 1); 3088 usec = nsec + (usec >> 6); 3089 tvp->tv_usec = usec >> 10; 3090 tvp->tv_sec = ts.tv_sec; 3091 3092 ++asy_ppsev.serial; 3093 3094 /* 3095 * Because the kernel keeps a high-resolution time, 3096 * pass the current highres timestamp in tvp and zero 3097 * in usec. 3098 */ 3099 ddi_hardpps(tvp, 0); 3100 } 3101 } 3102 3103 /* 3104 * Receiver interrupt: RDA interrupt, FIFO timeout interrupt or receive 3105 * error interrupt. 3106 * Try to put the character into the circular buffer for this line; if it 3107 * overflows, indicate a circular buffer overrun. If this port is always 3108 * to be serviced immediately, or the character is a STOP character, or 3109 * more than 15 characters have arrived, queue up a soft interrupt to 3110 * drain the circular buffer. 3111 * XXX - needs review for hw FIFOs support. 3112 */ 3113 3114 static void 3115 async_rxint(struct asycom *asy, uchar_t lsr) 3116 { 3117 struct asyncline *async = asy->asy_priv; 3118 uchar_t c; 3119 uint_t s, needsoft = 0; 3120 tty_common_t *tp; 3121 int looplim = asy->asy_fifo_buf * 2; 3122 3123 ASSERT(MUTEX_HELD(&asy->asy_excl_hi)); 3124 3125 tp = &async->async_ttycommon; 3126 if (!(tp->t_cflag & CREAD)) { 3127 /* Line is not open for reading. Flush receiver FIFO. */ 3128 while ((lsr & (ASY_LSR_DR | ASY_LSR_ERRORS)) != 0) { 3129 (void) asy_get(asy, ASY_RHR); 3130 lsr = asy_get(asy, ASY_LSR); 3131 if (looplim-- < 0) /* limit loop */ 3132 break; 3133 } 3134 return; 3135 } 3136 3137 while ((lsr & (ASY_LSR_DR | ASY_LSR_ERRORS)) != 0) { 3138 c = 0; 3139 s = 0; /* reset error status */ 3140 if (lsr & ASY_LSR_DR) { 3141 c = asy_get(asy, ASY_RHR); 3142 3143 /* 3144 * We handle XON/XOFF char if IXON is set, 3145 * but if received char is _POSIX_VDISABLE, 3146 * we left it to the up level module. 3147 */ 3148 if (tp->t_iflag & IXON) { 3149 if ((c == async->async_stopc) && 3150 (c != _POSIX_VDISABLE)) { 3151 async_flowcontrol_sw_output(asy, 3152 FLOW_STOP); 3153 goto check_looplim; 3154 } else if ((c == async->async_startc) && 3155 (c != _POSIX_VDISABLE)) { 3156 async_flowcontrol_sw_output(asy, 3157 FLOW_START); 3158 needsoft = 1; 3159 goto check_looplim; 3160 } 3161 if ((tp->t_iflag & IXANY) && 3162 (async->async_flags & ASYNC_SW_OUT_FLW)) { 3163 async_flowcontrol_sw_output(asy, 3164 FLOW_START); 3165 needsoft = 1; 3166 } 3167 } 3168 } 3169 3170 /* 3171 * Check for character break sequence 3172 */ 3173 if ((abort_enable == KIOCABORTALTERNATE) && 3174 (asy->asy_flags & ASY_CONSOLE)) { 3175 if (abort_charseq_recognize(c)) 3176 abort_sequence_enter((char *)NULL); 3177 } 3178 3179 /* Handle framing errors */ 3180 if (lsr & ASY_LSR_ERRORS) { 3181 if (lsr & ASY_LSR_PE) { 3182 if (tp->t_iflag & INPCK) /* parity enabled */ 3183 s |= PERROR; 3184 } 3185 3186 if (lsr & (ASY_LSR_FE | ASY_LSR_BI)) 3187 s |= FRERROR; 3188 if (lsr & ASY_LSR_OE) { 3189 async->async_hw_overrun = 1; 3190 s |= OVERRUN; 3191 } 3192 } 3193 3194 if (s == 0) 3195 if ((tp->t_iflag & PARMRK) && 3196 !(tp->t_iflag & (IGNPAR|ISTRIP)) && 3197 (c == 0377)) 3198 if (RING_POK(async, 2)) { 3199 RING_PUT(async, 0377); 3200 RING_PUT(async, c); 3201 } else 3202 async->async_sw_overrun = 1; 3203 else 3204 if (RING_POK(async, 1)) 3205 RING_PUT(async, c); 3206 else 3207 async->async_sw_overrun = 1; 3208 else 3209 if (s & FRERROR) /* Handle framing errors */ 3210 if (c == 0) 3211 if ((asy->asy_flags & ASY_CONSOLE) && 3212 (abort_enable != 3213 KIOCABORTALTERNATE)) 3214 abort_sequence_enter((char *)0); 3215 else 3216 async->async_break++; 3217 else 3218 if (RING_POK(async, 1)) 3219 RING_MARK(async, c, s); 3220 else 3221 async->async_sw_overrun = 1; 3222 else /* Parity errors are handled by ldterm */ 3223 if (RING_POK(async, 1)) 3224 RING_MARK(async, c, s); 3225 else 3226 async->async_sw_overrun = 1; 3227 check_looplim: 3228 lsr = asy_get(asy, ASY_LSR); 3229 if (looplim-- < 0) /* limit loop */ 3230 break; 3231 } 3232 if ((RING_CNT(async) > (RINGSIZE * 3)/4) && 3233 !(async->async_inflow_source & IN_FLOW_RINGBUFF)) { 3234 async_flowcontrol_hw_input(asy, FLOW_STOP, IN_FLOW_RINGBUFF); 3235 (void) async_flowcontrol_sw_input(asy, FLOW_STOP, 3236 IN_FLOW_RINGBUFF); 3237 } 3238 3239 if ((async->async_flags & ASYNC_SERVICEIMM) || needsoft || 3240 (RING_FRAC(async)) || (async->async_polltid == 0)) { 3241 asysetsoft(asy); /* need a soft interrupt */ 3242 } 3243 } 3244 3245 /* 3246 * Modem status interrupt. 3247 * 3248 * (Note: It is assumed that the MSR hasn't been read by asyintr().) 3249 */ 3250 3251 static void 3252 async_msint(struct asycom *asy) 3253 { 3254 struct asyncline *async = asy->asy_priv; 3255 int msr, t_cflag = async->async_ttycommon.t_cflag; 3256 3257 ASSERT(MUTEX_HELD(&asy->asy_excl_hi)); 3258 3259 async_msint_retry: 3260 /* this resets the interrupt */ 3261 msr = asy_get(asy, ASY_MSR); 3262 ASY_DPRINTF(asy, ASY_DEBUG_STATE, "call #%d:", 3263 ++(asy->asy_msint_cnt)); 3264 ASY_DPRINTF(asy, ASY_DEBUG_STATE, " transition: %3s %3s %3s %3s", 3265 (msr & ASY_MSR_DCTS) ? "DCTS" : " ", 3266 (msr & ASY_MSR_DDSR) ? "DDSR" : " ", 3267 (msr & ASY_MSR_TERI) ? "TERI" : " ", 3268 (msr & ASY_MSR_DDCD) ? "DDCD" : " "); 3269 ASY_DPRINTF(asy, ASY_DEBUG_STATE, "current state: %3s %3s %3s %3s", 3270 (msr & ASY_MSR_CTS) ? "CTS " : " ", 3271 (msr & ASY_MSR_DSR) ? "DSR " : " ", 3272 (msr & ASY_MSR_RI) ? "RI " : " ", 3273 (msr & ASY_MSR_DCD) ? "DCD " : " "); 3274 3275 /* If CTS status is changed, do H/W output flow control */ 3276 if ((t_cflag & CRTSCTS) && (((asy->asy_msr ^ msr) & ASY_MSR_CTS) != 0)) 3277 async_flowcontrol_hw_output(asy, 3278 msr & ASY_MSR_CTS ? FLOW_START : FLOW_STOP); 3279 /* 3280 * Reading MSR resets the interrupt, we save the 3281 * value of msr so that other functions could examine MSR by 3282 * looking at asy_msr. 3283 */ 3284 asy->asy_msr = (uchar_t)msr; 3285 3286 /* Handle PPS event */ 3287 if (asy->asy_flags & ASY_PPS) 3288 asy_ppsevent(asy, msr); 3289 3290 async->async_ext++; 3291 asysetsoft(asy); 3292 /* 3293 * We will make sure that the modem status presented to us 3294 * during the previous read has not changed. If the chip samples 3295 * the modem status on the falling edge of the interrupt line, 3296 * and uses this state as the base for detecting change of modem 3297 * status, we would miss a change of modem status event that occured 3298 * after we initiated a read MSR operation. 3299 */ 3300 msr = asy_get(asy, ASY_MSR); 3301 if (ASY_MSR_STATES(msr) != ASY_MSR_STATES(asy->asy_msr)) 3302 goto async_msint_retry; 3303 } 3304 3305 /* 3306 * Pend a soft interrupt if one isn't already pending. 3307 */ 3308 static void 3309 asysetsoft(struct asycom *asy) 3310 { 3311 ASSERT(MUTEX_HELD(&asy->asy_excl_hi)); 3312 3313 if (mutex_tryenter(&asy->asy_soft_lock) == 0) 3314 return; 3315 3316 asy->asy_flags |= ASY_NEEDSOFT; 3317 if (!asy->asysoftpend) { 3318 asy->asysoftpend = 1; 3319 mutex_exit(&asy->asy_soft_lock); 3320 (void) ddi_intr_trigger_softint(asy->asy_soft_inth, NULL); 3321 } else { 3322 mutex_exit(&asy->asy_soft_lock); 3323 } 3324 } 3325 3326 /* 3327 * Check the carrier signal DCD and handle carrier coming up or 3328 * going down, cleaning up as needed and signalling waiters. 3329 */ 3330 static void 3331 asy_carrier_check(struct asycom *asy) 3332 { 3333 struct asyncline *async = asy->asy_priv; 3334 tty_common_t *tp = &async->async_ttycommon; 3335 queue_t *q = tp->t_readq; 3336 mblk_t *bp; 3337 int flushflag; 3338 3339 ASY_DPRINTF(asy, ASY_DEBUG_MODM2, 3340 "asy_msr & DCD = %x, tp->t_flags & TS_SOFTCAR = %x", 3341 asy->asy_msr & ASY_MSR_DCD, tp->t_flags & TS_SOFTCAR); 3342 3343 if (asy->asy_msr & ASY_MSR_DCD) { 3344 /* 3345 * The DCD line is on. If we already had a carrier, 3346 * nothing changed and there's nothing to do. 3347 */ 3348 if ((async->async_flags & ASYNC_CARR_ON) != 0) 3349 return; 3350 3351 ASY_DPRINTF(asy, ASY_DEBUG_MODM2, "set ASYNC_CARR_ON"); 3352 async->async_flags |= ASYNC_CARR_ON; 3353 if (async->async_flags & ASYNC_ISOPEN) { 3354 mutex_exit(&asy->asy_excl_hi); 3355 mutex_exit(&asy->asy_excl); 3356 (void) putctl(q, M_UNHANGUP); 3357 mutex_enter(&asy->asy_excl); 3358 mutex_enter(&asy->asy_excl_hi); 3359 } 3360 cv_broadcast(&async->async_flags_cv); 3361 3362 return; 3363 } 3364 3365 /* 3366 * The DCD line is off. If we had no carrier, nothing changed 3367 * and there's nothing to do. 3368 */ 3369 if ((async->async_flags & ASYNC_CARR_ON) == 0) 3370 return; 3371 3372 /* 3373 * The DCD line is off, but we had a carrier. If we're on a local line, 3374 * where carrier is ignored, or we're using a soft carrier, we're done 3375 * here. 3376 */ 3377 if ((tp->t_cflag & CLOCAL) != 0 || (tp->t_flags & TS_SOFTCAR) != 0) 3378 goto out; 3379 3380 /* 3381 * Else, drop DTR, abort any output in progress, indicate that output 3382 * is not stopped. 3383 */ 3384 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "carrier dropped, so drop DTR"); 3385 asy_clr(asy, ASY_MCR, ASY_MCR_DTR); 3386 3387 if (async->async_flags & ASYNC_BUSY) { 3388 ASY_DPRINTF(asy, ASY_DEBUG_BUSY, 3389 "Carrier dropped. Clearing async_ocnt"); 3390 async->async_ocnt = 0; 3391 } 3392 3393 async->async_flags &= ~ASYNC_STOPPED; 3394 3395 /* If nobody had the device open, we're done here. */ 3396 if ((async->async_flags & ASYNC_ISOPEN) == 0) 3397 goto out; 3398 3399 /* Else, send a hangup notification upstream and clean up. */ 3400 mutex_exit(&asy->asy_excl_hi); 3401 mutex_exit(&asy->asy_excl); 3402 (void) putctl(q, M_HANGUP); 3403 mutex_enter(&asy->asy_excl); 3404 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "putctl(q, M_HANGUP)"); 3405 3406 /* 3407 * Flush the transmit FIFO. Any data left in there is invalid now. 3408 */ 3409 if (asy->asy_use_fifo == ASY_FCR_FIFO_EN) { 3410 mutex_enter(&asy->asy_excl_hi); 3411 asy_reset_fifo(asy, ASY_FCR_THR_FL); 3412 mutex_exit(&asy->asy_excl_hi); 3413 } 3414 3415 /* 3416 * Flush our write queue if we have one. If we're in the midst of close, 3417 * then flush everything. Don't leave stale ioctls lying about. 3418 */ 3419 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 3420 "Flushing to prevent HUPCL hanging"); 3421 flushflag = (async->async_flags & ASYNC_CLOSING) ? FLUSHALL : FLUSHDATA; 3422 flushq(tp->t_writeq, flushflag); 3423 3424 /* Free the last active msg. */ 3425 bp = async->async_xmitblk; 3426 if (bp != NULL) { 3427 freeb(bp); 3428 async->async_xmitblk = NULL; 3429 } 3430 3431 mutex_enter(&asy->asy_excl_hi); 3432 async->async_flags &= ~ASYNC_BUSY; 3433 3434 3435 out: 3436 /* Clear our carrier flag and signal anyone waiting. */ 3437 async->async_flags &= ~ASYNC_CARR_ON; 3438 cv_broadcast(&async->async_flags_cv); 3439 } 3440 3441 /* 3442 * Handle a second-stage interrupt. 3443 */ 3444 uint_t 3445 asysoftintr(caddr_t intarg, caddr_t unusedarg __unused) 3446 { 3447 struct asycom *asy = (struct asycom *)intarg; 3448 struct asyncline *async; 3449 int rv; 3450 uint_t cc; 3451 3452 /* 3453 * Test and clear soft interrupt. 3454 */ 3455 mutex_enter(&asy->asy_soft_lock); 3456 ASY_DPRINTF(asy, ASY_DEBUG_PROCS, "enter"); 3457 rv = asy->asysoftpend; 3458 if (rv != 0) 3459 asy->asysoftpend = 0; 3460 mutex_exit(&asy->asy_soft_lock); 3461 3462 if (rv) { 3463 if (asy->asy_priv == NULL) 3464 return (rv ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); 3465 async = (struct asyncline *)asy->asy_priv; 3466 mutex_enter(&asy->asy_excl_hi); 3467 if (asy->asy_flags & ASY_NEEDSOFT) { 3468 asy->asy_flags &= ~ASY_NEEDSOFT; 3469 mutex_exit(&asy->asy_excl_hi); 3470 async_softint(asy); 3471 mutex_enter(&asy->asy_excl_hi); 3472 } 3473 3474 /* 3475 * There are some instances where the softintr is not 3476 * scheduled and hence not called. It so happens that 3477 * causes the last few characters to be stuck in the 3478 * ringbuffer. Hence, call the handler once again so 3479 * the last few characters are cleared. 3480 */ 3481 cc = RING_CNT(async); 3482 mutex_exit(&asy->asy_excl_hi); 3483 if (cc > 0) 3484 (void) async_softint(asy); 3485 } 3486 return (rv ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); 3487 } 3488 3489 /* 3490 * Handle a software interrupt. 3491 */ 3492 static void 3493 async_softint(struct asycom *asy) 3494 { 3495 struct asyncline *async = asy->asy_priv; 3496 uint_t cc; 3497 mblk_t *bp; 3498 queue_t *q; 3499 uchar_t c; 3500 tty_common_t *tp; 3501 int nb; 3502 3503 ASY_DPRINTF(asy, ASY_DEBUG_PROCS, "enter"); 3504 mutex_enter(&asy->asy_excl_hi); 3505 if (asy->asy_flags & ASY_DOINGSOFT) { 3506 asy->asy_flags |= ASY_DOINGSOFT_RETRY; 3507 mutex_exit(&asy->asy_excl_hi); 3508 return; 3509 } 3510 asy->asy_flags |= ASY_DOINGSOFT; 3511 begin: 3512 asy->asy_flags &= ~ASY_DOINGSOFT_RETRY; 3513 mutex_exit(&asy->asy_excl_hi); 3514 mutex_enter(&asy->asy_excl); 3515 tp = &async->async_ttycommon; 3516 q = tp->t_readq; 3517 3518 if (async->async_flags & ASYNC_OUT_FLW_RESUME) { 3519 if (async->async_ocnt > 0) { 3520 mutex_enter(&asy->asy_excl_hi); 3521 async_resume(async); 3522 mutex_exit(&asy->asy_excl_hi); 3523 } else { 3524 if (async->async_xmitblk) 3525 freeb(async->async_xmitblk); 3526 async->async_xmitblk = NULL; 3527 async_start(async); 3528 } 3529 async->async_flags &= ~ASYNC_OUT_FLW_RESUME; 3530 } 3531 3532 mutex_enter(&asy->asy_excl_hi); 3533 if (async->async_ext) { 3534 async->async_ext = 0; 3535 asy_carrier_check(asy); 3536 } 3537 mutex_exit(&asy->asy_excl_hi); 3538 3539 /* 3540 * If data has been added to the circular buffer, remove 3541 * it from the buffer, and send it up the stream if there's 3542 * somebody listening. Try to do it 16 bytes at a time. If we 3543 * have more than 16 bytes to move, move 16 byte chunks and 3544 * leave the rest for next time around (maybe it will grow). 3545 */ 3546 mutex_enter(&asy->asy_excl_hi); 3547 if (!(async->async_flags & ASYNC_ISOPEN)) { 3548 RING_INIT(async); 3549 goto rv; 3550 } 3551 if ((cc = RING_CNT(async)) == 0) 3552 goto rv; 3553 mutex_exit(&asy->asy_excl_hi); 3554 3555 if (!canput(q)) { 3556 mutex_enter(&asy->asy_excl_hi); 3557 if (!(async->async_inflow_source & IN_FLOW_STREAMS)) { 3558 async_flowcontrol_hw_input(asy, FLOW_STOP, 3559 IN_FLOW_STREAMS); 3560 (void) async_flowcontrol_sw_input(asy, FLOW_STOP, 3561 IN_FLOW_STREAMS); 3562 } 3563 goto rv; 3564 } 3565 if (async->async_inflow_source & IN_FLOW_STREAMS) { 3566 mutex_enter(&asy->asy_excl_hi); 3567 async_flowcontrol_hw_input(asy, FLOW_START, 3568 IN_FLOW_STREAMS); 3569 (void) async_flowcontrol_sw_input(asy, FLOW_START, 3570 IN_FLOW_STREAMS); 3571 mutex_exit(&asy->asy_excl_hi); 3572 } 3573 3574 ASY_DPRINTF(asy, ASY_DEBUG_INPUT, "%d char(s) in queue", cc); 3575 3576 if (!(bp = allocb(cc, BPRI_MED))) { 3577 mutex_exit(&asy->asy_excl); 3578 ttycommon_qfull(&async->async_ttycommon, q); 3579 mutex_enter(&asy->asy_excl); 3580 mutex_enter(&asy->asy_excl_hi); 3581 goto rv; 3582 } 3583 mutex_enter(&asy->asy_excl_hi); 3584 do { 3585 if (RING_ERR(async, S_ERRORS)) { 3586 RING_UNMARK(async); 3587 c = RING_GET(async); 3588 break; 3589 } else { 3590 *bp->b_wptr++ = RING_GET(async); 3591 } 3592 } while (--cc); 3593 mutex_exit(&asy->asy_excl_hi); 3594 mutex_exit(&asy->asy_excl); 3595 if (bp->b_wptr > bp->b_rptr) { 3596 if (!canput(q)) { 3597 asyerror(asy, CE_WARN, "local queue full"); 3598 freemsg(bp); 3599 } else { 3600 (void) putq(q, bp); 3601 } 3602 } else { 3603 freemsg(bp); 3604 } 3605 /* 3606 * If we have a parity error, then send 3607 * up an M_BREAK with the "bad" 3608 * character as an argument. Let ldterm 3609 * figure out what to do with the error. 3610 */ 3611 if (cc) 3612 (void) putctl1(q, M_BREAK, c); 3613 mutex_enter(&asy->asy_excl); 3614 mutex_enter(&asy->asy_excl_hi); 3615 if (cc) { 3616 asysetsoft(asy); /* finish cc chars */ 3617 } 3618 rv: 3619 if ((RING_CNT(async) < (RINGSIZE/4)) && 3620 (async->async_inflow_source & IN_FLOW_RINGBUFF)) { 3621 async_flowcontrol_hw_input(asy, FLOW_START, IN_FLOW_RINGBUFF); 3622 (void) async_flowcontrol_sw_input(asy, FLOW_START, 3623 IN_FLOW_RINGBUFF); 3624 } 3625 3626 /* 3627 * If a transmission has finished, indicate that it's finished, 3628 * and start that line up again. 3629 */ 3630 if (async->async_break > 0) { 3631 nb = async->async_break; 3632 async->async_break = 0; 3633 if (async->async_flags & ASYNC_ISOPEN) { 3634 mutex_exit(&asy->asy_excl_hi); 3635 mutex_exit(&asy->asy_excl); 3636 for (; nb > 0; nb--) 3637 (void) putctl(q, M_BREAK); 3638 mutex_enter(&asy->asy_excl); 3639 mutex_enter(&asy->asy_excl_hi); 3640 } 3641 } 3642 if (async->async_ocnt <= 0 && (async->async_flags & ASYNC_BUSY)) { 3643 ASY_DPRINTF(asy, ASY_DEBUG_BUSY, 3644 "Clearing ASYNC_BUSY, async_ocnt=%d", async->async_ocnt); 3645 async->async_flags &= ~ASYNC_BUSY; 3646 mutex_exit(&asy->asy_excl_hi); 3647 if (async->async_xmitblk) 3648 freeb(async->async_xmitblk); 3649 async->async_xmitblk = NULL; 3650 async_start(async); 3651 /* 3652 * If the flag isn't set after doing the async_start above, we 3653 * may have finished all the queued output. Signal any thread 3654 * stuck in close. 3655 */ 3656 if (!(async->async_flags & ASYNC_BUSY)) 3657 cv_broadcast(&async->async_flags_cv); 3658 mutex_enter(&asy->asy_excl_hi); 3659 } 3660 /* 3661 * A note about these overrun bits: all they do is *tell* someone 3662 * about an error- They do not track multiple errors. In fact, 3663 * you could consider them latched register bits if you like. 3664 * We are only interested in printing the error message once for 3665 * any cluster of overrun errors. 3666 */ 3667 if (async->async_hw_overrun) { 3668 if (async->async_flags & ASYNC_ISOPEN) { 3669 mutex_exit(&asy->asy_excl_hi); 3670 mutex_exit(&asy->asy_excl); 3671 asyerror(asy, CE_WARN, "silo overflow"); 3672 mutex_enter(&asy->asy_excl); 3673 mutex_enter(&asy->asy_excl_hi); 3674 } 3675 async->async_hw_overrun = 0; 3676 } 3677 if (async->async_sw_overrun) { 3678 if (async->async_flags & ASYNC_ISOPEN) { 3679 mutex_exit(&asy->asy_excl_hi); 3680 mutex_exit(&asy->asy_excl); 3681 asyerror(asy, CE_WARN, "ring buffer overflow"); 3682 mutex_enter(&asy->asy_excl); 3683 mutex_enter(&asy->asy_excl_hi); 3684 } 3685 async->async_sw_overrun = 0; 3686 } 3687 if (asy->asy_flags & ASY_DOINGSOFT_RETRY) { 3688 mutex_exit(&asy->asy_excl); 3689 goto begin; 3690 } 3691 asy->asy_flags &= ~ASY_DOINGSOFT; 3692 mutex_exit(&asy->asy_excl_hi); 3693 mutex_exit(&asy->asy_excl); 3694 ASY_DPRINTF(asy, ASY_DEBUG_PROCS, "done"); 3695 } 3696 3697 /* 3698 * Restart output on a line after a delay or break timer expired. 3699 */ 3700 static void 3701 async_restart(void *arg) 3702 { 3703 struct asyncline *async = (struct asyncline *)arg; 3704 struct asycom *asy = async->async_common; 3705 3706 ASY_DPRINTF(asy, ASY_DEBUG_PROCS, "enter"); 3707 3708 /* 3709 * If break timer expired, turn off the break bit. 3710 */ 3711 3712 mutex_enter(&asy->asy_excl); 3713 /* 3714 * If ASYNC_OUT_SUSPEND is also set, we don't really 3715 * clean the HW break, TIOCCBRK is responsible for this. 3716 */ 3717 if ((async->async_flags & ASYNC_BREAK) && 3718 !(async->async_flags & ASYNC_OUT_SUSPEND)) { 3719 mutex_enter(&asy->asy_excl_hi); 3720 asy_clr(asy, ASY_LCR, ASY_LCR_SETBRK); 3721 mutex_exit(&asy->asy_excl_hi); 3722 } 3723 async->async_flags &= ~(ASYNC_DELAY|ASYNC_BREAK); 3724 cv_broadcast(&async->async_flags_cv); 3725 async_start(async); 3726 3727 mutex_exit(&asy->asy_excl); 3728 } 3729 3730 /* 3731 * Start output on a line, unless it's busy, frozen, or otherwise. 3732 */ 3733 static void 3734 async_start(struct asyncline *async) 3735 { 3736 struct asycom *asy = async->async_common; 3737 int cc; 3738 queue_t *q; 3739 mblk_t *bp; 3740 uchar_t *xmit_addr; 3741 int fifo_len = 1; 3742 boolean_t didsome; 3743 mblk_t *nbp; 3744 3745 ASY_DPRINTF(asy, ASY_DEBUG_PROCS, "enter"); 3746 3747 if (asy->asy_use_fifo == ASY_FCR_FIFO_EN) { 3748 fifo_len = asy->asy_fifo_buf; /* with FIFO buffers */ 3749 if (fifo_len > asy_max_tx_fifo) 3750 fifo_len = asy_max_tx_fifo; 3751 } 3752 3753 ASSERT(mutex_owned(&asy->asy_excl)); 3754 3755 /* 3756 * If the chip is busy (i.e., we're waiting for a break timeout 3757 * to expire, or for the current transmission to finish, or for 3758 * output to finish draining from chip), don't grab anything new. 3759 */ 3760 if (async->async_flags & (ASYNC_BREAK|ASYNC_BUSY)) { 3761 ASY_DPRINTF(asy, ASY_DEBUG_OUT, "%s", 3762 async->async_flags & ASYNC_BREAK ? "break" : "busy"); 3763 return; 3764 } 3765 3766 /* 3767 * Check only pended sw input flow control. 3768 */ 3769 mutex_enter(&asy->asy_excl_hi); 3770 if (async_flowcontrol_sw_input(asy, FLOW_CHECK, IN_FLOW_NULL)) 3771 fifo_len--; 3772 mutex_exit(&asy->asy_excl_hi); 3773 3774 /* 3775 * If we're waiting for a delay timeout to expire, don't grab 3776 * anything new. 3777 */ 3778 if (async->async_flags & ASYNC_DELAY) { 3779 ASY_DPRINTF(asy, ASY_DEBUG_OUT, "start ASYNC_DELAY"); 3780 return; 3781 } 3782 3783 if ((q = async->async_ttycommon.t_writeq) == NULL) { 3784 ASY_DPRINTF(asy, ASY_DEBUG_OUT, "start writeq is null"); 3785 return; /* not attached to a stream */ 3786 } 3787 3788 for (;;) { 3789 if ((bp = getq(q)) == NULL) 3790 return; /* no data to transmit */ 3791 3792 /* 3793 * We have a message block to work on. 3794 * Check whether it's a break, a delay, or an ioctl (the latter 3795 * occurs if the ioctl in question was waiting for the output 3796 * to drain). If it's one of those, process it immediately. 3797 */ 3798 switch (bp->b_datap->db_type) { 3799 3800 case M_BREAK: 3801 /* 3802 * Set the break bit, and arrange for "async_restart" 3803 * to be called in 1/4 second; it will turn the 3804 * break bit off, and call "async_start" to grab 3805 * the next message. 3806 */ 3807 mutex_enter(&asy->asy_excl_hi); 3808 asy_set(asy, ASY_LCR, ASY_LCR_SETBRK); 3809 mutex_exit(&asy->asy_excl_hi); 3810 async->async_flags |= ASYNC_BREAK; 3811 (void) timeout(async_restart, (caddr_t)async, 3812 drv_usectohz(1000000)/4); 3813 freemsg(bp); 3814 return; /* wait for this to finish */ 3815 3816 case M_DELAY: 3817 /* 3818 * Arrange for "async_restart" to be called when the 3819 * delay expires; it will turn ASYNC_DELAY off, 3820 * and call "async_start" to grab the next message. 3821 */ 3822 (void) timeout(async_restart, (caddr_t)async, 3823 (int)(*(unsigned char *)bp->b_rptr + 6)); 3824 async->async_flags |= ASYNC_DELAY; 3825 freemsg(bp); 3826 return; /* wait for this to finish */ 3827 3828 case M_IOCTL: 3829 /* 3830 * This ioctl was waiting for the output ahead of 3831 * it to drain; obviously, it has. Do it, and 3832 * then grab the next message after it. 3833 */ 3834 mutex_exit(&asy->asy_excl); 3835 async_ioctl(async, q, bp); 3836 mutex_enter(&asy->asy_excl); 3837 continue; 3838 } 3839 3840 while (bp != NULL && ((cc = MBLKL(bp)) == 0)) { 3841 nbp = bp->b_cont; 3842 freeb(bp); 3843 bp = nbp; 3844 } 3845 if (bp != NULL) 3846 break; 3847 } 3848 3849 /* 3850 * We have data to transmit. If output is stopped, put 3851 * it back and try again later. 3852 */ 3853 if (async->async_flags & (ASYNC_HW_OUT_FLW | ASYNC_SW_OUT_FLW | 3854 ASYNC_STOPPED | ASYNC_OUT_SUSPEND)) { 3855 (void) putbq(q, bp); 3856 return; 3857 } 3858 3859 async->async_xmitblk = bp; 3860 xmit_addr = bp->b_rptr; 3861 bp = bp->b_cont; 3862 if (bp != NULL) 3863 (void) putbq(q, bp); /* not done with this message yet */ 3864 3865 /* 3866 * In 5-bit mode, the high order bits are used 3867 * to indicate character sizes less than five, 3868 * so we need to explicitly mask before transmitting 3869 */ 3870 if ((async->async_ttycommon.t_cflag & CSIZE) == CS5) { 3871 unsigned char *p = xmit_addr; 3872 int cnt = cc; 3873 3874 while (cnt--) 3875 *p++ &= (unsigned char) 0x1f; 3876 } 3877 3878 /* 3879 * Set up this block for pseudo-DMA. 3880 */ 3881 mutex_enter(&asy->asy_excl_hi); 3882 /* 3883 * If the transmitter is ready, shove the first 3884 * character out. 3885 */ 3886 didsome = B_FALSE; 3887 while (--fifo_len >= 0 && cc > 0) { 3888 if (!(asy_get(asy, ASY_LSR) & ASY_LSR_THRE)) 3889 break; 3890 asy_put(asy, ASY_THR, *xmit_addr++); 3891 cc--; 3892 didsome = B_TRUE; 3893 } 3894 async->async_optr = xmit_addr; 3895 async->async_ocnt = cc; 3896 if (didsome) 3897 async->async_flags |= ASYNC_PROGRESS; 3898 ASY_DPRINTF(asy, ASY_DEBUG_BUSY, "Set ASYNC_BUSY, async_ocnt=%d", 3899 async->async_ocnt); 3900 async->async_flags |= ASYNC_BUSY; 3901 mutex_exit(&asy->asy_excl_hi); 3902 } 3903 3904 /* 3905 * Resume output by poking the transmitter. 3906 */ 3907 static void 3908 async_resume(struct asyncline *async) 3909 { 3910 struct asycom *asy = async->async_common; 3911 3912 ASY_DPRINTF(asy, ASY_DEBUG_PROCS, "enter"); 3913 ASSERT(mutex_owned(&asy->asy_excl_hi)); 3914 3915 if (asy_get(asy, ASY_LSR) & ASY_LSR_THRE) { 3916 if (async_flowcontrol_sw_input(asy, FLOW_CHECK, IN_FLOW_NULL)) 3917 return; 3918 if (async->async_ocnt > 0 && 3919 !(async->async_flags & 3920 (ASYNC_HW_OUT_FLW|ASYNC_SW_OUT_FLW|ASYNC_OUT_SUSPEND))) { 3921 asy_put(asy, ASY_THR, *async->async_optr++); 3922 async->async_ocnt--; 3923 async->async_flags |= ASYNC_PROGRESS; 3924 } 3925 } 3926 } 3927 3928 /* 3929 * Hold the untimed break to last the minimum time. 3930 */ 3931 static void 3932 async_hold_utbrk(void *arg) 3933 { 3934 struct asyncline *async = arg; 3935 struct asycom *asy = async->async_common; 3936 3937 mutex_enter(&asy->asy_excl); 3938 async->async_flags &= ~ASYNC_HOLD_UTBRK; 3939 cv_broadcast(&async->async_flags_cv); 3940 async->async_utbrktid = 0; 3941 mutex_exit(&asy->asy_excl); 3942 } 3943 3944 /* 3945 * Resume the untimed break. 3946 */ 3947 static void 3948 async_resume_utbrk(struct asyncline *async) 3949 { 3950 struct asycom *asy = async->async_common; 3951 ASSERT(mutex_owned(&asy->asy_excl)); 3952 3953 /* 3954 * Because the wait time is very short, 3955 * so we use uninterruptably wait. 3956 */ 3957 while (async->async_flags & ASYNC_HOLD_UTBRK) { 3958 cv_wait(&async->async_flags_cv, &asy->asy_excl); 3959 } 3960 mutex_enter(&asy->asy_excl_hi); 3961 /* 3962 * Timed break and untimed break can exist simultaneously, 3963 * if ASYNC_BREAK is also set at here, we don't 3964 * really clean the HW break. 3965 */ 3966 if (!(async->async_flags & ASYNC_BREAK)) 3967 asy_clr(asy, ASY_LCR, ASY_LCR_SETBRK); 3968 3969 async->async_flags &= ~ASYNC_OUT_SUSPEND; 3970 cv_broadcast(&async->async_flags_cv); 3971 if (async->async_ocnt > 0) { 3972 async_resume(async); 3973 mutex_exit(&asy->asy_excl_hi); 3974 } else { 3975 async->async_flags &= ~ASYNC_BUSY; 3976 mutex_exit(&asy->asy_excl_hi); 3977 if (async->async_xmitblk != NULL) { 3978 freeb(async->async_xmitblk); 3979 async->async_xmitblk = NULL; 3980 } 3981 async_start(async); 3982 } 3983 } 3984 3985 /* 3986 * Process an "ioctl" message sent down to us. 3987 * Note that we don't need to get any locks until we are ready to access 3988 * the hardware. Nothing we access until then is going to be altered 3989 * outside of the STREAMS framework, so we should be safe. 3990 */ 3991 int asydelay = 10000; 3992 static void 3993 async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp) 3994 { 3995 struct asycom *asy = async->async_common; 3996 tty_common_t *tp = &async->async_ttycommon; 3997 struct iocblk *iocp; 3998 unsigned datasize; 3999 int error = 0; 4000 mblk_t *datamp; 4001 4002 ASY_DPRINTF(asy, ASY_DEBUG_PROCS, "enter"); 4003 4004 if (tp->t_iocpending != NULL) { 4005 /* 4006 * We were holding an "ioctl" response pending the 4007 * availability of an "mblk" to hold data to be passed up; 4008 * another "ioctl" came through, which means that "ioctl" 4009 * must have timed out or been aborted. 4010 */ 4011 freemsg(async->async_ttycommon.t_iocpending); 4012 async->async_ttycommon.t_iocpending = NULL; 4013 } 4014 4015 iocp = (struct iocblk *)mp->b_rptr; 4016 4017 /* 4018 * For TIOCMGET and the PPS ioctls, do NOT call ttycommon_ioctl() 4019 * because this function frees up the message block (mp->b_cont) that 4020 * contains the user location where we pass back the results. 4021 * 4022 * Similarly, CONSOPENPOLLEDIO needs ioc_count, which ttycommon_ioctl 4023 * zaps. We know that ttycommon_ioctl doesn't know any CONS* 4024 * ioctls, so keep the others safe too. 4025 */ 4026 ASY_DPRINTF(asy, ASY_DEBUG_IOCTL, "%s", 4027 iocp->ioc_cmd == TIOCMGET ? "TIOCMGET" : 4028 iocp->ioc_cmd == TIOCMSET ? "TIOCMSET" : 4029 iocp->ioc_cmd == TIOCMBIS ? "TIOCMBIS" : 4030 iocp->ioc_cmd == TIOCMBIC ? "TIOCMBIC" : 4031 "other"); 4032 4033 switch (iocp->ioc_cmd) { 4034 case TIOCMGET: 4035 case TIOCGPPS: 4036 case TIOCSPPS: 4037 case TIOCGPPSEV: 4038 case CONSOPENPOLLEDIO: 4039 case CONSCLOSEPOLLEDIO: 4040 case CONSSETABORTENABLE: 4041 case CONSGETABORTENABLE: 4042 error = -1; /* Do Nothing */ 4043 break; 4044 default: 4045 4046 /* 4047 * The only way in which "ttycommon_ioctl" can fail is if the 4048 * "ioctl" requires a response containing data to be returned 4049 * to the user, and no mblk could be allocated for the data. 4050 * No such "ioctl" alters our state. Thus, we always go ahead 4051 * and do any state-changes the "ioctl" calls for. If we 4052 * couldn't allocate the data, "ttycommon_ioctl" has stashed 4053 * the "ioctl" away safely, so we just call "bufcall" to 4054 * request that we be called back when we stand a better 4055 * chance of allocating the data. 4056 */ 4057 if ((datasize = ttycommon_ioctl(tp, wq, mp, &error)) != 0) { 4058 if (async->async_wbufcid) 4059 unbufcall(async->async_wbufcid); 4060 async->async_wbufcid = bufcall(datasize, BPRI_HI, 4061 (void (*)(void *)) async_reioctl, 4062 (void *)(intptr_t)async->async_common->asy_unit); 4063 return; 4064 } 4065 } 4066 4067 mutex_enter(&asy->asy_excl); 4068 4069 if (error == 0) { 4070 /* 4071 * "ttycommon_ioctl" did most of the work; we just use the 4072 * data it set up. 4073 */ 4074 switch (iocp->ioc_cmd) { 4075 4076 case TCSETS: 4077 mutex_enter(&asy->asy_excl_hi); 4078 if (asy_baudok(asy)) 4079 asy_program(asy, ASY_NOINIT); 4080 else 4081 error = EINVAL; 4082 mutex_exit(&asy->asy_excl_hi); 4083 break; 4084 case TCSETSF: 4085 case TCSETSW: 4086 case TCSETA: 4087 case TCSETAW: 4088 case TCSETAF: 4089 mutex_enter(&asy->asy_excl_hi); 4090 if (!asy_baudok(asy)) 4091 error = EINVAL; 4092 else { 4093 if (asy_isbusy(asy)) 4094 asy_waiteot(asy); 4095 asy_program(asy, ASY_NOINIT); 4096 } 4097 mutex_exit(&asy->asy_excl_hi); 4098 break; 4099 } 4100 } else if (error < 0) { 4101 /* 4102 * "ttycommon_ioctl" didn't do anything; we process it here. 4103 */ 4104 error = 0; 4105 switch (iocp->ioc_cmd) { 4106 4107 case TIOCGPPS: 4108 /* 4109 * Get PPS on/off. 4110 */ 4111 if (mp->b_cont != NULL) 4112 freemsg(mp->b_cont); 4113 4114 mp->b_cont = allocb(sizeof (int), BPRI_HI); 4115 if (mp->b_cont == NULL) { 4116 error = ENOMEM; 4117 break; 4118 } 4119 if (asy->asy_flags & ASY_PPS) 4120 *(int *)mp->b_cont->b_wptr = 1; 4121 else 4122 *(int *)mp->b_cont->b_wptr = 0; 4123 mp->b_cont->b_wptr += sizeof (int); 4124 mp->b_datap->db_type = M_IOCACK; 4125 iocp->ioc_count = sizeof (int); 4126 break; 4127 4128 case TIOCSPPS: 4129 /* 4130 * Set PPS on/off. 4131 */ 4132 error = miocpullup(mp, sizeof (int)); 4133 if (error != 0) 4134 break; 4135 4136 mutex_enter(&asy->asy_excl_hi); 4137 if (*(int *)mp->b_cont->b_rptr) 4138 asy->asy_flags |= ASY_PPS; 4139 else 4140 asy->asy_flags &= ~ASY_PPS; 4141 /* Reset edge sense */ 4142 asy->asy_flags &= ~ASY_PPS_EDGE; 4143 mutex_exit(&asy->asy_excl_hi); 4144 mp->b_datap->db_type = M_IOCACK; 4145 break; 4146 4147 case TIOCGPPSEV: 4148 { 4149 /* 4150 * Get PPS event data. 4151 */ 4152 mblk_t *bp; 4153 void *buf; 4154 #ifdef _SYSCALL32_IMPL 4155 struct ppsclockev32 p32; 4156 #endif 4157 struct ppsclockev ppsclockev; 4158 4159 if (mp->b_cont != NULL) { 4160 freemsg(mp->b_cont); 4161 mp->b_cont = NULL; 4162 } 4163 4164 if ((asy->asy_flags & ASY_PPS) == 0) { 4165 error = ENXIO; 4166 break; 4167 } 4168 4169 /* Protect from incomplete asy_ppsev */ 4170 mutex_enter(&asy->asy_excl_hi); 4171 ppsclockev = asy_ppsev; 4172 mutex_exit(&asy->asy_excl_hi); 4173 4174 #ifdef _SYSCALL32_IMPL 4175 if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) { 4176 TIMEVAL_TO_TIMEVAL32(&p32.tv, &ppsclockev.tv); 4177 p32.serial = ppsclockev.serial; 4178 buf = &p32; 4179 iocp->ioc_count = sizeof (struct ppsclockev32); 4180 } else 4181 #endif 4182 { 4183 buf = &ppsclockev; 4184 iocp->ioc_count = sizeof (struct ppsclockev); 4185 } 4186 4187 if ((bp = allocb(iocp->ioc_count, BPRI_HI)) == NULL) { 4188 error = ENOMEM; 4189 break; 4190 } 4191 mp->b_cont = bp; 4192 4193 bcopy(buf, bp->b_wptr, iocp->ioc_count); 4194 bp->b_wptr += iocp->ioc_count; 4195 mp->b_datap->db_type = M_IOCACK; 4196 break; 4197 } 4198 4199 case TCSBRK: 4200 error = miocpullup(mp, sizeof (int)); 4201 if (error != 0) 4202 break; 4203 4204 if (*(int *)mp->b_cont->b_rptr == 0) { 4205 4206 /* 4207 * XXX Arrangements to ensure that a break 4208 * isn't in progress should be sufficient. 4209 * This ugly delay() is the only thing 4210 * that seems to work on the NCR Worldmark. 4211 * It should be replaced. Note that an 4212 * asy_waiteot() also does not work. 4213 */ 4214 if (asydelay) 4215 delay(drv_usectohz(asydelay)); 4216 4217 while (async->async_flags & ASYNC_BREAK) { 4218 cv_wait(&async->async_flags_cv, 4219 &asy->asy_excl); 4220 } 4221 mutex_enter(&asy->asy_excl_hi); 4222 /* 4223 * Wait until TSR is empty and then set the 4224 * break. ASYNC_BREAK has been set to ensure 4225 * that no characters are transmitted while the 4226 * TSR is being flushed and SOUT is being used 4227 * for the break signal. 4228 */ 4229 async->async_flags |= ASYNC_BREAK; 4230 asy_wait_baudrate(asy); 4231 /* 4232 * Arrange for "async_restart" 4233 * to be called in 1/4 second; 4234 * it will turn the break bit off, and call 4235 * "async_start" to grab the next message. 4236 */ 4237 asy_set(asy, ASY_LCR, ASY_LCR_SETBRK); 4238 mutex_exit(&asy->asy_excl_hi); 4239 (void) timeout(async_restart, (caddr_t)async, 4240 drv_usectohz(1000000)/4); 4241 } else { 4242 ASY_DPRINTF(asy, ASY_DEBUG_OUT, 4243 "wait for flush"); 4244 mutex_enter(&asy->asy_excl_hi); 4245 asy_waiteot(asy); 4246 mutex_exit(&asy->asy_excl_hi); 4247 ASY_DPRINTF(asy, ASY_DEBUG_OUT, 4248 "ldterm satisfied"); 4249 } 4250 break; 4251 4252 case TIOCSBRK: 4253 if (!(async->async_flags & ASYNC_OUT_SUSPEND)) { 4254 mutex_enter(&asy->asy_excl_hi); 4255 async->async_flags |= ASYNC_OUT_SUSPEND; 4256 async->async_flags |= ASYNC_HOLD_UTBRK; 4257 asy_wait_baudrate(asy); 4258 mutex_exit(&asy->asy_excl_hi); 4259 /* wait for 100ms to hold BREAK */ 4260 async->async_utbrktid = 4261 timeout((void (*)())async_hold_utbrk, 4262 (caddr_t)async, 4263 drv_usectohz(asy_min_utbrk)); 4264 } 4265 mioc2ack(mp, NULL, 0, 0); 4266 break; 4267 4268 case TIOCCBRK: 4269 if (async->async_flags & ASYNC_OUT_SUSPEND) 4270 async_resume_utbrk(async); 4271 mioc2ack(mp, NULL, 0, 0); 4272 break; 4273 4274 case TIOCMSET: 4275 case TIOCMBIS: 4276 case TIOCMBIC: 4277 if (iocp->ioc_count != TRANSPARENT) { 4278 ASY_DPRINTF(asy, ASY_DEBUG_IOCTL, 4279 "non-transparent"); 4280 4281 error = miocpullup(mp, sizeof (int)); 4282 if (error != 0) 4283 break; 4284 4285 mutex_enter(&asy->asy_excl_hi); 4286 (void) asymctl(asy, 4287 dmtoasy(asy, *(int *)mp->b_cont->b_rptr), 4288 iocp->ioc_cmd); 4289 mutex_exit(&asy->asy_excl_hi); 4290 iocp->ioc_error = 0; 4291 mp->b_datap->db_type = M_IOCACK; 4292 } else { 4293 ASY_DPRINTF(asy, ASY_DEBUG_IOCTL, 4294 "transparent"); 4295 mcopyin(mp, NULL, sizeof (int), NULL); 4296 } 4297 break; 4298 4299 case TIOCMGET: 4300 datamp = allocb(sizeof (int), BPRI_MED); 4301 if (datamp == NULL) { 4302 error = EAGAIN; 4303 break; 4304 } 4305 4306 mutex_enter(&asy->asy_excl_hi); 4307 *(int *)datamp->b_rptr = asymctl(asy, 0, TIOCMGET); 4308 mutex_exit(&asy->asy_excl_hi); 4309 4310 if (iocp->ioc_count == TRANSPARENT) { 4311 ASY_DPRINTF(asy, ASY_DEBUG_IOCTL, 4312 "transparent"); 4313 mcopyout(mp, NULL, sizeof (int), NULL, datamp); 4314 } else { 4315 ASY_DPRINTF(asy, ASY_DEBUG_IOCTL, 4316 "non-transparent"); 4317 mioc2ack(mp, datamp, sizeof (int), 0); 4318 } 4319 break; 4320 4321 case CONSOPENPOLLEDIO: 4322 error = miocpullup(mp, sizeof (struct cons_polledio *)); 4323 if (error != 0) 4324 break; 4325 4326 *(struct cons_polledio **)mp->b_cont->b_rptr = 4327 &asy->polledio; 4328 4329 mp->b_datap->db_type = M_IOCACK; 4330 break; 4331 4332 case CONSCLOSEPOLLEDIO: 4333 mp->b_datap->db_type = M_IOCACK; 4334 iocp->ioc_error = 0; 4335 iocp->ioc_rval = 0; 4336 break; 4337 4338 case CONSSETABORTENABLE: 4339 error = secpolicy_console(iocp->ioc_cr); 4340 if (error != 0) 4341 break; 4342 4343 if (iocp->ioc_count != TRANSPARENT) { 4344 error = EINVAL; 4345 break; 4346 } 4347 4348 mutex_enter(&asy->asy_excl_hi); 4349 if (*(intptr_t *)mp->b_cont->b_rptr) 4350 asy->asy_flags |= ASY_CONSOLE; 4351 else 4352 asy->asy_flags &= ~ASY_CONSOLE; 4353 mutex_exit(&asy->asy_excl_hi); 4354 4355 mp->b_datap->db_type = M_IOCACK; 4356 iocp->ioc_error = 0; 4357 iocp->ioc_rval = 0; 4358 break; 4359 4360 case CONSGETABORTENABLE: 4361 /*CONSTANTCONDITION*/ 4362 ASSERT(sizeof (boolean_t) <= sizeof (boolean_t *)); 4363 /* 4364 * Store the return value right in the payload 4365 * we were passed. Crude. 4366 */ 4367 mcopyout(mp, NULL, sizeof (boolean_t), NULL, NULL); 4368 *(boolean_t *)mp->b_cont->b_rptr = 4369 (asy->asy_flags & ASY_CONSOLE) != 0; 4370 break; 4371 4372 default: 4373 /* 4374 * If we don't understand it, it's an error. NAK it. 4375 */ 4376 error = EINVAL; 4377 break; 4378 } 4379 } 4380 if (error != 0) { 4381 iocp->ioc_error = error; 4382 mp->b_datap->db_type = M_IOCNAK; 4383 } 4384 mutex_exit(&asy->asy_excl); 4385 qreply(wq, mp); 4386 ASY_DPRINTF(asy, ASY_DEBUG_PROCS, "done"); 4387 } 4388 4389 static int 4390 asyrsrv(queue_t *q) 4391 { 4392 mblk_t *bp; 4393 struct asyncline *async; 4394 struct asycom *asy; 4395 4396 async = (struct asyncline *)q->q_ptr; 4397 asy = (struct asycom *)async->async_common; 4398 4399 while (canputnext(q) && (bp = getq(q))) 4400 putnext(q, bp); 4401 mutex_enter(&asy->asy_excl_hi); 4402 asysetsoft(asy); 4403 mutex_exit(&asy->asy_excl_hi); 4404 async->async_polltid = 0; 4405 return (0); 4406 } 4407 4408 /* 4409 * The ASYWPUTDO_NOT_SUSP macro indicates to asywputdo() whether it should 4410 * handle messages as though the driver is operating normally or is 4411 * suspended. In the suspended case, some or all of the processing may have 4412 * to be delayed until the driver is resumed. 4413 */ 4414 #define ASYWPUTDO_NOT_SUSP(async, wput) \ 4415 !((wput) && ((async)->async_flags & ASYNC_DDI_SUSPENDED)) 4416 4417 /* 4418 * Processing for write queue put procedure. 4419 * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here; 4420 * set the flow control character for M_STOPI and M_STARTI messages; 4421 * queue up M_BREAK, M_DELAY, and M_DATA messages for processing 4422 * by the start routine, and then call the start routine; discard 4423 * everything else. Note that this driver does not incorporate any 4424 * mechanism to negotiate to handle the canonicalization process. 4425 * It expects that these functions are handled in upper module(s), 4426 * as we do in ldterm. 4427 */ 4428 static int 4429 asywputdo(queue_t *q, mblk_t *mp, boolean_t wput) 4430 { 4431 struct asyncline *async; 4432 struct asycom *asy; 4433 int error; 4434 4435 async = (struct asyncline *)q->q_ptr; 4436 asy = async->async_common; 4437 4438 switch (mp->b_datap->db_type) { 4439 4440 case M_STOP: 4441 /* 4442 * Since we don't do real DMA, we can just let the 4443 * chip coast to a stop after applying the brakes. 4444 */ 4445 mutex_enter(&asy->asy_excl); 4446 async->async_flags |= ASYNC_STOPPED; 4447 mutex_exit(&asy->asy_excl); 4448 freemsg(mp); 4449 break; 4450 4451 case M_START: 4452 mutex_enter(&asy->asy_excl); 4453 if (async->async_flags & ASYNC_STOPPED) { 4454 async->async_flags &= ~ASYNC_STOPPED; 4455 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4456 /* 4457 * If an output operation is in progress, 4458 * resume it. Otherwise, prod the start 4459 * routine. 4460 */ 4461 if (async->async_ocnt > 0) { 4462 mutex_enter(&asy->asy_excl_hi); 4463 async_resume(async); 4464 mutex_exit(&asy->asy_excl_hi); 4465 } else { 4466 async_start(async); 4467 } 4468 } 4469 } 4470 mutex_exit(&asy->asy_excl); 4471 freemsg(mp); 4472 break; 4473 4474 case M_IOCTL: 4475 switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 4476 4477 case TCSBRK: 4478 error = miocpullup(mp, sizeof (int)); 4479 if (error != 0) { 4480 miocnak(q, mp, 0, error); 4481 return (0); 4482 } 4483 4484 if (*(int *)mp->b_cont->b_rptr != 0) { 4485 ASY_DPRINTF(asy, ASY_DEBUG_OUT, 4486 "flush request"); 4487 (void) putq(q, mp); 4488 4489 mutex_enter(&asy->asy_excl); 4490 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4491 /* 4492 * If an TIOCSBRK is in progress, 4493 * clean it as TIOCCBRK does, 4494 * then kick off output. 4495 * If TIOCSBRK is not in progress, 4496 * just kick off output. 4497 */ 4498 async_resume_utbrk(async); 4499 } 4500 mutex_exit(&asy->asy_excl); 4501 break; 4502 } 4503 /*FALLTHROUGH*/ 4504 case TCSETSW: 4505 case TCSETSF: 4506 case TCSETAW: 4507 case TCSETAF: 4508 /* 4509 * The changes do not take effect until all 4510 * output queued before them is drained. 4511 * Put this message on the queue, so that 4512 * "async_start" will see it when it's done 4513 * with the output before it. Poke the 4514 * start routine, just in case. 4515 */ 4516 (void) putq(q, mp); 4517 4518 mutex_enter(&asy->asy_excl); 4519 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4520 /* 4521 * If an TIOCSBRK is in progress, 4522 * clean it as TIOCCBRK does. 4523 * then kick off output. 4524 * If TIOCSBRK is not in progress, 4525 * just kick off output. 4526 */ 4527 async_resume_utbrk(async); 4528 } 4529 mutex_exit(&asy->asy_excl); 4530 break; 4531 4532 default: 4533 /* 4534 * Do it now. 4535 */ 4536 mutex_enter(&asy->asy_excl); 4537 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4538 mutex_exit(&asy->asy_excl); 4539 async_ioctl(async, q, mp); 4540 break; 4541 } 4542 async_put_suspq(asy, mp); 4543 mutex_exit(&asy->asy_excl); 4544 break; 4545 } 4546 break; 4547 4548 case M_FLUSH: 4549 if (*mp->b_rptr & FLUSHW) { 4550 mutex_enter(&asy->asy_excl); 4551 4552 /* 4553 * Abort any output in progress. 4554 */ 4555 mutex_enter(&asy->asy_excl_hi); 4556 if (async->async_flags & ASYNC_BUSY) { 4557 ASY_DPRINTF(asy, ASY_DEBUG_BUSY, 4558 "Clearing async_ocnt, " 4559 "leaving ASYNC_BUSY set"); 4560 async->async_ocnt = 0; 4561 async->async_flags &= ~ASYNC_BUSY; 4562 } /* if */ 4563 4564 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4565 /* Flush FIFO buffers */ 4566 if (asy->asy_use_fifo == ASY_FCR_FIFO_EN) { 4567 asy_reset_fifo(asy, ASY_FCR_THR_FL); 4568 } 4569 } 4570 mutex_exit(&asy->asy_excl_hi); 4571 4572 /* 4573 * Flush our write queue. 4574 */ 4575 flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */ 4576 if (async->async_xmitblk != NULL) { 4577 freeb(async->async_xmitblk); 4578 async->async_xmitblk = NULL; 4579 } 4580 mutex_exit(&asy->asy_excl); 4581 *mp->b_rptr &= ~FLUSHW; /* it has been flushed */ 4582 } 4583 if (*mp->b_rptr & FLUSHR) { 4584 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4585 mutex_enter(&asy->asy_excl); 4586 mutex_enter(&asy->asy_excl_hi); 4587 /* Flush FIFO buffers */ 4588 if (asy->asy_use_fifo == ASY_FCR_FIFO_EN) { 4589 asy_reset_fifo(asy, ASY_FCR_RHR_FL); 4590 } 4591 mutex_exit(&asy->asy_excl_hi); 4592 mutex_exit(&asy->asy_excl); 4593 } 4594 flushq(RD(q), FLUSHDATA); 4595 qreply(q, mp); /* give the read queues a crack at it */ 4596 } else { 4597 freemsg(mp); 4598 } 4599 4600 /* 4601 * We must make sure we process messages that survive the 4602 * write-side flush. 4603 */ 4604 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4605 mutex_enter(&asy->asy_excl); 4606 async_start(async); 4607 mutex_exit(&asy->asy_excl); 4608 } 4609 break; 4610 4611 case M_BREAK: 4612 case M_DELAY: 4613 case M_DATA: 4614 /* 4615 * Queue the message up to be transmitted, 4616 * and poke the start routine. 4617 */ 4618 (void) putq(q, mp); 4619 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4620 mutex_enter(&asy->asy_excl); 4621 async_start(async); 4622 mutex_exit(&asy->asy_excl); 4623 } 4624 break; 4625 4626 case M_STOPI: 4627 mutex_enter(&asy->asy_excl); 4628 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4629 mutex_enter(&asy->asy_excl_hi); 4630 if (!(async->async_inflow_source & IN_FLOW_USER)) { 4631 async_flowcontrol_hw_input(asy, FLOW_STOP, 4632 IN_FLOW_USER); 4633 (void) async_flowcontrol_sw_input(asy, 4634 FLOW_STOP, IN_FLOW_USER); 4635 } 4636 mutex_exit(&asy->asy_excl_hi); 4637 mutex_exit(&asy->asy_excl); 4638 freemsg(mp); 4639 break; 4640 } 4641 async_put_suspq(asy, mp); 4642 mutex_exit(&asy->asy_excl); 4643 break; 4644 4645 case M_STARTI: 4646 mutex_enter(&asy->asy_excl); 4647 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4648 mutex_enter(&asy->asy_excl_hi); 4649 if (async->async_inflow_source & IN_FLOW_USER) { 4650 async_flowcontrol_hw_input(asy, FLOW_START, 4651 IN_FLOW_USER); 4652 (void) async_flowcontrol_sw_input(asy, 4653 FLOW_START, IN_FLOW_USER); 4654 } 4655 mutex_exit(&asy->asy_excl_hi); 4656 mutex_exit(&asy->asy_excl); 4657 freemsg(mp); 4658 break; 4659 } 4660 async_put_suspq(asy, mp); 4661 mutex_exit(&asy->asy_excl); 4662 break; 4663 4664 case M_CTL: 4665 if (MBLKL(mp) >= sizeof (struct iocblk) && 4666 ((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_POSIXQUERY) { 4667 mutex_enter(&asy->asy_excl); 4668 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4669 ((struct iocblk *)mp->b_rptr)->ioc_cmd = 4670 MC_HAS_POSIX; 4671 mutex_exit(&asy->asy_excl); 4672 qreply(q, mp); 4673 break; 4674 } else { 4675 async_put_suspq(asy, mp); 4676 } 4677 } else { 4678 /* 4679 * These MC_SERVICE type messages are used by upper 4680 * modules to tell this driver to send input up 4681 * immediately, or that it can wait for normal 4682 * processing that may or may not be done. Sun 4683 * requires these for the mouse module. 4684 * (XXX - for x86?) 4685 */ 4686 mutex_enter(&asy->asy_excl); 4687 switch (*mp->b_rptr) { 4688 4689 case MC_SERVICEIMM: 4690 async->async_flags |= ASYNC_SERVICEIMM; 4691 break; 4692 4693 case MC_SERVICEDEF: 4694 async->async_flags &= ~ASYNC_SERVICEIMM; 4695 break; 4696 } 4697 mutex_exit(&asy->asy_excl); 4698 freemsg(mp); 4699 } 4700 break; 4701 4702 case M_IOCDATA: 4703 mutex_enter(&asy->asy_excl); 4704 if (ASYWPUTDO_NOT_SUSP(async, wput)) { 4705 mutex_exit(&asy->asy_excl); 4706 async_iocdata(q, mp); 4707 break; 4708 } 4709 async_put_suspq(asy, mp); 4710 mutex_exit(&asy->asy_excl); 4711 break; 4712 4713 default: 4714 freemsg(mp); 4715 break; 4716 } 4717 return (0); 4718 } 4719 4720 static int 4721 asywput(queue_t *q, mblk_t *mp) 4722 { 4723 return (asywputdo(q, mp, B_TRUE)); 4724 } 4725 4726 /* 4727 * Retry an "ioctl", now that "bufcall" claims we may be able to allocate 4728 * the buffer we need. 4729 */ 4730 static void 4731 async_reioctl(void *unit) 4732 { 4733 int instance = (uintptr_t)unit; 4734 struct asyncline *async; 4735 struct asycom *asy; 4736 queue_t *q; 4737 mblk_t *mp; 4738 4739 asy = ddi_get_soft_state(asy_soft_state, instance); 4740 ASSERT(asy != NULL); 4741 async = asy->asy_priv; 4742 4743 /* 4744 * The bufcall is no longer pending. 4745 */ 4746 mutex_enter(&asy->asy_excl); 4747 async->async_wbufcid = 0; 4748 if ((q = async->async_ttycommon.t_writeq) == NULL) { 4749 mutex_exit(&asy->asy_excl); 4750 return; 4751 } 4752 if ((mp = async->async_ttycommon.t_iocpending) != NULL) { 4753 /* not pending any more */ 4754 async->async_ttycommon.t_iocpending = NULL; 4755 mutex_exit(&asy->asy_excl); 4756 async_ioctl(async, q, mp); 4757 } else 4758 mutex_exit(&asy->asy_excl); 4759 } 4760 4761 static void 4762 async_iocdata(queue_t *q, mblk_t *mp) 4763 { 4764 struct asyncline *async = (struct asyncline *)q->q_ptr; 4765 struct asycom *asy; 4766 struct iocblk *ip; 4767 struct copyresp *csp; 4768 4769 asy = async->async_common; 4770 ip = (struct iocblk *)mp->b_rptr; 4771 csp = (struct copyresp *)mp->b_rptr; 4772 4773 if (csp->cp_rval != 0) { 4774 if (csp->cp_private) 4775 freemsg(csp->cp_private); 4776 freemsg(mp); 4777 return; 4778 } 4779 4780 mutex_enter(&asy->asy_excl); 4781 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "case %s", 4782 csp->cp_cmd == TIOCMGET ? "TIOCMGET" : 4783 csp->cp_cmd == TIOCMSET ? "TIOCMSET" : 4784 csp->cp_cmd == TIOCMBIS ? "TIOCMBIS" : 4785 "TIOCMBIC"); 4786 switch (csp->cp_cmd) { 4787 4788 case TIOCMGET: 4789 if (mp->b_cont) { 4790 freemsg(mp->b_cont); 4791 mp->b_cont = NULL; 4792 } 4793 mp->b_datap->db_type = M_IOCACK; 4794 ip->ioc_error = 0; 4795 ip->ioc_count = 0; 4796 ip->ioc_rval = 0; 4797 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); 4798 break; 4799 4800 case TIOCMSET: 4801 case TIOCMBIS: 4802 case TIOCMBIC: 4803 mutex_enter(&asy->asy_excl_hi); 4804 (void) asymctl(asy, dmtoasy(asy, *(int *)mp->b_cont->b_rptr), 4805 csp->cp_cmd); 4806 mutex_exit(&asy->asy_excl_hi); 4807 mioc2ack(mp, NULL, 0, 0); 4808 break; 4809 4810 default: 4811 mp->b_datap->db_type = M_IOCNAK; 4812 ip->ioc_error = EINVAL; 4813 break; 4814 } 4815 qreply(q, mp); 4816 mutex_exit(&asy->asy_excl); 4817 } 4818 4819 /* 4820 * debugger/console support routines. 4821 */ 4822 4823 /* 4824 * put a character out 4825 * Do not use interrupts. If char is LF, put out CR, LF. 4826 */ 4827 static void 4828 asyputchar(cons_polledio_arg_t arg, uchar_t c) 4829 { 4830 struct asycom *asy = (struct asycom *)arg; 4831 4832 if (c == '\n') 4833 asyputchar(arg, '\r'); 4834 4835 while ((asy_get_reg(asy, ASY_LSR) & ASY_LSR_THRE) == 0) { 4836 /* wait for xmit to finish */ 4837 drv_usecwait(10); 4838 } 4839 4840 /* put the character out */ 4841 asy_put_reg(asy, ASY_THR, c); 4842 } 4843 4844 /* 4845 * See if there's a character available. If no character is 4846 * available, return 0. Run in polled mode, no interrupts. 4847 */ 4848 static boolean_t 4849 asyischar(cons_polledio_arg_t arg) 4850 { 4851 struct asycom *asy = (struct asycom *)arg; 4852 4853 return ((asy_get_reg(asy, ASY_LSR) & ASY_LSR_DR) != 0); 4854 } 4855 4856 /* 4857 * Get a character. Run in polled mode, no interrupts. 4858 */ 4859 static int 4860 asygetchar(cons_polledio_arg_t arg) 4861 { 4862 struct asycom *asy = (struct asycom *)arg; 4863 4864 while (!asyischar(arg)) 4865 drv_usecwait(10); 4866 return (asy_get_reg(asy, ASY_RHR)); 4867 } 4868 4869 /* 4870 * Set or get the modem control status. 4871 */ 4872 static int 4873 asymctl(struct asycom *asy, int bits, int how) 4874 { 4875 int mcr_r, msr_r; 4876 4877 ASSERT(mutex_owned(&asy->asy_excl_hi)); 4878 ASSERT(mutex_owned(&asy->asy_excl)); 4879 4880 /* Read Modem Control Registers */ 4881 mcr_r = asy_get(asy, ASY_MCR); 4882 4883 switch (how) { 4884 4885 case TIOCMSET: 4886 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "TIOCMSET, bits = %x", bits); 4887 mcr_r = bits; /* Set bits */ 4888 break; 4889 4890 case TIOCMBIS: 4891 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "TIOCMBIS, bits = %x", bits); 4892 mcr_r |= bits; /* Mask in bits */ 4893 break; 4894 4895 case TIOCMBIC: 4896 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "TIOCMBIC, bits = %x", bits); 4897 mcr_r &= ~bits; /* Mask out bits */ 4898 break; 4899 4900 case TIOCMGET: 4901 /* Read Modem Status Registers */ 4902 /* 4903 * If modem interrupts are enabled, we return the 4904 * saved value of msr. We read MSR only in async_msint() 4905 */ 4906 if (asy_get(asy, ASY_IER) & ASY_IER_MIEN) { 4907 msr_r = asy->asy_msr; 4908 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 4909 "TIOCMGET, read msr_r = %x", msr_r); 4910 } else { 4911 msr_r = asy_get(asy, ASY_MSR); 4912 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, 4913 "TIOCMGET, read MSR = %x", msr_r); 4914 } 4915 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "modem_lines = %x", 4916 asytodm(mcr_r, msr_r)); 4917 return (asytodm(mcr_r, msr_r)); 4918 } 4919 4920 asy_put(asy, ASY_MCR, mcr_r); 4921 4922 return (mcr_r); 4923 } 4924 4925 static int 4926 asytodm(int mcr_r, int msr_r) 4927 { 4928 int b = 0; 4929 4930 /* MCR registers */ 4931 if (mcr_r & ASY_MCR_RTS) 4932 b |= TIOCM_RTS; 4933 4934 if (mcr_r & ASY_MCR_DTR) 4935 b |= TIOCM_DTR; 4936 4937 /* MSR registers */ 4938 if (msr_r & ASY_MSR_DCD) 4939 b |= TIOCM_CAR; 4940 4941 if (msr_r & ASY_MSR_CTS) 4942 b |= TIOCM_CTS; 4943 4944 if (msr_r & ASY_MSR_DSR) 4945 b |= TIOCM_DSR; 4946 4947 if (msr_r & ASY_MSR_RI) 4948 b |= TIOCM_RNG; 4949 return (b); 4950 } 4951 4952 static int 4953 dmtoasy(struct asycom *asy, int bits) 4954 { 4955 int b = 0; 4956 4957 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "bits = %x", bits); 4958 #ifdef CAN_NOT_SET /* only DTR and RTS can be set */ 4959 if (bits & TIOCM_CAR) 4960 b |= ASY_MSR_DCD; 4961 if (bits & TIOCM_CTS) 4962 b |= ASY_MSR_CTS; 4963 if (bits & TIOCM_DSR) 4964 b |= ASY_MSR_DSR; 4965 if (bits & TIOCM_RNG) 4966 b |= ASY_MSR_RI; 4967 #endif 4968 4969 if (bits & TIOCM_RTS) { 4970 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "set b & RTS"); 4971 b |= ASY_MCR_RTS; 4972 } 4973 if (bits & TIOCM_DTR) { 4974 ASY_DPRINTF(asy, ASY_DEBUG_MODEM, "set b & DTR"); 4975 b |= ASY_MCR_DTR; 4976 } 4977 4978 return (b); 4979 } 4980 4981 static void 4982 asyerror(const struct asycom *asy, int level, const char *fmt, ...) 4983 { 4984 va_list adx; 4985 static time_t last; 4986 static const char *lastfmt; 4987 time_t now; 4988 4989 /* 4990 * Don't print the same error message too often. 4991 * Print the message only if we have not printed the 4992 * message within the last second. 4993 * Note: that fmt cannot be a pointer to a string 4994 * stored on the stack. The fmt pointer 4995 * must be in the data segment otherwise lastfmt would point 4996 * to non-sense. 4997 */ 4998 now = gethrestime_sec(); 4999 if (last == now && lastfmt == fmt) 5000 return; 5001 5002 last = now; 5003 lastfmt = fmt; 5004 5005 va_start(adx, fmt); 5006 vdev_err(asy->asy_dip, level, fmt, adx); 5007 va_end(adx); 5008 } 5009 5010 /* 5011 * asy_parse_mode(dev_info_t *devi, struct asycom *asy) 5012 * The value of this property is in the form of "9600,8,n,1,-" 5013 * 1) speed: 9600, 4800, ... 5014 * 2) data bits 5015 * 3) parity: n(none), e(even), o(odd) 5016 * 4) stop bits 5017 * 5) handshake: -(none), h(hardware: rts/cts), s(software: xon/off) 5018 * 5019 * This parsing came from a SPARCstation eeprom. 5020 */ 5021 static void 5022 asy_parse_mode(dev_info_t *devi, struct asycom *asy) 5023 { 5024 char name[40]; 5025 char val[40]; 5026 int len; 5027 int ret; 5028 char *p; 5029 char *p1; 5030 5031 ASSERT(asy->asy_com_port != 0); 5032 5033 /* 5034 * Parse the ttyx-mode property 5035 */ 5036 (void) sprintf(name, "tty%c-mode", asy->asy_com_port + 'a' - 1); 5037 len = sizeof (val); 5038 ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len); 5039 if (ret != DDI_PROP_SUCCESS) { 5040 (void) sprintf(name, "com%c-mode", asy->asy_com_port + '0'); 5041 len = sizeof (val); 5042 ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len); 5043 } 5044 5045 /* no property to parse */ 5046 asy->asy_cflag = 0; 5047 if (ret != DDI_PROP_SUCCESS) 5048 return; 5049 5050 p = val; 5051 /* ---- baud rate ---- */ 5052 asy->asy_cflag = CREAD|B9600; /* initial default */ 5053 if (p && (p1 = strchr(p, ',')) != 0) { 5054 *p1++ = '\0'; 5055 } else { 5056 asy->asy_cflag |= ASY_LCR_BITS8; /* add default bits */ 5057 return; 5058 } 5059 5060 if (strcmp(p, "110") == 0) 5061 asy->asy_bidx = B110; 5062 else if (strcmp(p, "150") == 0) 5063 asy->asy_bidx = B150; 5064 else if (strcmp(p, "300") == 0) 5065 asy->asy_bidx = B300; 5066 else if (strcmp(p, "600") == 0) 5067 asy->asy_bidx = B600; 5068 else if (strcmp(p, "1200") == 0) 5069 asy->asy_bidx = B1200; 5070 else if (strcmp(p, "2400") == 0) 5071 asy->asy_bidx = B2400; 5072 else if (strcmp(p, "4800") == 0) 5073 asy->asy_bidx = B4800; 5074 else if (strcmp(p, "9600") == 0) 5075 asy->asy_bidx = B9600; 5076 else if (strcmp(p, "19200") == 0) 5077 asy->asy_bidx = B19200; 5078 else if (strcmp(p, "38400") == 0) 5079 asy->asy_bidx = B38400; 5080 else if (strcmp(p, "57600") == 0) 5081 asy->asy_bidx = B57600; 5082 else if (strcmp(p, "115200") == 0) 5083 asy->asy_bidx = B115200; 5084 else 5085 asy->asy_bidx = B9600; 5086 5087 asy->asy_cflag &= ~CBAUD; 5088 if (asy->asy_bidx > CBAUD) { /* > 38400 uses the CBAUDEXT bit */ 5089 asy->asy_cflag |= CBAUDEXT; 5090 asy->asy_cflag |= asy->asy_bidx - CBAUD - 1; 5091 } else { 5092 asy->asy_cflag |= asy->asy_bidx; 5093 } 5094 5095 ASSERT(asy->asy_bidx == BAUDINDEX(asy->asy_cflag)); 5096 5097 /* ---- Next item is data bits ---- */ 5098 p = p1; 5099 if (p && (p1 = strchr(p, ',')) != 0) { 5100 *p1++ = '\0'; 5101 } else { 5102 asy->asy_cflag |= ASY_LCR_BITS8; /* add default bits */ 5103 return; 5104 } 5105 switch (*p) { 5106 default: 5107 case '8': 5108 asy->asy_cflag |= CS8; 5109 asy->asy_lcr = ASY_LCR_BITS8; 5110 break; 5111 case '7': 5112 asy->asy_cflag |= CS7; 5113 asy->asy_lcr = ASY_LCR_BITS7; 5114 break; 5115 case '6': 5116 asy->asy_cflag |= CS6; 5117 asy->asy_lcr = ASY_LCR_BITS6; 5118 break; 5119 case '5': 5120 /* LINTED: CS5 is currently zero (but might change) */ 5121 asy->asy_cflag |= CS5; 5122 asy->asy_lcr = ASY_LCR_BITS5; 5123 break; 5124 } 5125 5126 /* ---- Parity info ---- */ 5127 p = p1; 5128 if (p && (p1 = strchr(p, ',')) != 0) { 5129 *p1++ = '\0'; 5130 } else { 5131 return; 5132 } 5133 switch (*p) { 5134 default: 5135 case 'n': 5136 break; 5137 case 'e': 5138 asy->asy_cflag |= PARENB; 5139 asy->asy_lcr |= ASY_LCR_PEN; 5140 break; 5141 case 'o': 5142 asy->asy_cflag |= PARENB|PARODD; 5143 asy->asy_lcr |= ASY_LCR_PEN | ASY_LCR_EPS; 5144 break; 5145 } 5146 5147 /* ---- Find stop bits ---- */ 5148 p = p1; 5149 if (p && (p1 = strchr(p, ',')) != 0) { 5150 *p1++ = '\0'; 5151 } else { 5152 return; 5153 } 5154 if (*p == '2') { 5155 asy->asy_cflag |= CSTOPB; 5156 asy->asy_lcr |= ASY_LCR_STB; 5157 } 5158 5159 /* ---- handshake is next ---- */ 5160 p = p1; 5161 if (p) { 5162 if ((p1 = strchr(p, ',')) != 0) 5163 *p1++ = '\0'; 5164 5165 if (*p == 'h') 5166 asy->asy_cflag |= CRTSCTS; 5167 else if (*p == 's') 5168 asy->asy_cflag |= CRTSXOFF; 5169 } 5170 } 5171 5172 /* 5173 * Check for abort character sequence 5174 */ 5175 static boolean_t 5176 abort_charseq_recognize(uchar_t ch) 5177 { 5178 static int state = 0; 5179 #define CNTRL(c) ((c)&037) 5180 static char sequence[] = { '\r', '~', CNTRL('b') }; 5181 5182 if (ch == sequence[state]) { 5183 if (++state >= sizeof (sequence)) { 5184 state = 0; 5185 return (B_TRUE); 5186 } 5187 } else { 5188 state = (ch == sequence[0]) ? 1 : 0; 5189 } 5190 return (B_FALSE); 5191 } 5192 5193 /* 5194 * Flow control functions 5195 */ 5196 /* 5197 * Software input flow control 5198 * This function can execute software input flow control sucessfully 5199 * at most of situations except that the line is in BREAK status 5200 * (timed and untimed break). 5201 * INPUT VALUE of onoff: 5202 * FLOW_START means to send out a XON char 5203 * and clear SW input flow control flag. 5204 * FLOW_STOP means to send out a XOFF char 5205 * and set SW input flow control flag. 5206 * FLOW_CHECK means to check whether there is pending XON/XOFF 5207 * if it is true, send it out. 5208 * INPUT VALUE of type: 5209 * IN_FLOW_RINGBUFF means flow control is due to RING BUFFER 5210 * IN_FLOW_STREAMS means flow control is due to STREAMS 5211 * IN_FLOW_USER means flow control is due to user's commands 5212 * RETURN VALUE: B_FALSE means no flow control char is sent 5213 * B_TRUE means one flow control char is sent 5214 */ 5215 static boolean_t 5216 async_flowcontrol_sw_input(struct asycom *asy, async_flowc_action onoff, 5217 int type) 5218 { 5219 struct asyncline *async = asy->asy_priv; 5220 int rval = B_FALSE; 5221 5222 ASSERT(mutex_owned(&asy->asy_excl_hi)); 5223 5224 if (!(async->async_ttycommon.t_iflag & IXOFF)) 5225 return (rval); 5226 5227 /* 5228 * If we get this far, then we know IXOFF is set. 5229 */ 5230 switch (onoff) { 5231 case FLOW_STOP: 5232 async->async_inflow_source |= type; 5233 5234 /* 5235 * We'll send an XOFF character for each of up to 5236 * three different input flow control attempts to stop input. 5237 * If we already send out one XOFF, but FLOW_STOP comes again, 5238 * it seems that input flow control becomes more serious, 5239 * then send XOFF again. 5240 */ 5241 if (async->async_inflow_source & (IN_FLOW_RINGBUFF | 5242 IN_FLOW_STREAMS | IN_FLOW_USER)) 5243 async->async_flags |= ASYNC_SW_IN_FLOW | 5244 ASYNC_SW_IN_NEEDED; 5245 ASY_DPRINTF(asy, ASY_DEBUG_SFLOW, "input sflow stop, type = %x", 5246 async->async_inflow_source); 5247 break; 5248 case FLOW_START: 5249 async->async_inflow_source &= ~type; 5250 if (async->async_inflow_source == 0) { 5251 async->async_flags = (async->async_flags & 5252 ~ASYNC_SW_IN_FLOW) | ASYNC_SW_IN_NEEDED; 5253 ASY_DPRINTF(asy, ASY_DEBUG_SFLOW, "input sflow start"); 5254 } 5255 break; 5256 default: 5257 break; 5258 } 5259 5260 if (((async->async_flags & (ASYNC_SW_IN_NEEDED | ASYNC_BREAK | 5261 ASYNC_OUT_SUSPEND)) == ASYNC_SW_IN_NEEDED) && 5262 (asy_get(asy, ASY_LSR) & ASY_LSR_THRE)) { 5263 /* 5264 * If we get this far, then we know we need to send out 5265 * XON or XOFF char. 5266 */ 5267 async->async_flags = (async->async_flags & 5268 ~ASYNC_SW_IN_NEEDED) | ASYNC_BUSY; 5269 asy_put(asy, ASY_THR, 5270 async->async_flags & ASYNC_SW_IN_FLOW ? 5271 async->async_stopc : async->async_startc); 5272 rval = B_TRUE; 5273 } 5274 return (rval); 5275 } 5276 5277 /* 5278 * Software output flow control 5279 * This function can be executed sucessfully at any situation. 5280 * It does not handle HW, and just change the SW output flow control flag. 5281 * INPUT VALUE of onoff: 5282 * FLOW_START means to clear SW output flow control flag, 5283 * also combine with HW output flow control status to 5284 * determine if we need to set ASYNC_OUT_FLW_RESUME. 5285 * FLOW_STOP means to set SW output flow control flag, 5286 * also clear ASYNC_OUT_FLW_RESUME. 5287 */ 5288 static void 5289 async_flowcontrol_sw_output(struct asycom *asy, async_flowc_action onoff) 5290 { 5291 struct asyncline *async = asy->asy_priv; 5292 5293 ASSERT(mutex_owned(&asy->asy_excl_hi)); 5294 5295 if (!(async->async_ttycommon.t_iflag & IXON)) 5296 return; 5297 5298 switch (onoff) { 5299 case FLOW_STOP: 5300 async->async_flags |= ASYNC_SW_OUT_FLW; 5301 async->async_flags &= ~ASYNC_OUT_FLW_RESUME; 5302 ASY_DPRINTF(asy, ASY_DEBUG_SFLOW, "output sflow stop"); 5303 break; 5304 case FLOW_START: 5305 async->async_flags &= ~ASYNC_SW_OUT_FLW; 5306 if (!(async->async_flags & ASYNC_HW_OUT_FLW)) 5307 async->async_flags |= ASYNC_OUT_FLW_RESUME; 5308 ASY_DPRINTF(asy, ASY_DEBUG_SFLOW, "output sflow start"); 5309 break; 5310 default: 5311 break; 5312 } 5313 } 5314 5315 /* 5316 * Hardware input flow control 5317 * This function can be executed sucessfully at any situation. 5318 * It directly changes RTS depending on input parameter onoff. 5319 * INPUT VALUE of onoff: 5320 * FLOW_START means to clear HW input flow control flag, 5321 * and pull up RTS if it is low. 5322 * FLOW_STOP means to set HW input flow control flag, 5323 * and low RTS if it is high. 5324 * INPUT VALUE of type: 5325 * IN_FLOW_RINGBUFF means flow control is due to RING BUFFER 5326 * IN_FLOW_STREAMS means flow control is due to STREAMS 5327 * IN_FLOW_USER means flow control is due to user's commands 5328 */ 5329 static void 5330 async_flowcontrol_hw_input(struct asycom *asy, async_flowc_action onoff, 5331 int type) 5332 { 5333 uchar_t mcr; 5334 uchar_t flag; 5335 struct asyncline *async = asy->asy_priv; 5336 5337 ASSERT(mutex_owned(&asy->asy_excl_hi)); 5338 5339 if (!(async->async_ttycommon.t_cflag & CRTSXOFF)) 5340 return; 5341 5342 switch (onoff) { 5343 case FLOW_STOP: 5344 async->async_inflow_source |= type; 5345 if (async->async_inflow_source & (IN_FLOW_RINGBUFF | 5346 IN_FLOW_STREAMS | IN_FLOW_USER)) 5347 async->async_flags |= ASYNC_HW_IN_FLOW; 5348 ASY_DPRINTF(asy, ASY_DEBUG_HFLOW, "input hflow stop, type = %x", 5349 async->async_inflow_source); 5350 break; 5351 case FLOW_START: 5352 async->async_inflow_source &= ~type; 5353 if (async->async_inflow_source == 0) { 5354 async->async_flags &= ~ASYNC_HW_IN_FLOW; 5355 ASY_DPRINTF(asy, ASY_DEBUG_HFLOW, "input hflow start"); 5356 } 5357 break; 5358 default: 5359 break; 5360 } 5361 mcr = asy_get(asy, ASY_MCR); 5362 flag = (async->async_flags & ASYNC_HW_IN_FLOW) ? 0 : ASY_MCR_RTS; 5363 5364 if (((mcr ^ flag) & ASY_MCR_RTS) != 0) { 5365 asy_put(asy, ASY_MCR, (mcr ^ ASY_MCR_RTS)); 5366 } 5367 } 5368 5369 /* 5370 * Hardware output flow control 5371 * This function can execute HW output flow control sucessfully 5372 * at any situation. 5373 * It doesn't really change RTS, and just change 5374 * HW output flow control flag depending on CTS status. 5375 * INPUT VALUE of onoff: 5376 * FLOW_START means to clear HW output flow control flag. 5377 * also combine with SW output flow control status to 5378 * determine if we need to set ASYNC_OUT_FLW_RESUME. 5379 * FLOW_STOP means to set HW output flow control flag. 5380 * also clear ASYNC_OUT_FLW_RESUME. 5381 */ 5382 static void 5383 async_flowcontrol_hw_output(struct asycom *asy, async_flowc_action onoff) 5384 { 5385 struct asyncline *async = asy->asy_priv; 5386 5387 ASSERT(mutex_owned(&asy->asy_excl_hi)); 5388 5389 if (!(async->async_ttycommon.t_cflag & CRTSCTS)) 5390 return; 5391 5392 switch (onoff) { 5393 case FLOW_STOP: 5394 async->async_flags |= ASYNC_HW_OUT_FLW; 5395 async->async_flags &= ~ASYNC_OUT_FLW_RESUME; 5396 ASY_DPRINTF(asy, ASY_DEBUG_HFLOW, "output hflow stop"); 5397 break; 5398 case FLOW_START: 5399 async->async_flags &= ~ASYNC_HW_OUT_FLW; 5400 if (!(async->async_flags & ASYNC_SW_OUT_FLW)) 5401 async->async_flags |= ASYNC_OUT_FLW_RESUME; 5402 ASY_DPRINTF(asy, ASY_DEBUG_HFLOW, "output hflow start"); 5403 break; 5404 default: 5405 break; 5406 } 5407 } 5408 5409 /* 5410 * quiesce(9E) entry point. 5411 * 5412 * This function is called when the system is single-threaded at high 5413 * PIL with preemption disabled. Therefore, this function must not be 5414 * blocked. 5415 * 5416 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 5417 * DDI_FAILURE indicates an error condition and should almost never happen. 5418 */ 5419 static int 5420 asyquiesce(dev_info_t *devi) 5421 { 5422 int instance; 5423 struct asycom *asy; 5424 5425 instance = ddi_get_instance(devi); /* find out which unit */ 5426 5427 asy = ddi_get_soft_state(asy_soft_state, instance); 5428 if (asy == NULL) 5429 return (DDI_FAILURE); 5430 5431 asy_disable_interrupts(asy, ASY_IER_ALL); 5432 5433 /* Flush the FIFOs */ 5434 asy_reset_fifo(asy, ASY_FCR_THR_FL | ASY_FCR_RHR_FL); 5435 5436 return (DDI_SUCCESS); 5437 } 5438