Home | History | Annotate | Download | only in usbser
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 /*
     28  *
     29  * USB generic serial driver (GSD)
     30  *
     31  */
     32 #include <sys/types.h>
     33 #include <sys/param.h>
     34 #include <sys/stream.h>
     35 #include <sys/stropts.h>
     36 #include <sys/errno.h>
     37 #include <sys/cred.h>
     38 #include <sys/conf.h>
     39 #include <sys/stat.h>
     40 #include <sys/modctl.h>
     41 #include <sys/ddi.h>
     42 #include <sys/sunddi.h>
     43 #include <sys/sunndi.h>
     44 #include <sys/termio.h>
     45 #include <sys/termiox.h>
     46 #include <sys/stropts.h>
     47 #include <sys/stream.h>
     48 #include <sys/strsubr.h>
     49 #include <sys/strsun.h>
     50 #include <sys/strtty.h>
     51 #include <sys/policy.h>
     52 #include <sys/consdev.h>
     53 
     54 #include <sys/usb/usba.h>
     55 #include <sys/usb/clients/usbser/usbser_var.h>
     56 #include <sys/usb/clients/usbser/usbser_dsdi.h>
     57 #include <sys/usb/clients/usbser/usbser_rseq.h>
     58 #include <sys/usb/usba/genconsole.h>
     59 
     60 /* autoconfiguration subroutines */
     61 static int	usbser_rseq_do_cb(rseq_t *, int, uintptr_t);
     62 static int	usbser_free_soft_state(usbser_state_t *);
     63 static int	usbser_init_soft_state(usbser_state_t *);
     64 static int	usbser_fini_soft_state(usbser_state_t *);
     65 static int	usbser_attach_dev(usbser_state_t *);
     66 static void	usbser_detach_dev(usbser_state_t *);
     67 static int	usbser_attach_ports(usbser_state_t *);
     68 static int	usbser_create_port_minor_nodes(usbser_state_t *, int);
     69 static void	usbser_detach_ports(usbser_state_t *);
     70 static int	usbser_create_taskq(usbser_state_t *);
     71 static void	usbser_destroy_taskq(usbser_state_t *);
     72 static void	usbser_set_dev_state_init(usbser_state_t *);
     73 
     74 /* hotplugging and power management */
     75 static int	usbser_disconnect_cb(dev_info_t *);
     76 static int	usbser_reconnect_cb(dev_info_t *);
     77 static void	usbser_disconnect_ports(usbser_state_t *);
     78 static int	usbser_cpr_suspend(dev_info_t *);
     79 static int	usbser_suspend_ports(usbser_state_t *);
     80 static void	usbser_cpr_resume(dev_info_t *);
     81 static int	usbser_restore_device_state(usbser_state_t *);
     82 static void	usbser_restore_ports_state(usbser_state_t *);
     83 
     84 /* STREAMS subroutines */
     85 static int	usbser_open_setup(queue_t *, usbser_port_t *, int, int,
     86 		cred_t *);
     87 static int	usbser_open_init(usbser_port_t *, int);
     88 static void	usbser_check_port_props(usbser_port_t *);
     89 static void	usbser_open_fini(usbser_port_t *);
     90 static int	usbser_open_line_setup(usbser_port_t *, int, int);
     91 static int	usbser_open_carrier_check(usbser_port_t *, int, int);
     92 static void	usbser_open_queues_init(usbser_port_t *, queue_t *);
     93 static void	usbser_open_queues_fini(usbser_port_t *);
     94 static void	usbser_close_drain(usbser_port_t *);
     95 static void	usbser_close_cancel_break(usbser_port_t *);
     96 static void	usbser_close_hangup(usbser_port_t *);
     97 static void	usbser_close_cleanup(usbser_port_t *);
     98 
     99 /* threads */
    100 static void	usbser_thr_dispatch(usbser_thread_t *);
    101 static void	usbser_thr_cancel(usbser_thread_t *);
    102 static void	usbser_thr_wake(usbser_thread_t *);
    103 static void	usbser_wq_thread(void *);
    104 static void	usbser_rq_thread(void *);
    105 
    106 /* DSD callbacks */
    107 static void	usbser_tx_cb(caddr_t);
    108 static void	usbser_rx_cb(caddr_t);
    109 static void	usbser_rx_massage_data(usbser_port_t *, mblk_t *);
    110 static void	usbser_rx_massage_mbreak(usbser_port_t *, mblk_t *);
    111 static void	usbser_rx_cb_put(usbser_port_t *, queue_t *, queue_t *,
    112 		mblk_t *);
    113 static void	usbser_status_cb(caddr_t);
    114 static void	usbser_status_proc_cb(usbser_port_t *);
    115 
    116 /* serial support */
    117 static void	usbser_wmsg(usbser_port_t *);
    118 static int	usbser_data(usbser_port_t *, mblk_t *);
    119 static int	usbser_ioctl(usbser_port_t *, mblk_t *);
    120 static void	usbser_iocdata(usbser_port_t *, mblk_t *);
    121 static void	usbser_stop(usbser_port_t *, mblk_t *);
    122 static void	usbser_start(usbser_port_t *, mblk_t *);
    123 static void	usbser_stopi(usbser_port_t *, mblk_t *);
    124 static void	usbser_starti(usbser_port_t *, mblk_t *);
    125 static void	usbser_flush(usbser_port_t *, mblk_t *);
    126 static void	usbser_break(usbser_port_t *, mblk_t *);
    127 static void	usbser_delay(usbser_port_t *, mblk_t *);
    128 static void	usbser_restart(void *);
    129 static int	usbser_port_program(usbser_port_t *);
    130 static void	usbser_inbound_flow_ctl(usbser_port_t *);
    131 
    132 /* misc */
    133 static int	usbser_dev_is_online(usbser_state_t *);
    134 static void	usbser_serialize_port_act(usbser_port_t *, int);
    135 static void	usbser_release_port_act(usbser_port_t *, int);
    136 static char	*usbser_msgtype2str(int);
    137 static char	*usbser_ioctl2str(int);
    138 
    139 
    140 /* USBA events */
    141 usb_event_t usbser_usb_events = {
    142 	usbser_disconnect_cb,	/* disconnect */
    143 	usbser_reconnect_cb,	/* reconnect */
    144 	NULL,			/* pre-suspend */
    145 	NULL,			/* pre-resume */
    146 };
    147 
    148 /* debug support */
    149 uint_t	 usbser_errlevel = USB_LOG_L4;
    150 uint_t	 usbser_errmask = DPRINT_MASK_ALL;
    151 uint_t	 usbser_instance_debug = (uint_t)-1;
    152 
    153 /* usb serial console */
    154 static struct usbser_state *usbser_list;
    155 static kmutex_t usbser_lock;
    156 static int usbser_console_abort;
    157 static usb_console_info_t console_input, console_output;
    158 static uchar_t *console_input_buf;
    159 static uchar_t *console_input_start, *console_input_end;
    160 
    161 _NOTE(SCHEME_PROTECTS_DATA("unshared", usbser_console_abort))
    162 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input))
    163 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_output))
    164 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_start))
    165 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_end))
    166 
    167 static void usbser_putchar(cons_polledio_arg_t, uchar_t);
    168 static int usbser_getchar(cons_polledio_arg_t);
    169 static boolean_t usbser_ischar(cons_polledio_arg_t);
    170 static void usbser_polledio_enter(cons_polledio_arg_t);
    171 static void usbser_polledio_exit(cons_polledio_arg_t);
    172 static int usbser_polledio_init(usbser_port_t *);
    173 static void usbser_polledio_fini(usbser_port_t *);
    174 
    175 static struct cons_polledio usbser_polledio = {
    176 	CONSPOLLEDIO_V1,
    177 	NULL,	/* to be set later */
    178 	usbser_putchar,
    179 	usbser_getchar,
    180 	usbser_ischar,
    181 	usbser_polledio_enter,
    182 	usbser_polledio_exit
    183 };
    184 
    185 /* various statistics. TODO: replace with kstats */
    186 static int usbser_st_tx_data_loss = 0;
    187 static int usbser_st_rx_data_loss = 0;
    188 static int usbser_st_put_stopi = 0;
    189 static int usbser_st_mstop = 0;
    190 static int usbser_st_mstart = 0;
    191 static int usbser_st_mstopi = 0;
    192 static int usbser_st_mstarti = 0;
    193 static int usbser_st_rsrv = 0;
    194 _NOTE(SCHEME_PROTECTS_DATA("monotonic stats", usbser_st_{
    195 	tx_data_loss rx_data_loss put_stopi mstop mstart mstopi mstarti rsrv}))
    196 _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_bulk_req_t))
    197 _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_intr_req_t))
    198 
    199 /* taskq parameter */
    200 extern pri_t minclsyspri;
    201 
    202 /*
    203  * tell warlock not to worry about STREAMS structures
    204  */
    205 _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk datab msgb queue copyreq))
    206 
    207 /*
    208  * modload support
    209  */
    210 extern struct mod_ops mod_miscops;
    211 
    212 static struct modlmisc modlmisc = {
    213 	&mod_miscops,	/* Type of module */
    214 	"USB generic serial module"
    215 };
    216 
    217 static struct modlinkage modlinkage = {
    218 	MODREV_1, (void *)&modlmisc, NULL
    219 };
    220 
    221 
    222 #define	RSEQ(f1, f2) RSEQE(f1, usbser_rseq_do_cb, f2, NULL)
    223 
    224 
    225 /*
    226  * loadable module entry points
    227  * ----------------------------
    228  */
    229 
    230 int
    231 _init(void)
    232 {
    233 	int err;
    234 
    235 	mutex_init(&usbser_lock, NULL, MUTEX_DRIVER, (void *)NULL);
    236 	if (err = mod_install(&modlinkage))
    237 		mutex_destroy(&usbser_lock);
    238 
    239 	return (err);
    240 }
    241 
    242 
    243 int
    244 _fini(void)
    245 {
    246 	int err;
    247 
    248 	if (err = mod_remove(&modlinkage))
    249 
    250 		return (err);
    251 
    252 	mutex_destroy(&usbser_lock);
    253 
    254 	return (0);
    255 }
    256 
    257 
    258 int
    259 _info(struct modinfo *modinfop)
    260 {
    261 	return (mod_info(&modlinkage, modinfop));
    262 }
    263 
    264 
    265 /*
    266  * soft state size
    267  */
    268 int
    269 usbser_soft_state_size()
    270 {
    271 	return (sizeof (usbser_state_t));
    272 }
    273 
    274 
    275 /*
    276  * autoconfiguration entry points
    277  * ------------------------------
    278  */
    279 
    280 /*ARGSUSED*/
    281 int
    282 usbser_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
    283 		void **result, void *statep)
    284 {
    285 	int		instance;
    286 	int		ret = DDI_FAILURE;
    287 	usbser_state_t	*usbserp;
    288 
    289 	instance = USBSER_MINOR2INST(getminor((dev_t)arg));
    290 
    291 	switch (infocmd) {
    292 	case DDI_INFO_DEVT2DEVINFO:
    293 		*result = NULL;
    294 		usbserp = ddi_get_soft_state(statep, instance);
    295 		if (usbserp != NULL) {
    296 			*result = usbserp->us_dip;
    297 			if (*result != NULL) {
    298 				ret = DDI_SUCCESS;
    299 			}
    300 		}
    301 
    302 		break;
    303 	case DDI_INFO_DEVT2INSTANCE:
    304 		*result = (void *)(uintptr_t)instance;
    305 		ret = DDI_SUCCESS;
    306 
    307 		break;
    308 	default:
    309 		break;
    310 	}
    311 
    312 	return (ret);
    313 }
    314 
    315 /*
    316  * device attach
    317  */
    318 static rseq_t rseq_att[] = {
    319 	RSEQ(NULL,			usbser_free_soft_state),
    320 	RSEQ(usbser_init_soft_state,	usbser_fini_soft_state),
    321 	RSEQ(usbser_attach_dev,		usbser_detach_dev),
    322 	RSEQ(usbser_attach_ports,	usbser_detach_ports),
    323 	RSEQ(usbser_create_taskq,	usbser_destroy_taskq),
    324 	RSEQ(NULL,			usbser_set_dev_state_init)
    325 };
    326 
    327 static void
    328 usbser_insert(struct usbser_state *usp)
    329 {
    330 	struct usbser_state *tmp;
    331 
    332 	mutex_enter(&usbser_lock);
    333 	tmp = usbser_list;
    334 	if (tmp == NULL)
    335 		usbser_list = usp;
    336 	else {
    337 		while (tmp->us_next)
    338 			tmp = tmp->us_next;
    339 		tmp->us_next = usp;
    340 	}
    341 	mutex_exit(&usbser_lock);
    342 }
    343 
    344 static void
    345 usbser_remove(struct usbser_state *usp)
    346 {
    347 	struct usbser_state *tmp, *prev = NULL;
    348 
    349 	mutex_enter(&usbser_lock);
    350 	tmp = usbser_list;
    351 	while (tmp != usp) {
    352 		prev = tmp;
    353 		tmp = tmp->us_next;
    354 	}
    355 	ASSERT(tmp == usp);	/* must exist, else attach/detach wrong */
    356 	if (prev)
    357 		prev->us_next = usp->us_next;
    358 	else
    359 		usbser_list = usp->us_next;
    360 	usp->us_next = NULL;
    361 	mutex_exit(&usbser_lock);
    362 }
    363 
    364 /*
    365  * Return the first serial device, with dip held. This is called
    366  * from the console subsystem to place console on usb serial device.
    367  */
    368 dev_info_t *
    369 usbser_first_device(void)
    370 {
    371 	dev_info_t *dip = NULL;
    372 
    373 	mutex_enter(&usbser_lock);
    374 	if (usbser_list) {
    375 		dip = usbser_list->us_dip;
    376 		ndi_hold_devi(dip);
    377 	}
    378 	mutex_exit(&usbser_lock);
    379 
    380 	return (dip);
    381 }
    382 
    383 int
    384 usbser_attach(dev_info_t *dip, ddi_attach_cmd_t cmd,
    385 		void *statep, ds_ops_t *ds_ops)
    386 {
    387 	int		instance;
    388 	usbser_state_t	*usp;
    389 
    390 	instance = ddi_get_instance(dip);
    391 
    392 	switch (cmd) {
    393 	case DDI_ATTACH:
    394 
    395 		break;
    396 	case DDI_RESUME:
    397 		usbser_cpr_resume(dip);
    398 
    399 		return (DDI_SUCCESS);
    400 	default:
    401 
    402 		return (DDI_FAILURE);
    403 	}
    404 
    405 	/* allocate and get soft state */
    406 	if (ddi_soft_state_zalloc(statep, instance) != DDI_SUCCESS) {
    407 
    408 		return (DDI_FAILURE);
    409 	}
    410 	if ((usp = ddi_get_soft_state(statep, instance)) == NULL) {
    411 		ddi_soft_state_free(statep, instance);
    412 
    413 		return (DDI_FAILURE);
    414 	}
    415 
    416 	usp->us_statep = statep;
    417 	usp->us_dip = dip;
    418 	usp->us_instance = instance;
    419 	usp->us_ds_ops = ds_ops;
    420 
    421 	if (rseq_do(rseq_att, NELEM(rseq_att), (uintptr_t)usp, 0) == RSEQ_OK) {
    422 		ddi_report_dev(dip);
    423 		usbser_insert(usp);
    424 
    425 		return (DDI_SUCCESS);
    426 	} else {
    427 
    428 		return (DDI_FAILURE);
    429 	}
    430 }
    431 
    432 /*
    433  * device detach
    434  */
    435 int
    436 usbser_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, void *statep)
    437 {
    438 	int		instance = ddi_get_instance(dip);
    439 	usbser_state_t	*usp;
    440 	int		rval;
    441 
    442 	usp = ddi_get_soft_state(statep, instance);
    443 
    444 	switch (cmd) {
    445 	case DDI_DETACH:
    446 		USB_DPRINTF_L4(DPRINT_DETACH, usp->us_lh, "usbser_detach");
    447 		usbser_remove(usp);
    448 		(void) rseq_undo(rseq_att, NELEM(rseq_att), (uintptr_t)usp, 0);
    449 		USB_DPRINTF_L4(DPRINT_DETACH, NULL,
    450 		    "usbser_detach.%d: end", instance);
    451 
    452 		return (DDI_SUCCESS);
    453 	case DDI_SUSPEND:
    454 		rval = usbser_cpr_suspend(dip);
    455 
    456 		return ((rval == USB_SUCCESS)? DDI_SUCCESS : DDI_FAILURE);
    457 	default:
    458 
    459 		return (DDI_FAILURE);
    460 	}
    461 }
    462 
    463 /*
    464  * STREAMS entry points
    465  * --------------------
    466  *
    467  *
    468  * port open
    469  */
    470 /*ARGSUSED*/
    471 int
    472 usbser_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr,
    473 		void *statep)
    474 {
    475 	usbser_state_t	*usp;
    476 	usbser_port_t	*pp;
    477 	int		minor = getminor(*dev);
    478 	int		instance;
    479 	uint_t		port_num;
    480 	int		rval;
    481 
    482 	instance = USBSER_MINOR2INST(minor);
    483 	if (instance < 0) {
    484 
    485 		return (ENXIO);
    486 	}
    487 
    488 	usp = ddi_get_soft_state(statep, instance);
    489 	if (usp == NULL) {
    490 
    491 		return (ENXIO);
    492 	}
    493 
    494 	/* don't allow to open disconnected device */
    495 	mutex_enter(&usp->us_mutex);
    496 	if (usp->us_dev_state == USB_DEV_DISCONNECTED) {
    497 		mutex_exit(&usp->us_mutex);
    498 
    499 		return (ENXIO);
    500 	}
    501 	mutex_exit(&usp->us_mutex);
    502 
    503 	/* get port soft state */
    504 	port_num = USBSER_MINOR2PORT(minor);
    505 	if (port_num >= usp->us_port_cnt) {
    506 
    507 		return (ENXIO);
    508 	}
    509 	pp = &usp->us_ports[port_num];
    510 
    511 	/* set up everything for open */
    512 	rval = usbser_open_setup(rq, pp, minor, flag, cr);
    513 
    514 	USB_DPRINTF_L4(DPRINT_OPEN, pp->port_lh, "usbser_open: rval=%d", rval);
    515 
    516 	return (rval);
    517 }
    518 
    519 
    520 /*
    521  * port close
    522  *
    523  * some things driver should do when the last app closes the line:
    524  *
    525  *	drain data;
    526  *	cancel break/delay;
    527  *	hangup line (if necessary);
    528  *	DSD close;
    529  *	cleanup soft state;
    530  */
    531 /*ARGSUSED*/
    532 int
    533 usbser_close(queue_t *rq, int flag, cred_t *cr)
    534 {
    535 	usbser_port_t	*pp = (usbser_port_t *)rq->q_ptr;
    536 	int		online;
    537 
    538 	if (pp == NULL) {
    539 
    540 		return (ENXIO);
    541 	}
    542 
    543 	online = usbser_dev_is_online(pp->port_usp);
    544 
    545 	/*
    546 	 * in the closing state new activities will not be initiated
    547 	 */
    548 	mutex_enter(&pp->port_mutex);
    549 	pp->port_state = USBSER_PORT_CLOSING;
    550 
    551 	if (online) {
    552 		/* drain the data */
    553 		usbser_close_drain(pp);
    554 	}
    555 
    556 	/* stop break/delay */
    557 	usbser_close_cancel_break(pp);
    558 
    559 	if (online) {
    560 		/* hangup line */
    561 		usbser_close_hangup(pp);
    562 	}
    563 
    564 	/*
    565 	 * close DSD, cleanup state and transition to 'closed' state
    566 	 */
    567 	usbser_close_cleanup(pp);
    568 	mutex_exit(&pp->port_mutex);
    569 
    570 	USB_DPRINTF_L4(DPRINT_CLOSE, pp->port_lh, "usbser_close: end");
    571 
    572 	return (0);
    573 }
    574 
    575 
    576 /*
    577  * read side service routine: send as much as possible messages upstream
    578  * and if there is still place on the queue, enable receive (if not already)
    579  */
    580 int
    581 usbser_rsrv(queue_t *q)
    582 {
    583 	usbser_port_t	*pp = (usbser_port_t *)q->q_ptr;
    584 	mblk_t		*mp;
    585 
    586 	usbser_st_rsrv++;
    587 	USB_DPRINTF_L4(DPRINT_RQ, pp->port_lh, "usbser_rsrv");
    588 
    589 	while (canputnext(q) && (mp = getq(q))) {
    590 		putnext(q, mp);
    591 	}
    592 
    593 	if (canputnext(q)) {
    594 		mutex_enter(&pp->port_mutex);
    595 		ASSERT(pp->port_state != USBSER_PORT_CLOSED);
    596 
    597 		if (USBSER_PORT_ACCESS_OK(pp)) {
    598 			usbser_thr_wake(&pp->port_rq_thread);
    599 		}
    600 		mutex_exit(&pp->port_mutex);
    601 	}
    602 
    603 	return (0);
    604 }
    605 
    606 
    607 /*
    608  * wput: put message on the queue and wake wq thread
    609  */
    610 int
    611 usbser_wput(queue_t *q, mblk_t *mp)
    612 {
    613 	usbser_port_t	*pp = (usbser_port_t *)q->q_ptr;
    614 
    615 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wput");
    616 
    617 	mutex_enter(&pp->port_mutex);
    618 	ASSERT(pp->port_state != USBSER_PORT_CLOSED);
    619 
    620 	/* ignore new messages if port is already closing */
    621 	if (pp->port_state == USBSER_PORT_CLOSING) {
    622 		freemsg(mp);
    623 	} else if (putq(q, mp)) {
    624 		/*
    625 		 * this counter represents amount of tx data on the wq.
    626 		 * each time the data is passed to DSD for transmission,
    627 		 * the counter is decremented accordingly
    628 		 */
    629 		pp->port_wq_data_cnt += msgdsize(mp);
    630 	} else {
    631 		usbser_st_tx_data_loss++;
    632 	}
    633 	mutex_exit(&pp->port_mutex);
    634 
    635 	return (0);
    636 }
    637 
    638 
    639 /*
    640  * we need wsrv() routine to take advantage of STREAMS flow control:
    641  * without it the framework will consider we are always able to process msgs
    642  */
    643 int
    644 usbser_wsrv(queue_t *q)
    645 {
    646 	usbser_port_t	*pp = (usbser_port_t *)q->q_ptr;
    647 
    648 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wsrv");
    649 
    650 	mutex_enter(&pp->port_mutex);
    651 	ASSERT(pp->port_state != USBSER_PORT_CLOSED);
    652 
    653 	if (USBSER_PORT_ACCESS_OK(pp)) {
    654 		usbser_thr_wake(&pp->port_wq_thread);
    655 	}
    656 	mutex_exit(&pp->port_mutex);
    657 
    658 	return (0);
    659 }
    660 
    661 
    662 /*
    663  * power entry point
    664  */
    665 int
    666 usbser_power(dev_info_t *dip, int comp, int level)
    667 {
    668 	void		*statep;
    669 	usbser_state_t	*usp;
    670 	int		new_state;
    671 	int		rval;
    672 
    673 	statep = ddi_get_driver_private(dip);
    674 	usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
    675 
    676 	USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
    677 	    "usbser_power: dip=0x%p, comp=%d, level=%d",
    678 	    (void *)dip, comp, level);
    679 
    680 	mutex_enter(&usp->us_mutex);
    681 	new_state = usp->us_dev_state;
    682 	mutex_exit(&usp->us_mutex);
    683 
    684 	/* let DSD do the job */
    685 	rval = USBSER_DS_USB_POWER(usp, comp, level, &new_state);
    686 
    687 	/* stay in sync with DSD */
    688 	mutex_enter(&usp->us_mutex);
    689 	usp->us_dev_state = new_state;
    690 	mutex_exit(&usp->us_mutex);
    691 
    692 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
    693 }
    694 
    695 
    696 /*
    697  *
    698  * configuration entry point subroutines
    699  * -------------------------------------
    700  *
    701  * rseq callback
    702  */
    703 static int
    704 usbser_rseq_do_cb(rseq_t *rseq, int num, uintptr_t arg)
    705 {
    706 	usbser_state_t *usp = (usbser_state_t *)arg;
    707 	int	rval = rseq[num].r_do.s_rval;
    708 	char	*name = rseq[num].r_do.s_name;
    709 
    710 	if (rval != DDI_SUCCESS) {
    711 		USB_DPRINTF_L2(DPRINT_ATTACH, usp->us_lh,
    712 		    "do %s failed (%d)", name, rval);
    713 
    714 		return (RSEQ_UNDO);
    715 	} else {
    716 
    717 		return (RSEQ_OK);
    718 	}
    719 }
    720 
    721 
    722 /*
    723  * free soft state
    724  */
    725 static int
    726 usbser_free_soft_state(usbser_state_t *usp)
    727 {
    728 	ddi_soft_state_free(usp->us_statep, usp->us_instance);
    729 
    730 	return (USB_SUCCESS);
    731 }
    732 
    733 /*
    734  * init instance soft state
    735  */
    736 static int
    737 usbser_init_soft_state(usbser_state_t *usp)
    738 {
    739 	usp->us_lh = usb_alloc_log_hdl(usp->us_dip, "usbs[*].",
    740 	    &usbser_errlevel, &usbser_errmask, &usbser_instance_debug,
    741 	    0);
    742 	mutex_init(&usp->us_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
    743 
    744 	/* save state pointer for use in event callbacks */
    745 	ddi_set_driver_private(usp->us_dip, usp->us_statep);
    746 
    747 	usp->us_dev_state = USBSER_DEV_INIT;
    748 
    749 	return (DDI_SUCCESS);
    750 }
    751 
    752 /*
    753  * fini instance soft state
    754  */
    755 static int
    756 usbser_fini_soft_state(usbser_state_t *usp)
    757 {
    758 	usb_free_log_hdl(usp->us_lh);
    759 	mutex_destroy(&usp->us_mutex);
    760 	ddi_set_driver_private(usp->us_dip, NULL);
    761 
    762 	return (DDI_SUCCESS);
    763 }
    764 
    765 /*
    766  * attach entire device
    767  */
    768 static int
    769 usbser_attach_dev(usbser_state_t *usp)
    770 {
    771 	ds_attach_info_t ai;
    772 	int		rval;
    773 
    774 	usp->us_dev_state = USB_DEV_ONLINE;
    775 
    776 	ai.ai_dip = usp->us_dip;
    777 	ai.ai_usb_events = &usbser_usb_events;
    778 	ai.ai_hdl = &usp->us_ds_hdl;
    779 	ai.ai_port_cnt = &usp->us_port_cnt;
    780 
    781 	rval = USBSER_DS_ATTACH(usp, &ai);
    782 
    783 	if ((rval != USB_SUCCESS) || (usp->us_ds_hdl == NULL) ||
    784 	    (usp->us_port_cnt == 0)) {
    785 		USB_DPRINTF_L4(DPRINT_ATTACH, usp->us_lh, "usbser_attach_dev: "
    786 		    "failed %d %p %d", rval, usp->us_ds_hdl, usp->us_port_cnt);
    787 
    788 		return (DDI_FAILURE);
    789 	}
    790 
    791 	USB_DPRINTF_L4(DPRINT_ATTACH, usp->us_lh,
    792 	    "usbser_attach_dev: port_cnt = %d", usp->us_port_cnt);
    793 
    794 	return (DDI_SUCCESS);
    795 }
    796 
    797 
    798 /*
    799  * detach entire device
    800  */
    801 static void
    802 usbser_detach_dev(usbser_state_t *usp)
    803 {
    804 	USBSER_DS_DETACH(usp);
    805 }
    806 
    807 
    808 /*
    809  * attach each individual port
    810  */
    811 static int
    812 usbser_attach_ports(usbser_state_t *usp)
    813 {
    814 	int		i;
    815 	usbser_port_t	*pp;
    816 	ds_cb_t		ds_cb;
    817 
    818 	/*
    819 	 * allocate port array
    820 	 */
    821 	usp->us_ports = kmem_zalloc(usp->us_port_cnt *
    822 	    sizeof (usbser_port_t), KM_SLEEP);
    823 
    824 	/* callback handlers */
    825 	ds_cb.cb_tx = usbser_tx_cb;
    826 	ds_cb.cb_rx = usbser_rx_cb;
    827 	ds_cb.cb_status = usbser_status_cb;
    828 
    829 	/*
    830 	 * initialize each port
    831 	 */
    832 	for (i = 0; i < usp->us_port_cnt; i++) {
    833 		pp = &usp->us_ports[i];
    834 
    835 		/*
    836 		 * initialize data
    837 		 */
    838 		pp->port_num = i;
    839 		pp->port_usp = usp;
    840 		pp->port_ds_ops = usp->us_ds_ops;
    841 		pp->port_ds_hdl = usp->us_ds_hdl;
    842 
    843 		/* allocate log handle */
    844 		(void) sprintf(pp->port_lh_name, "usbs[%d].", i);
    845 		pp->port_lh = usb_alloc_log_hdl(usp->us_dip,
    846 		    pp->port_lh_name, &usbser_errlevel, &usbser_errmask,
    847 		    &usbser_instance_debug, 0);
    848 
    849 		mutex_init(&pp->port_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
    850 		cv_init(&pp->port_state_cv, NULL, CV_DEFAULT, NULL);
    851 		cv_init(&pp->port_act_cv, NULL, CV_DEFAULT, NULL);
    852 		cv_init(&pp->port_car_cv, NULL, CV_DEFAULT, NULL);
    853 
    854 		/*
    855 		 * init threads
    856 		 */
    857 		pp->port_wq_thread.thr_port = pp;
    858 		pp->port_wq_thread.thr_func = usbser_wq_thread;
    859 		pp->port_wq_thread.thr_arg = (void *)&pp->port_wq_thread;
    860 		cv_init(&pp->port_wq_thread.thr_cv, NULL, CV_DEFAULT, NULL);
    861 
    862 		pp->port_rq_thread.thr_port = pp;
    863 		pp->port_rq_thread.thr_func = usbser_rq_thread;
    864 		pp->port_rq_thread.thr_arg = (void *)&pp->port_rq_thread;
    865 		cv_init(&pp->port_rq_thread.thr_cv, NULL, CV_DEFAULT, NULL);
    866 
    867 		/*
    868 		 * register callbacks
    869 		 */
    870 		ds_cb.cb_arg = (caddr_t)pp;
    871 		USBSER_DS_REGISTER_CB(usp, i, &ds_cb);
    872 
    873 		pp->port_state = USBSER_PORT_CLOSED;
    874 
    875 		if (usbser_create_port_minor_nodes(usp, i) != USB_SUCCESS) {
    876 			usbser_detach_ports(usp);
    877 
    878 			return (DDI_FAILURE);
    879 		}
    880 	}
    881 
    882 	return (DDI_SUCCESS);
    883 }
    884 
    885 
    886 /*
    887  * create a pair of minor nodes for the port
    888  */
    889 static int
    890 usbser_create_port_minor_nodes(usbser_state_t *usp, int port_num)
    891 {
    892 	int	instance = usp->us_instance;
    893 	minor_t	minor;
    894 	char	name[16];
    895 
    896 	/*
    897 	 * tty node
    898 	 */
    899 	(void) sprintf(name, "%d", port_num);
    900 	minor = USBSER_MAKEMINOR(instance, port_num, 0);
    901 
    902 	if (ddi_create_minor_node(usp->us_dip, name,
    903 	    S_IFCHR, minor, DDI_NT_SERIAL, NULL) != DDI_SUCCESS) {
    904 
    905 		return (USB_FAILURE);
    906 	}
    907 
    908 	/*
    909 	 * dial-out node
    910 	 */
    911 	(void) sprintf(name, "%d,cu", port_num);
    912 	minor = USBSER_MAKEMINOR(instance, port_num, OUTLINE);
    913 
    914 	if (ddi_create_minor_node(usp->us_dip, name,
    915 	    S_IFCHR, minor, DDI_NT_SERIAL_DO, NULL) != DDI_SUCCESS) {
    916 
    917 		return (USB_FAILURE);
    918 	}
    919 
    920 	return (USB_SUCCESS);
    921 }
    922 
    923 
    924 /*
    925  * detach each port individually
    926  */
    927 static void
    928 usbser_detach_ports(usbser_state_t *usp)
    929 {
    930 	int		i;
    931 	int		sz;
    932 	usbser_port_t	*pp;
    933 
    934 	/*
    935 	 * remove all minor nodes
    936 	 */
    937 	ddi_remove_minor_node(usp->us_dip, NULL);
    938 
    939 	for (i = 0; i < usp->us_port_cnt; i++) {
    940 		pp = &usp->us_ports[i];
    941 
    942 		if (pp->port_state != USBSER_PORT_CLOSED) {
    943 			ASSERT(pp->port_state == USBSER_PORT_NOT_INIT);
    944 
    945 			continue;
    946 		}
    947 
    948 		USBSER_DS_UNREGISTER_CB(usp, i);
    949 
    950 		mutex_destroy(&pp->port_mutex);
    951 		cv_destroy(&pp->port_state_cv);
    952 		cv_destroy(&pp->port_act_cv);
    953 		cv_destroy(&pp->port_car_cv);
    954 
    955 		cv_destroy(&pp->port_wq_thread.thr_cv);
    956 		cv_destroy(&pp->port_rq_thread.thr_cv);
    957 
    958 		usb_free_log_hdl(pp->port_lh);
    959 	}
    960 
    961 	/*
    962 	 * free memory
    963 	 */
    964 	sz = usp->us_port_cnt * sizeof (usbser_port_t);
    965 	kmem_free(usp->us_ports, sz);
    966 	usp->us_ports = NULL;
    967 }
    968 
    969 
    970 /*
    971  * create a taskq with two threads per port (read and write sides)
    972  */
    973 static int
    974 usbser_create_taskq(usbser_state_t *usp)
    975 {
    976 	int	nthr = usp->us_port_cnt * 2;
    977 
    978 	usp->us_taskq = ddi_taskq_create(usp->us_dip, "usbser_taskq",
    979 	    nthr, TASKQ_DEFAULTPRI, 0);
    980 
    981 	return ((usp->us_taskq == NULL) ? DDI_FAILURE : DDI_SUCCESS);
    982 }
    983 
    984 
    985 static void
    986 usbser_destroy_taskq(usbser_state_t *usp)
    987 {
    988 	ddi_taskq_destroy(usp->us_taskq);
    989 }
    990 
    991 
    992 static void
    993 usbser_set_dev_state_init(usbser_state_t *usp)
    994 {
    995 	mutex_enter(&usp->us_mutex);
    996 	usp->us_dev_state = USBSER_DEV_INIT;
    997 	mutex_exit(&usp->us_mutex);
    998 }
    999 
   1000 /*
   1001  * hotplugging and power management
   1002  * ---------------------------------
   1003  *
   1004  * disconnect event callback
   1005  */
   1006 /*ARGSUSED*/
   1007 static int
   1008 usbser_disconnect_cb(dev_info_t *dip)
   1009 {
   1010 	void		*statep;
   1011 	usbser_state_t	*usp;
   1012 
   1013 	statep = ddi_get_driver_private(dip);
   1014 	usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
   1015 
   1016 	USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
   1017 	    "usbser_disconnect_cb: dip=%p", (void *)dip);
   1018 
   1019 	mutex_enter(&usp->us_mutex);
   1020 	switch (usp->us_dev_state) {
   1021 	case USB_DEV_ONLINE:
   1022 	case USB_DEV_PWRED_DOWN:
   1023 		/* prevent further activity */
   1024 		usp->us_dev_state = USB_DEV_DISCONNECTED;
   1025 		mutex_exit(&usp->us_mutex);
   1026 
   1027 		/* see if any of the ports are open and do necessary handling */
   1028 		usbser_disconnect_ports(usp);
   1029 
   1030 		/* call DSD to do any necessary work */
   1031 		if (USBSER_DS_DISCONNECT(usp) != USB_DEV_DISCONNECTED) {
   1032 			USB_DPRINTF_L2(DPRINT_EVENTS, usp->us_lh,
   1033 			    "usbser_disconnect_cb: ds_disconnect failed");
   1034 		}
   1035 
   1036 		break;
   1037 	case USB_DEV_SUSPENDED:
   1038 		/* we remain suspended */
   1039 	default:
   1040 		mutex_exit(&usp->us_mutex);
   1041 
   1042 		break;
   1043 	}
   1044 
   1045 	return (USB_SUCCESS);
   1046 }
   1047 
   1048 
   1049 /*
   1050  * reconnect event callback
   1051  */
   1052 /*ARGSUSED*/
   1053 static int
   1054 usbser_reconnect_cb(dev_info_t *dip)
   1055 {
   1056 	void		*statep;
   1057 	usbser_state_t	*usp;
   1058 
   1059 	statep = ddi_get_driver_private(dip);
   1060 	usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
   1061 
   1062 	USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
   1063 	    "usbser_reconnect_cb: dip=%p", (void *)dip);
   1064 
   1065 	(void) usbser_restore_device_state(usp);
   1066 
   1067 	return (USB_SUCCESS);
   1068 }
   1069 
   1070 
   1071 /*
   1072  * if any of the ports is open during disconnect,
   1073  * send M_HANGUP message upstream and log a warning
   1074  */
   1075 static void
   1076 usbser_disconnect_ports(usbser_state_t *usp)
   1077 {
   1078 	usbser_port_t	*pp;
   1079 	queue_t		*rq;
   1080 	int		complain = 0;
   1081 	int		hangup = 0;
   1082 	timeout_id_t	delay_id = 0;
   1083 	int		i;
   1084 
   1085 	if (usp->us_ports == NULL) {
   1086 		return;
   1087 	}
   1088 
   1089 	for (i = 0; i < usp->us_port_cnt; i++) {
   1090 		pp = &usp->us_ports[i];
   1091 
   1092 		mutex_enter(&pp->port_mutex);
   1093 		if (pp->port_state == USBSER_PORT_OPEN ||
   1094 		    USBSER_IS_OPENING(pp) ||
   1095 		    pp->port_state == USBSER_PORT_CLOSING) {
   1096 			complain = 1;
   1097 		}
   1098 
   1099 		if (pp->port_state == USBSER_PORT_OPEN) {
   1100 			rq = pp->port_ttycommon.t_readq;
   1101 
   1102 			/*
   1103 			 * hangup the stream; will send actual
   1104 			 * M_HANGUP message after releasing mutex
   1105 			 */
   1106 			pp->port_flags |= USBSER_FL_HUNGUP;
   1107 			hangup = 1;
   1108 
   1109 			/*
   1110 			 * cancel all activities
   1111 			 */
   1112 			usbser_release_port_act(pp, USBSER_ACT_ALL);
   1113 
   1114 			delay_id = pp->port_delay_id;
   1115 			pp->port_delay_id = 0;
   1116 
   1117 			/* mark disconnected */
   1118 			pp->port_state = USBSER_PORT_DISCONNECTED;
   1119 			cv_broadcast(&pp->port_state_cv);
   1120 		}
   1121 		mutex_exit(&pp->port_mutex);
   1122 
   1123 		if (hangup) {
   1124 			(void) putnextctl(rq, M_HANGUP);
   1125 			hangup = 0;
   1126 		}
   1127 
   1128 		/*
   1129 		 * we couldn't untimeout while holding the mutex - do it now
   1130 		 */
   1131 		if (delay_id) {
   1132 			(void) untimeout(delay_id);
   1133 			delay_id = 0;
   1134 		}
   1135 	}
   1136 
   1137 	/*
   1138 	 * complain about disconnecting device while open
   1139 	 */
   1140 	if (complain) {
   1141 		USB_DPRINTF_L0(DPRINT_EVENTS, usp->us_lh, "device was "
   1142 		    "disconnected while open. Data may have been lost");
   1143 	}
   1144 }
   1145 
   1146 
   1147 /*
   1148  * do CPR suspend
   1149  *
   1150  * We use a trivial CPR strategy - fail if any of the device's ports are open.
   1151  * The problem with more sophisticated strategies is that each open port uses
   1152  * two threads that sit in the loop until the port is closed, while CPR has to
   1153  * stop all kernel threads to succeed. Stopping port threads is a rather
   1154  * intrusive and delicate procedure; I leave it as an RFE for now.
   1155  *
   1156  */
   1157 static int
   1158 usbser_cpr_suspend(dev_info_t *dip)
   1159 {
   1160 	void		*statep;
   1161 	usbser_state_t	*usp;
   1162 	int		new_state;
   1163 	int		rval;
   1164 
   1165 	statep = ddi_get_driver_private(dip);
   1166 	usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
   1167 
   1168 	USB_DPRINTF_L4(DPRINT_EVENTS, usp->us_lh, "usbser_cpr_suspend");
   1169 
   1170 	/* suspend each port first */
   1171 	if (usbser_suspend_ports(usp) != USB_SUCCESS) {
   1172 		USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
   1173 		    "usbser_cpr_suspend: GSD failure");
   1174 
   1175 		return (USB_FAILURE);
   1176 	}
   1177 
   1178 	new_state = USBSER_DS_SUSPEND(usp);	/* let DSD do its part */
   1179 
   1180 	mutex_enter(&usp->us_mutex);
   1181 	if (new_state == USB_DEV_SUSPENDED) {
   1182 		rval = USB_SUCCESS;
   1183 	} else {
   1184 		ASSERT(new_state == USB_DEV_ONLINE);
   1185 		rval = USB_FAILURE;
   1186 	}
   1187 	usp->us_dev_state = new_state;
   1188 	mutex_exit(&usp->us_mutex);
   1189 
   1190 	return (rval);
   1191 }
   1192 
   1193 
   1194 static int
   1195 usbser_suspend_ports(usbser_state_t *usp)
   1196 {
   1197 	usbser_port_t	*pp;
   1198 	int		i;
   1199 
   1200 	for (i = 0; i < usp->us_port_cnt; i++) {
   1201 		pp = &usp->us_ports[i];
   1202 
   1203 		mutex_enter(&pp->port_mutex);
   1204 		if (pp->port_state != USBSER_PORT_CLOSED) {
   1205 			mutex_exit(&pp->port_mutex);
   1206 
   1207 			return (USB_FAILURE);
   1208 		}
   1209 		mutex_exit(&pp->port_mutex);
   1210 	}
   1211 
   1212 	return (USB_SUCCESS);
   1213 }
   1214 
   1215 
   1216 /*
   1217  * do CPR resume
   1218  *
   1219  * DSD will return USB_DEV_ONLINE in case of success
   1220  */
   1221 static void
   1222 usbser_cpr_resume(dev_info_t *dip)
   1223 {
   1224 	void		*statep;
   1225 	usbser_state_t	*usp;
   1226 
   1227 	statep = ddi_get_driver_private(dip);
   1228 	usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
   1229 
   1230 	USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh, "usbser_cpr_resume");
   1231 
   1232 	(void) usbser_restore_device_state(usp);
   1233 }
   1234 
   1235 
   1236 /*
   1237  * restore device state after CPR resume or reconnect
   1238  */
   1239 static int
   1240 usbser_restore_device_state(usbser_state_t *usp)
   1241 {
   1242 	int	new_state, current_state;
   1243 
   1244 	/* needed as power up state of dev is "unknown" to system */
   1245 	(void) pm_busy_component(usp->us_dip, 0);
   1246 	(void) pm_raise_power(usp->us_dip, 0, USB_DEV_OS_FULL_PWR);
   1247 
   1248 	mutex_enter(&usp->us_mutex);
   1249 	current_state = usp->us_dev_state;
   1250 	mutex_exit(&usp->us_mutex);
   1251 
   1252 	ASSERT((current_state == USB_DEV_DISCONNECTED) ||
   1253 	    (current_state == USB_DEV_SUSPENDED));
   1254 
   1255 	/*
   1256 	 * call DSD to perform device-specific work
   1257 	 */
   1258 	if (current_state == USB_DEV_DISCONNECTED) {
   1259 		new_state = USBSER_DS_RECONNECT(usp);
   1260 	} else {
   1261 		new_state = USBSER_DS_RESUME(usp);
   1262 	}
   1263 
   1264 	mutex_enter(&usp->us_mutex);
   1265 	usp->us_dev_state = new_state;
   1266 	mutex_exit(&usp->us_mutex);
   1267 
   1268 	if (new_state == USB_DEV_ONLINE) {
   1269 		/*
   1270 		 * restore ports state
   1271 		 */
   1272 		usbser_restore_ports_state(usp);
   1273 	}
   1274 
   1275 	(void) pm_idle_component(usp->us_dip, 0);
   1276 
   1277 	return (USB_SUCCESS);
   1278 }
   1279 
   1280 
   1281 /*
   1282  * restore ports state after device reconnect/resume
   1283  */
   1284 static void
   1285 usbser_restore_ports_state(usbser_state_t *usp)
   1286 {
   1287 	usbser_port_t	*pp;
   1288 	queue_t		*rq;
   1289 	int		i;
   1290 
   1291 	for (i = 0; i < usp->us_port_cnt; i++) {
   1292 		pp = &usp->us_ports[i];
   1293 
   1294 		mutex_enter(&pp->port_mutex);
   1295 		/*
   1296 		 * only care about ports that are open
   1297 		 */
   1298 		if ((pp->port_state != USBSER_PORT_SUSPENDED) &&
   1299 		    (pp->port_state != USBSER_PORT_DISCONNECTED)) {
   1300 			mutex_exit(&pp->port_mutex);
   1301 
   1302 			continue;
   1303 		}
   1304 
   1305 		pp->port_state = USBSER_PORT_OPEN;
   1306 
   1307 		/*
   1308 		 * if the stream was hung up during disconnect, restore it
   1309 		 */
   1310 		if (pp->port_flags & USBSER_FL_HUNGUP) {
   1311 			pp->port_flags &= ~USBSER_FL_HUNGUP;
   1312 			rq = pp->port_ttycommon.t_readq;
   1313 
   1314 			mutex_exit(&pp->port_mutex);
   1315 			(void) putnextctl(rq, M_UNHANGUP);
   1316 			mutex_enter(&pp->port_mutex);
   1317 		}
   1318 
   1319 		/*
   1320 		 * restore serial parameters
   1321 		 */
   1322 		(void) usbser_port_program(pp);
   1323 
   1324 		/*
   1325 		 * wake anything that might be sleeping
   1326 		 */
   1327 		cv_broadcast(&pp->port_state_cv);
   1328 		cv_broadcast(&pp->port_act_cv);
   1329 		usbser_thr_wake(&pp->port_wq_thread);
   1330 		usbser_thr_wake(&pp->port_rq_thread);
   1331 		mutex_exit(&pp->port_mutex);
   1332 	}
   1333 }
   1334 
   1335 
   1336 /*
   1337  * STREAMS subroutines
   1338  * -------------------
   1339  *
   1340  *
   1341  * port open state machine
   1342  *
   1343  * here's a list of things that the driver has to do while open;
   1344  * because device can be opened any number of times,
   1345  * initial open has additional responsibilities:
   1346  *
   1347  *	if (initial_open) {
   1348  *		initialize soft state;	\
   1349  *		DSD open;		- see usbser_open_init()
   1350  *		dispatch threads;	/
   1351  *	}
   1352  *	raise DTR;
   1353  *	wait for carrier (if necessary);
   1354  *
   1355  * we should also take into consideration that two threads can try to open
   1356  * the same physical port simultaneously (/dev/term/N and /dev/cua/N).
   1357  *
   1358  * return values:
   1359  *	0	- success;
   1360  *	>0	- fail with this error code;
   1361  */
   1362 static int
   1363 usbser_open_setup(queue_t *rq, usbser_port_t *pp, int minor, int flag,
   1364 		cred_t *cr)
   1365 {
   1366 	int	rval = USBSER_CONTINUE;
   1367 
   1368 	mutex_enter(&pp->port_mutex);
   1369 	/*
   1370 	 * refer to port state diagram in the header file
   1371 	 */
   1372 loop:
   1373 	switch (pp->port_state) {
   1374 	case USBSER_PORT_CLOSED:
   1375 		/*
   1376 		 * initial open
   1377 		 */
   1378 		rval = usbser_open_init(pp, minor);
   1379 
   1380 		break;
   1381 	case USBSER_PORT_OPENING_TTY:
   1382 		/*
   1383 		 * dial-out thread can overtake the port
   1384 		 * if tty open thread is sleeping waiting for carrier
   1385 		 */
   1386 		if ((minor & OUTLINE) && (pp->port_flags & USBSER_FL_WOPEN)) {
   1387 			pp->port_state = USBSER_PORT_OPENING_OUT;
   1388 
   1389 			USB_DPRINTF_L3(DPRINT_OPEN, pp->port_lh,
   1390 			    "usbser_open_state: overtake");
   1391 		}
   1392 
   1393 		/* FALLTHRU */
   1394 	case USBSER_PORT_OPENING_OUT:
   1395 		/*
   1396 		 * if no other open in progress, setup the line
   1397 		 */
   1398 		if (USBSER_NO_OTHER_OPEN(pp, minor)) {
   1399 			rval = usbser_open_line_setup(pp, minor, flag);
   1400 
   1401 			break;
   1402 		}
   1403 
   1404 		/* FALLTHRU */
   1405 	case USBSER_PORT_CLOSING:
   1406 		/*
   1407 		 * wait until close active phase ends
   1408 		 */
   1409 		if (cv_wait_sig(&pp->port_state_cv, &pp->port_mutex) == 0) {
   1410 			rval = EINTR;
   1411 		}
   1412 
   1413 		break;
   1414 	case USBSER_PORT_OPEN:
   1415 		if ((pp->port_ttycommon.t_flags & TS_XCLUDE) &&
   1416 		    secpolicy_excl_open(cr) != 0) {
   1417 			/*
   1418 			 * exclusive use
   1419 			 */
   1420 			rval = EBUSY;
   1421 		} else if (USBSER_OPEN_IN_OTHER_MODE(pp, minor)) {
   1422 			/*
   1423 			 * tty and dial-out modes are mutually exclusive
   1424 			 */
   1425 			rval = EBUSY;
   1426 		} else {
   1427 			/*
   1428 			 * port is being re-open in the same mode
   1429 			 */
   1430 			rval = usbser_open_line_setup(pp, minor, flag);
   1431 		}
   1432 
   1433 		break;
   1434 	default:
   1435 		rval = ENXIO;
   1436 
   1437 		break;
   1438 	}
   1439 
   1440 	if (rval == USBSER_CONTINUE) {
   1441 
   1442 		goto loop;
   1443 	}
   1444 
   1445 	/*
   1446 	 * initial open requires additional handling
   1447 	 */
   1448 	if (USBSER_IS_OPENING(pp)) {
   1449 		if (rval == USBSER_COMPLETE) {
   1450 			if (pp->port_state == USBSER_PORT_OPENING_OUT) {
   1451 				pp->port_flags |= USBSER_FL_OUT;
   1452 			}
   1453 			pp->port_state = USBSER_PORT_OPEN;
   1454 			cv_broadcast(&pp->port_state_cv);
   1455 
   1456 			usbser_open_queues_init(pp, rq);
   1457 		} else {
   1458 			usbser_open_fini(pp);
   1459 		}
   1460 	}
   1461 	mutex_exit(&pp->port_mutex);
   1462 
   1463 	return (rval);
   1464 }
   1465 
   1466 
   1467 /*
   1468  * initialize the port when opened for the first time
   1469  */
   1470 static int
   1471 usbser_open_init(usbser_port_t *pp, int minor)
   1472 {
   1473 	usbser_state_t	*usp = pp->port_usp;
   1474 	tty_common_t	*tp = &pp->port_ttycommon;
   1475 	int		rval = ENXIO;
   1476 
   1477 	ASSERT(pp->port_state == USBSER_PORT_CLOSED);
   1478 
   1479 	/*
   1480 	 * init state
   1481 	 */
   1482 	pp->port_act = 0;
   1483 	pp->port_flags &= USBSER_FL_PRESERVE;
   1484 	pp->port_flowc = '\0';
   1485 	pp->port_wq_data_cnt = 0;
   1486 
   1487 	if (minor & OUTLINE) {
   1488 		pp->port_state = USBSER_PORT_OPENING_OUT;
   1489 	} else {
   1490 		pp->port_state = USBSER_PORT_OPENING_TTY;
   1491 	}
   1492 
   1493 	/*
   1494 	 * init termios settings
   1495 	 */
   1496 	tp->t_iflag = 0;
   1497 	tp->t_iocpending = NULL;
   1498 	tp->t_size.ws_row = tp->t_size.ws_col = 0;
   1499 	tp->t_size.ws_xpixel = tp->t_size.ws_ypixel = 0;
   1500 	tp->t_startc = CSTART;
   1501 	tp->t_stopc = CSTOP;
   1502 
   1503 	usbser_check_port_props(pp);
   1504 
   1505 	/*
   1506 	 * dispatch wq and rq threads:
   1507 	 * although queues are not enabled at this point,
   1508 	 * we will need wq to run status processing callback
   1509 	 */
   1510 	usbser_thr_dispatch(&pp->port_wq_thread);
   1511 	usbser_thr_dispatch(&pp->port_rq_thread);
   1512 
   1513 	/*
   1514 	 * open DSD port
   1515 	 */
   1516 	mutex_exit(&pp->port_mutex);
   1517 	rval = USBSER_DS_OPEN_PORT(usp, pp->port_num);
   1518 	mutex_enter(&pp->port_mutex);
   1519 
   1520 	if (rval != USB_SUCCESS) {
   1521 
   1522 		return (ENXIO);
   1523 	}
   1524 	pp->port_flags |= USBSER_FL_DSD_OPEN;
   1525 
   1526 	/*
   1527 	 * program port with default parameters
   1528 	 */
   1529 	if ((rval = usbser_port_program(pp)) != 0) {
   1530 
   1531 		return (ENXIO);
   1532 	}
   1533 
   1534 	return (USBSER_CONTINUE);
   1535 }
   1536 
   1537 
   1538 /*
   1539  * create a pair of minor nodes for the port
   1540  */
   1541 static void
   1542 usbser_check_port_props(usbser_port_t *pp)
   1543 {
   1544 	dev_info_t	*dip = pp->port_usp->us_dip;
   1545 	tty_common_t	*tp = &pp->port_ttycommon;
   1546 	struct termios	*termiosp;
   1547 	uint_t		len;
   1548 	char		name[20];
   1549 
   1550 	/*
   1551 	 * take default modes from "ttymodes" property if it exists
   1552 	 */
   1553 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ddi_root_node(), 0,
   1554 	    "ttymodes", (uchar_t **)&termiosp, &len) == DDI_PROP_SUCCESS) {
   1555 
   1556 		if (len == sizeof (struct termios)) {
   1557 			tp->t_cflag = termiosp->c_cflag;
   1558 
   1559 			if (termiosp->c_iflag & (IXON | IXANY)) {
   1560 				tp->t_iflag =
   1561 				    termiosp->c_iflag & (IXON | IXANY);
   1562 				tp->t_startc = termiosp->c_cc[VSTART];
   1563 				tp->t_stopc = termiosp->c_cc[VSTOP];
   1564 			}
   1565 		}
   1566 		ddi_prop_free(termiosp);
   1567 	}
   1568 
   1569 	/*
   1570 	 * look for "ignore-cd" or "port-N-ignore-cd" property
   1571 	 */
   1572 	(void) sprintf(name, "port-%d-ignore-cd", pp->port_num);
   1573 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
   1574 	    "ignore-cd", 0) ||
   1575 	    ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, name, 0)) {
   1576 		pp->port_flags |= USBSER_FL_IGNORE_CD;
   1577 	} else {
   1578 		pp->port_flags &= ~USBSER_FL_IGNORE_CD;
   1579 	}
   1580 }
   1581 
   1582 
   1583 /*
   1584  * undo what was done in usbser_open_init()
   1585  */
   1586 static void
   1587 usbser_open_fini(usbser_port_t *pp)
   1588 {
   1589 	uint_t		port_num = pp->port_num;
   1590 	usbser_state_t	*usp = pp->port_usp;
   1591 
   1592 	/*
   1593 	 * close DSD if it is open
   1594 	 */
   1595 	if (pp->port_flags & USBSER_FL_DSD_OPEN) {
   1596 		mutex_exit(&pp->port_mutex);
   1597 		if (USBSER_DS_CLOSE_PORT(usp, port_num) != USB_SUCCESS) {
   1598 			USB_DPRINTF_L2(DPRINT_CLOSE, pp->port_lh,
   1599 			    "usbser_open_fini: CLOSE_PORT fail");
   1600 		}
   1601 		mutex_enter(&pp->port_mutex);
   1602 	}
   1603 
   1604 	/*
   1605 	 * cancel threads
   1606 	 */
   1607 	usbser_thr_cancel(&pp->port_wq_thread);
   1608 	usbser_thr_cancel(&pp->port_rq_thread);
   1609 
   1610 	/*
   1611 	 * unpdate soft state
   1612 	 */
   1613 	pp->port_state = USBSER_PORT_CLOSED;
   1614 	cv_broadcast(&pp->port_state_cv);
   1615 	cv_broadcast(&pp->port_car_cv);
   1616 }
   1617 
   1618 
   1619 /*
   1620  * setup serial line
   1621  */
   1622 static int
   1623 usbser_open_line_setup(usbser_port_t *pp, int minor, int flag)
   1624 {
   1625 	int	rval;
   1626 
   1627 	mutex_exit(&pp->port_mutex);
   1628 	/*
   1629 	 * prevent opening a disconnected device
   1630 	 */
   1631 	if (!usbser_dev_is_online(pp->port_usp)) {
   1632 		mutex_enter(&pp->port_mutex);
   1633 
   1634 		return (ENXIO);
   1635 	}
   1636 
   1637 	/* raise DTR on every open */
   1638 	(void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR, TIOCM_DTR);
   1639 
   1640 	mutex_enter(&pp->port_mutex);
   1641 	/*
   1642 	 * check carrier
   1643 	 */
   1644 	rval = usbser_open_carrier_check(pp, minor, flag);
   1645 
   1646 	return (rval);
   1647 }
   1648 
   1649 
   1650 /*
   1651  * check carrier and wait if needed
   1652  */
   1653 static int
   1654 usbser_open_carrier_check(usbser_port_t *pp, int minor, int flag)
   1655 {
   1656 	tty_common_t	*tp = &pp->port_ttycommon;
   1657 	int		val = 0;
   1658 	int		rval;
   1659 
   1660 	if (pp->port_flags & USBSER_FL_IGNORE_CD) {
   1661 		tp->t_flags |= TS_SOFTCAR;
   1662 	}
   1663 
   1664 	/*
   1665 	 * check carrier
   1666 	 */
   1667 	if (tp->t_flags & TS_SOFTCAR) {
   1668 		pp->port_flags |= USBSER_FL_CARR_ON;
   1669 	} else if (USBSER_DS_GET_MODEM_CTL(pp, TIOCM_CD, &val) != USB_SUCCESS) {
   1670 
   1671 		return (ENXIO);
   1672 	} else if (val & TIOCM_CD) {
   1673 		pp->port_flags |= USBSER_FL_CARR_ON;
   1674 	} else {
   1675 		pp->port_flags &= ~USBSER_FL_CARR_ON;
   1676 	}
   1677 
   1678 	/*
   1679 	 * don't block if 1) not allowed to, 2) this is a local device,
   1680 	 * 3) opening in dial-out mode, or 4) carrier is already on
   1681 	 */
   1682 	if ((flag & (FNDELAY | FNONBLOCK)) || (tp->t_cflag & CLOCAL) ||
   1683 	    (minor & OUTLINE) || (pp->port_flags & USBSER_FL_CARR_ON)) {
   1684 
   1685 		return (USBSER_COMPLETE);
   1686 	}
   1687 
   1688 	/*
   1689 	 * block until carrier up (only in tty mode)
   1690 	 */
   1691 	USB_DPRINTF_L4(DPRINT_OPEN, pp->port_lh,
   1692 	    "usbser_open_carrier_check: waiting for carrier...");
   1693 
   1694 	pp->port_flags |= USBSER_FL_WOPEN;
   1695 
   1696 	rval = cv_wait_sig(&pp->port_car_cv, &pp->port_mutex);
   1697 
   1698 	pp->port_flags &= ~USBSER_FL_WOPEN;
   1699 
   1700 	if (rval == 0) {
   1701 		/*
   1702 		 * interrupted with a signal
   1703 		 */
   1704 		return (EINTR);
   1705 	} else {
   1706 		/*
   1707 		 * try again
   1708 		 */
   1709 		return (USBSER_CONTINUE);
   1710 	}
   1711 }
   1712 
   1713 
   1714 /*
   1715  * during open, setup queues and message processing
   1716  */
   1717 static void
   1718 usbser_open_queues_init(usbser_port_t *pp, queue_t *rq)
   1719 {
   1720 	pp->port_ttycommon.t_readq = rq;
   1721 	pp->port_ttycommon.t_writeq = WR(rq);
   1722 	rq->q_ptr = WR(rq)->q_ptr = (caddr_t)pp;
   1723 
   1724 	qprocson(rq);
   1725 }
   1726 
   1727 
   1728 /*
   1729  * clean up queues and message processing
   1730  */
   1731 static void
   1732 usbser_open_queues_fini(usbser_port_t *pp)
   1733 {
   1734 	queue_t	*rq = pp->port_ttycommon.t_readq;
   1735 
   1736 	mutex_exit(&pp->port_mutex);
   1737 	/*
   1738 	 * clean up queues
   1739 	 */
   1740 	qprocsoff(rq);
   1741 
   1742 	/*
   1743 	 * free unused messages
   1744 	 */
   1745 	flushq(rq, FLUSHALL);
   1746 	flushq(WR(rq), FLUSHALL);
   1747 
   1748 	rq->q_ptr = WR(rq)->q_ptr = NULL;
   1749 	ttycommon_close(&pp->port_ttycommon);
   1750 	mutex_enter(&pp->port_mutex);
   1751 }
   1752 
   1753 
   1754 /*
   1755  * during close, wait until pending data is gone or the signal is sent
   1756  */
   1757 static void
   1758 usbser_close_drain(usbser_port_t *pp)
   1759 {
   1760 	int	need_drain;
   1761 	clock_t	until;
   1762 	int	rval;
   1763 
   1764 	/*
   1765 	 * port_wq_data_cnt indicates amount of data on the write queue,
   1766 	 * which becomes zero when all data is submitted to DSD. But usbser
   1767 	 * stays busy until it gets tx callback from DSD, signalling that
   1768 	 * data has been sent over USB. To be continued in the next comment...
   1769 	 */
   1770 	until = ddi_get_lbolt() +
   1771 	    drv_usectohz(USBSER_WQ_DRAIN_TIMEOUT * 1000000);
   1772 
   1773 	while ((pp->port_wq_data_cnt > 0) && USBSER_PORT_IS_BUSY(pp)) {
   1774 		if ((rval = cv_timedwait_sig(&pp->port_act_cv, &pp->port_mutex,
   1775 		    until)) <= 0) {
   1776 
   1777 			break;
   1778 		}
   1779 	}
   1780 
   1781 	/* don't drain if timed out or received a signal */
   1782 	need_drain = (pp->port_wq_data_cnt == 0) || !USBSER_PORT_IS_BUSY(pp) ||
   1783 	    (rval != 0);
   1784 
   1785 	mutex_exit(&pp->port_mutex);
   1786 	/*
   1787 	 * Once the data reaches USB serial box, it may still be stored in its
   1788 	 * internal output buffer (FIFO). We call DSD drain to ensure that all
   1789 	 * the data is transmitted transmitted over the serial line.
   1790 	 */
   1791 	if (need_drain) {
   1792 		rval = USBSER_DS_FIFO_DRAIN(pp, USBSER_TX_FIFO_DRAIN_TIMEOUT);
   1793 		if (rval != USB_SUCCESS) {
   1794 			(void) USBSER_DS_FIFO_FLUSH(pp, DS_TX);
   1795 		}
   1796 	} else {
   1797 		(void) USBSER_DS_FIFO_FLUSH(pp, DS_TX);
   1798 	}
   1799 	mutex_enter(&pp->port_mutex);
   1800 }
   1801 
   1802 
   1803 /*
   1804  * during close, cancel break/delay
   1805  */
   1806 static void
   1807 usbser_close_cancel_break(usbser_port_t *pp)
   1808 {
   1809 	timeout_id_t	delay_id;
   1810 
   1811 	if (pp->port_act & USBSER_ACT_BREAK) {
   1812 		delay_id = pp->port_delay_id;
   1813 		pp->port_delay_id = 0;
   1814 
   1815 		mutex_exit(&pp->port_mutex);
   1816 		(void) untimeout(delay_id);
   1817 		(void) USBSER_DS_BREAK_CTL(pp, DS_OFF);
   1818 		mutex_enter(&pp->port_mutex);
   1819 
   1820 		pp->port_act &= ~USBSER_ACT_BREAK;
   1821 	}
   1822 }
   1823 
   1824 
   1825 /*
   1826  * during close, drop RTS/DTR if necessary
   1827  */
   1828 static void
   1829 usbser_close_hangup(usbser_port_t *pp)
   1830 {
   1831 	/*
   1832 	 * drop DTR and RTS if HUPCL is set
   1833 	 */
   1834 	if (pp->port_ttycommon.t_cflag & HUPCL) {
   1835 		mutex_exit(&pp->port_mutex);
   1836 		(void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_RTS | TIOCM_DTR, 0);
   1837 		mutex_enter(&pp->port_mutex);
   1838 	}
   1839 }
   1840 
   1841 
   1842 /*
   1843  * state cleanup during close
   1844  */
   1845 static void
   1846 usbser_close_cleanup(usbser_port_t *pp)
   1847 {
   1848 	usbser_open_queues_fini(pp);
   1849 
   1850 	usbser_open_fini(pp);
   1851 }
   1852 
   1853 
   1854 /*
   1855  *
   1856  * thread management
   1857  * -----------------
   1858  *
   1859  *
   1860  * dispatch a thread
   1861  */
   1862 static void
   1863 usbser_thr_dispatch(usbser_thread_t *thr)
   1864 {
   1865 	usbser_port_t	*pp = thr->thr_port;
   1866 	usbser_state_t	*usp = pp->port_usp;
   1867 	int		rval;
   1868 
   1869 	ASSERT(mutex_owned(&pp->port_mutex));
   1870 	ASSERT((thr->thr_flags & USBSER_THR_RUNNING) == 0);
   1871 
   1872 	thr->thr_flags = USBSER_THR_RUNNING;
   1873 
   1874 	rval = ddi_taskq_dispatch(usp->us_taskq, thr->thr_func, thr->thr_arg,
   1875 	    DDI_SLEEP);
   1876 	ASSERT(rval == DDI_SUCCESS);
   1877 }
   1878 
   1879 
   1880 /*
   1881  * cancel a thread
   1882  */
   1883 static void
   1884 usbser_thr_cancel(usbser_thread_t *thr)
   1885 {
   1886 	usbser_port_t	*pp = thr->thr_port;
   1887 
   1888 	ASSERT(mutex_owned(&pp->port_mutex));
   1889 
   1890 	thr->thr_flags &= ~USBSER_THR_RUNNING;
   1891 	cv_signal(&thr->thr_cv);
   1892 
   1893 	/* wait until the thread actually exits */
   1894 	do {
   1895 		cv_wait(&thr->thr_cv, &pp->port_mutex);
   1896 
   1897 	} while ((thr->thr_flags & USBSER_THR_EXITED) == 0);
   1898 }
   1899 
   1900 
   1901 /*
   1902  * wake thread
   1903  */
   1904 static void
   1905 usbser_thr_wake(usbser_thread_t *thr)
   1906 {
   1907 	usbser_port_t	*pp = thr->thr_port;
   1908 
   1909 	ASSERT(mutex_owned(&pp->port_mutex));
   1910 
   1911 	thr->thr_flags |= USBSER_THR_WAKE;
   1912 	cv_signal(&thr->thr_cv);
   1913 }
   1914 
   1915 
   1916 /*
   1917  * thread handling write queue requests
   1918  */
   1919 static void
   1920 usbser_wq_thread(void *arg)
   1921 {
   1922 	usbser_thread_t	*thr = (usbser_thread_t *)arg;
   1923 	usbser_port_t	*pp = thr->thr_port;
   1924 
   1925 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wq_thread: enter");
   1926 
   1927 	mutex_enter(&pp->port_mutex);
   1928 	while (thr->thr_flags & USBSER_THR_RUNNING) {
   1929 		/*
   1930 		 * when woken, see what we should do
   1931 		 */
   1932 		if (thr->thr_flags & USBSER_THR_WAKE) {
   1933 			thr->thr_flags &= ~USBSER_THR_WAKE;
   1934 
   1935 			/*
   1936 			 * status callback pending?
   1937 			 */
   1938 			if (pp->port_flags & USBSER_FL_STATUS_CB) {
   1939 				usbser_status_proc_cb(pp);
   1940 			}
   1941 
   1942 			usbser_wmsg(pp);
   1943 		} else {
   1944 			/*
   1945 			 * sleep until woken up to do some work, e.g:
   1946 			 * - new message arrives;
   1947 			 * - data transmit completes;
   1948 			 * - status callback pending;
   1949 			 * - wq thread is cancelled;
   1950 			 */
   1951 			cv_wait(&thr->thr_cv, &pp->port_mutex);
   1952 			USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
   1953 			    "usbser_wq_thread: wakeup");
   1954 		}
   1955 	}
   1956 	thr->thr_flags |= USBSER_THR_EXITED;
   1957 	cv_signal(&thr->thr_cv);
   1958 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wq_thread: exit");
   1959 	mutex_exit(&pp->port_mutex);
   1960 }
   1961 
   1962 
   1963 /*
   1964  * thread handling read queue requests
   1965  */
   1966 static void
   1967 usbser_rq_thread(void *arg)
   1968 {
   1969 	usbser_thread_t	*thr = (usbser_thread_t *)arg;
   1970 	usbser_port_t	*pp = thr->thr_port;
   1971 
   1972 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_rq_thread: enter");
   1973 
   1974 	mutex_enter(&pp->port_mutex);
   1975 	while (thr->thr_flags & USBSER_THR_RUNNING) {
   1976 		/*
   1977 		 * read service routine will wake us when
   1978 		 * more space is available on the read queue
   1979 		 */
   1980 		if (thr->thr_flags & USBSER_THR_WAKE) {
   1981 			thr->thr_flags &= ~USBSER_THR_WAKE;
   1982 
   1983 			/*
   1984 			 * don't process messages until queue is enabled
   1985 			 */
   1986 			if (!pp->port_ttycommon.t_readq) {
   1987 
   1988 				continue;
   1989 			}
   1990 
   1991 			/*
   1992 			 * check whether we need to resume receive
   1993 			 */
   1994 			if (pp->port_flags & USBSER_FL_RX_STOPPED) {
   1995 				pp->port_flowc = pp->port_ttycommon.t_startc;
   1996 				usbser_inbound_flow_ctl(pp);
   1997 			}
   1998 
   1999 			/*
   2000 			 * grab more data if available
   2001 			 */
   2002 			mutex_exit(&pp->port_mutex);
   2003 			usbser_rx_cb((caddr_t)pp);
   2004 			mutex_enter(&pp->port_mutex);
   2005 		} else {
   2006 			cv_wait(&thr->thr_cv, &pp->port_mutex);
   2007 			USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
   2008 			    "usbser_rq_thread: wakeup");
   2009 		}
   2010 	}
   2011 	thr->thr_flags |= USBSER_THR_EXITED;
   2012 	cv_signal(&thr->thr_cv);
   2013 	USB_DPRINTF_L4(DPRINT_RQ, pp->port_lh, "usbser_rq_thread: exit");
   2014 	mutex_exit(&pp->port_mutex);
   2015 }
   2016 
   2017 
   2018 /*
   2019  * DSD callbacks
   2020  * -------------
   2021  *
   2022  * Note: to avoid deadlocks with DSD, these callbacks
   2023  * should not call DSD functions that can block.
   2024  *
   2025  *
   2026  * transmit callback
   2027  *
   2028  * invoked by DSD when the last byte of data is transmitted over USB
   2029  */
   2030 static void
   2031 usbser_tx_cb(caddr_t arg)
   2032 {
   2033 	usbser_port_t	*pp = (usbser_port_t *)arg;
   2034 	int		online;
   2035 
   2036 	online = usbser_dev_is_online(pp->port_usp);
   2037 
   2038 	mutex_enter(&pp->port_mutex);
   2039 	USB_DPRINTF_L4(DPRINT_TX_CB, pp->port_lh,
   2040 	    "usbser_tx_cb: act=%x curthread=%p", pp->port_act,
   2041 	    (void *)curthread);
   2042 
   2043 	usbser_release_port_act(pp, USBSER_ACT_TX);
   2044 
   2045 	/*
   2046 	 * as long as port access is ok and the port is not busy on
   2047 	 * TX, break, ctrl or delay, the wq_thread should be waken
   2048 	 * to do further process for next message
   2049 	 */
   2050 	if (online && USBSER_PORT_ACCESS_OK(pp) &&
   2051 	    !USBSER_PORT_IS_BUSY_NON_RX(pp)) {
   2052 		/*
   2053 		 * wake wq thread for further data/ioctl processing
   2054 		 */
   2055 		usbser_thr_wake(&pp->port_wq_thread);
   2056 	}
   2057 	mutex_exit(&pp->port_mutex);
   2058 }
   2059 
   2060 
   2061 /*
   2062  * receive callback
   2063  *
   2064  * invoked by DSD when there is more data for us to pick
   2065  */
   2066 static void
   2067 usbser_rx_cb(caddr_t arg)
   2068 {
   2069 	usbser_port_t	*pp = (usbser_port_t *)arg;
   2070 	queue_t		*rq, *wq;
   2071 	mblk_t		*mp;		/* current mblk */
   2072 	mblk_t		*data, *data_tail; /* M_DATA mblk list and its tail */
   2073 	mblk_t		*emp;		/* error (M_BREAK) mblk */
   2074 
   2075 	USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh, "usbser_rx_cb");
   2076 
   2077 	if (!usbser_dev_is_online(pp->port_usp)) {
   2078 
   2079 		return;
   2080 	}
   2081 
   2082 	/* get data from DSD */
   2083 	if ((mp = USBSER_DS_RX(pp)) == NULL) {
   2084 
   2085 		return;
   2086 	}
   2087 
   2088 	mutex_enter(&pp->port_mutex);
   2089 	if ((!USBSER_PORT_ACCESS_OK(pp)) ||
   2090 	    ((pp->port_ttycommon.t_cflag & CREAD) == 0)) {
   2091 		freemsg(mp);
   2092 		mutex_exit(&pp->port_mutex);
   2093 		USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
   2094 		    "usbser_rx_cb: access not ok or receiver disabled");
   2095 
   2096 		return;
   2097 	}
   2098 
   2099 	usbser_serialize_port_act(pp, USBSER_ACT_RX);
   2100 
   2101 	rq = pp->port_ttycommon.t_readq;
   2102 	wq = pp->port_ttycommon.t_writeq;
   2103 	mutex_exit(&pp->port_mutex);
   2104 
   2105 	/*
   2106 	 * DSD data is a b_cont-linked list of M_DATA and M_BREAK blocks.
   2107 	 * M_DATA is correctly received data.
   2108 	 * M_BREAK is a character with either framing or parity error.
   2109 	 *
   2110 	 * this loop runs through the list of mblks. when it meets an M_BREAK,
   2111 	 * it sends all leading M_DATA's in one shot, then sends M_BREAK.
   2112 	 * in the trivial case when list contains only M_DATA's, the loop
   2113 	 * does nothing but set data variable.
   2114 	 */
   2115 	data = data_tail = NULL;
   2116 	while (mp) {
   2117 		/*
   2118 		 * skip data until we meet M_BREAK or end of list
   2119 		 */
   2120 		if (DB_TYPE(mp) == M_DATA) {
   2121 			if (data == NULL) {
   2122 				data = mp;
   2123 			}
   2124 			data_tail = mp;
   2125 			mp = mp->b_cont;
   2126 
   2127 			continue;
   2128 		}
   2129 
   2130 		/* detach data list from mp */
   2131 		if (data_tail) {
   2132 			data_tail->b_cont = NULL;
   2133 		}
   2134 		/* detach emp from the list */
   2135 		emp = mp;
   2136 		mp = mp->b_cont;
   2137 		emp->b_cont = NULL;
   2138 
   2139 		/* DSD shouldn't send anything but M_DATA or M_BREAK */
   2140 		if ((DB_TYPE(emp) != M_BREAK) || (MBLKL(emp) != 2)) {
   2141 			freemsg(emp);
   2142 			USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
   2143 			    "usbser_rx_cb: bad message");
   2144 
   2145 			continue;
   2146 		}
   2147 
   2148 		/*
   2149 		 * first tweak and send M_DATA's
   2150 		 */
   2151 		if (data) {
   2152 			usbser_rx_massage_data(pp, data);
   2153 			usbser_rx_cb_put(pp, rq, wq, data);
   2154 			data = data_tail = NULL;
   2155 		}
   2156 
   2157 		/*
   2158 		 * now tweak and send M_BREAK
   2159 		 */
   2160 		mutex_enter(&pp->port_mutex);
   2161 		usbser_rx_massage_mbreak(pp, emp);
   2162 		mutex_exit(&pp->port_mutex);
   2163 		usbser_rx_cb_put(pp, rq, wq, emp);
   2164 	}
   2165 
   2166 	/* send the rest of the data, if any */
   2167 	if (data) {
   2168 		usbser_rx_massage_data(pp, data);
   2169 		usbser_rx_cb_put(pp, rq, wq, data);
   2170 	}
   2171 
   2172 	mutex_enter(&pp->port_mutex);
   2173 	usbser_release_port_act(pp, USBSER_ACT_RX);
   2174 	mutex_exit(&pp->port_mutex);
   2175 }
   2176 
   2177 /*
   2178  * the joys of termio -- this is to accomodate Unix98 assertion:
   2179  *
   2180  *   If PARENB is supported and is set, when PARMRK is set, and CSIZE is
   2181  *   set to CS8, and IGNPAR is clear, and ISTRIP is clear, a valid
   2182  *   character of '\377' is read as '\377', '\377'.
   2183  *
   2184  *   Posix Ref: Assertion 7.1.2.2-16(C)
   2185  *
   2186  * this requires the driver to scan every incoming valid character
   2187  */
   2188 static void
   2189 usbser_rx_massage_data(usbser_port_t *pp, mblk_t *mp)
   2190 {
   2191 	tty_common_t	*tp = &pp->port_ttycommon;
   2192 	uchar_t		*p;
   2193 	mblk_t		*newmp;
   2194 	int		tailsz;
   2195 
   2196 	/* avoid scanning if possible */
   2197 	mutex_enter(&pp->port_mutex);
   2198 	if (!((tp->t_cflag & PARENB) && (tp->t_iflag & PARMRK) &&
   2199 	    ((tp->t_cflag & CSIZE) == CS8) &&
   2200 	    ((tp->t_iflag & (IGNPAR|ISTRIP)) == 0))) {
   2201 		mutex_exit(&pp->port_mutex);
   2202 
   2203 		return;
   2204 	}
   2205 	mutex_exit(&pp->port_mutex);
   2206 
   2207 	while (mp) {
   2208 		for (p = mp->b_rptr; p < mp->b_wptr; ) {
   2209 			if (*p++ != 0377) {
   2210 
   2211 				continue;
   2212 			}
   2213 			USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
   2214 			    "usbser_rx_massage_data: mp=%p off=%ld(%ld)",
   2215 			    (void *)mp, _PTRDIFF(p,  mp->b_rptr) - 1,
   2216 			    (long)MBLKL(mp));
   2217 
   2218 			/*
   2219 			 * insert another 0377 after this one. all data after
   2220 			 * the original 0377 have to be copied to the new mblk
   2221 			 */
   2222 			tailsz = _PTRDIFF(mp->b_wptr, p);
   2223 			if ((newmp = allocb(tailsz + 1, BPRI_HI)) == NULL) {
   2224 				USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
   2225 				    "usbser_rx_massage_data: allocb failed");
   2226 
   2227 				continue;
   2228 			}
   2229 
   2230 			/* fill in the new mblk */
   2231 			*newmp->b_wptr++ = 0377;
   2232 			if (tailsz > 0) {
   2233 				bcopy(p, newmp->b_wptr, tailsz);
   2234 				newmp->b_wptr += tailsz;
   2235 			}
   2236 			/* shrink the original mblk */
   2237 			mp->b_wptr = p;
   2238 
   2239 			newmp->b_cont = mp->b_cont;
   2240 			mp->b_cont = newmp;
   2241 			p = newmp->b_rptr + 1;
   2242 			mp = newmp;
   2243 		}
   2244 		mp = mp->b_cont;
   2245 	}
   2246 }
   2247 
   2248 /*
   2249  * more joys of termio
   2250  */
   2251 static void
   2252 usbser_rx_massage_mbreak(usbser_port_t *pp, mblk_t *mp)
   2253 {
   2254 	tty_common_t	*tp = &pp->port_ttycommon;
   2255 	uchar_t		err, c;
   2256 
   2257 	err = *mp->b_rptr;
   2258 	c = *(mp->b_rptr + 1);
   2259 
   2260 	if ((err & (DS_FRAMING_ERR | DS_BREAK_ERR)) && (c == 0)) {
   2261 		/* break */
   2262 		mp->b_rptr += 2;
   2263 	} else if (!(tp->t_iflag & INPCK) && (err & (DS_PARITY_ERR))) {
   2264 		/* Posix Ref: Assertion 7.1.2.2-20(C) */
   2265 		mp->b_rptr++;
   2266 		DB_TYPE(mp) = M_DATA;
   2267 	} else {
   2268 		/* for ldterm to handle */
   2269 		mp->b_rptr++;
   2270 	}
   2271 
   2272 	USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
   2273 	    "usbser_rx_massage_mbreak: type=%x len=%ld [0]=0%o",
   2274 	    DB_TYPE(mp), (long)MBLKL(mp), (MBLKL(mp) > 0) ? *mp->b_rptr : 45);
   2275 }
   2276 
   2277 
   2278 /*
   2279  * in rx callback, try to send an mblk upstream
   2280  */
   2281 static void
   2282 usbser_rx_cb_put(usbser_port_t *pp, queue_t *rq, queue_t *wq, mblk_t *mp)
   2283 {
   2284 	if (canputnext(rq)) {
   2285 		putnext(rq, mp);
   2286 	} else if (canput(rq) && putq(rq, mp)) {
   2287 		/*
   2288 		 * full queue indicates the need for inbound flow control
   2289 		 */
   2290 		(void) putctl(wq, M_STOPI);
   2291 		usbser_st_put_stopi++;
   2292 
   2293 		USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
   2294 		    "usbser_rx_cb: cannot putnext, flow ctl");
   2295 	} else {
   2296 		freemsg(mp);
   2297 		usbser_st_rx_data_loss++;
   2298 		(void) putctl(wq, M_STOPI);
   2299 		usbser_st_put_stopi++;
   2300 
   2301 		USB_DPRINTF_L1(DPRINT_RX_CB, pp->port_lh,
   2302 		    "input overrun");
   2303 	}
   2304 }
   2305 
   2306 
   2307 /*
   2308  * modem status change callback
   2309  *
   2310  * each time external status lines are changed, DSD calls this routine
   2311  */
   2312 static void
   2313 usbser_status_cb(caddr_t arg)
   2314 {
   2315 	usbser_port_t	*pp = (usbser_port_t *)arg;
   2316 
   2317 	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_cb");
   2318 
   2319 	if (!usbser_dev_is_online(pp->port_usp)) {
   2320 
   2321 		return;
   2322 	}
   2323 
   2324 	/*
   2325 	 * actual processing will be done in usbser_status_proc_cb()
   2326 	 * running in wq thread
   2327 	 */
   2328 	mutex_enter(&pp->port_mutex);
   2329 	if (USBSER_PORT_ACCESS_OK(pp) || USBSER_IS_OPENING(pp)) {
   2330 		pp->port_flags |= USBSER_FL_STATUS_CB;
   2331 		usbser_thr_wake(&pp->port_wq_thread);
   2332 	}
   2333 	mutex_exit(&pp->port_mutex);
   2334 }
   2335 
   2336 
   2337 /*
   2338  * modem status change
   2339  */
   2340 static void
   2341 usbser_status_proc_cb(usbser_port_t *pp)
   2342 {
   2343 	tty_common_t	*tp = &pp->port_ttycommon;
   2344 	queue_t		*rq, *wq;
   2345 	int		status;
   2346 	int		drop_dtr = 0;
   2347 	int		rq_msg = 0, wq_msg = 0;
   2348 
   2349 	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_proc_cb");
   2350 
   2351 	pp->port_flags &= ~USBSER_FL_STATUS_CB;
   2352 
   2353 	mutex_exit(&pp->port_mutex);
   2354 	if (!usbser_dev_is_online(pp->port_usp)) {
   2355 		mutex_enter(&pp->port_mutex);
   2356 
   2357 		return;
   2358 	}
   2359 
   2360 	/* get modem status */
   2361 	if (USBSER_DS_GET_MODEM_CTL(pp, -1, &status) != USB_SUCCESS) {
   2362 		mutex_enter(&pp->port_mutex);
   2363 
   2364 		return;
   2365 	}
   2366 
   2367 	mutex_enter(&pp->port_mutex);
   2368 	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
   2369 
   2370 	rq = pp->port_ttycommon.t_readq;
   2371 	wq = pp->port_ttycommon.t_writeq;
   2372 
   2373 	/*
   2374 	 * outbound flow control
   2375 	 */
   2376 	if (tp->t_cflag & CRTSCTS) {
   2377 		if (!(status & TIOCM_CTS)) {
   2378 			/*
   2379 			 * CTS dropped, stop xmit
   2380 			 */
   2381 			if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
   2382 				wq_msg = M_STOP;
   2383 			}
   2384 		} else if (pp->port_flags & USBSER_FL_TX_STOPPED) {
   2385 			/*
   2386 			 * CTS raised, resume xmit
   2387 			 */
   2388 			wq_msg = M_START;
   2389 		}
   2390 	}
   2391 
   2392 	/*
   2393 	 * check carrier
   2394 	 */
   2395 	if ((status & TIOCM_CD) || (tp->t_flags & TS_SOFTCAR)) {
   2396 		/*
   2397 		 * carrier present
   2398 		 */
   2399 		if ((pp->port_flags & USBSER_FL_CARR_ON) == 0) {
   2400 			pp->port_flags |= USBSER_FL_CARR_ON;
   2401 
   2402 			rq_msg = M_UNHANGUP;
   2403 			/*
   2404 			 * wake open
   2405 			 */
   2406 			if (pp->port_flags & USBSER_FL_WOPEN) {
   2407 				cv_broadcast(&pp->port_car_cv);
   2408 			}
   2409 
   2410 			USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
   2411 			    "usbser_status_cb: carr on");
   2412 		}
   2413 	} else if (pp->port_flags & USBSER_FL_CARR_ON) {
   2414 		pp->port_flags &= ~USBSER_FL_CARR_ON;
   2415 		/*
   2416 		 * carrier went away: if not local line, drop DTR
   2417 		 */
   2418 		if (!(tp->t_cflag & CLOCAL)) {
   2419 			drop_dtr = 1;
   2420 			rq_msg = M_HANGUP;
   2421 		}
   2422 		if ((pp->port_flags & USBSER_FL_TX_STOPPED) && (wq_msg == 0)) {
   2423 			wq_msg = M_START;
   2424 		}
   2425 
   2426 		USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
   2427 		    "usbser_status_cb: carr off");
   2428 	}
   2429 	mutex_exit(&pp->port_mutex);
   2430 
   2431 	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
   2432 	    "usbser_status_cb: rq_msg=%d wq_msg=%d", rq_msg, wq_msg);
   2433 
   2434 	/*
   2435 	 * commit postponed actions now
   2436 	 * do so only if port is fully open (queues are enabled)
   2437 	 */
   2438 	if (rq) {
   2439 		if (rq_msg) {
   2440 			(void) putnextctl(rq, rq_msg);
   2441 		}
   2442 		if (drop_dtr) {
   2443 			(void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR, 0);
   2444 		}
   2445 		if (wq_msg) {
   2446 			(void) putctl(wq, wq_msg);
   2447 		}
   2448 	}
   2449 
   2450 	mutex_enter(&pp->port_mutex);
   2451 	usbser_release_port_act(pp, USBSER_ACT_CTL);
   2452 }
   2453 
   2454 
   2455 /*
   2456  * serial support
   2457  * --------------
   2458  *
   2459  *
   2460  * this routine is run by wq thread every time it's woken,
   2461  * i.e. when the queue contains messages to process
   2462  */
   2463 static void
   2464 usbser_wmsg(usbser_port_t *pp)
   2465 {
   2466 	queue_t		*q = pp->port_ttycommon.t_writeq;
   2467 	mblk_t		*mp;
   2468 	int		msgtype;
   2469 
   2470 	ASSERT(mutex_owned(&pp->port_mutex));
   2471 
   2472 	if (q == NULL) {
   2473 		USB_DPRINTF_L3(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=NULL");
   2474 
   2475 		return;
   2476 	}
   2477 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=%p act=%x 0x%x",
   2478 	    (void *)q, pp->port_act, q->q_first ? DB_TYPE(q->q_first) : 0xff);
   2479 
   2480 	while ((mp = getq(q)) != NULL) {
   2481 		msgtype = DB_TYPE(mp);
   2482 		USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: "
   2483 		    "type=%s (0x%x)", usbser_msgtype2str(msgtype), msgtype);
   2484 
   2485 		switch (msgtype) {
   2486 		/*
   2487 		 * high-priority messages
   2488 		 */
   2489 		case M_STOP:
   2490 			usbser_stop(pp, mp);
   2491 
   2492 			break;
   2493 		case M_START:
   2494 			usbser_start(pp, mp);
   2495 
   2496 			break;
   2497 		case M_STOPI:
   2498 			usbser_stopi(pp, mp);
   2499 
   2500 			break;
   2501 		case M_STARTI:
   2502 			usbser_starti(pp, mp);
   2503 
   2504 			break;
   2505 		case M_IOCDATA:
   2506 			usbser_iocdata(pp, mp);
   2507 
   2508 			break;
   2509 		case M_FLUSH:
   2510 			usbser_flush(pp, mp);
   2511 
   2512 			break;
   2513 		/*
   2514 		 * normal-priority messages
   2515 		 */
   2516 		case M_BREAK:
   2517 			usbser_break(pp, mp);
   2518 
   2519 			break;
   2520 		case M_DELAY:
   2521 			usbser_delay(pp, mp);
   2522 
   2523 			break;
   2524 		case M_DATA:
   2525 			if (usbser_data(pp, mp) != USB_SUCCESS) {
   2526 				(void) putbq(q, mp);
   2527 
   2528 				return;
   2529 			}
   2530 
   2531 			break;
   2532 		case M_IOCTL:
   2533 			if (usbser_ioctl(pp, mp) != USB_SUCCESS) {
   2534 				(void) putbq(q, mp);
   2535 
   2536 				return;
   2537 			}
   2538 
   2539 			break;
   2540 		default:
   2541 			freemsg(mp);
   2542 
   2543 			break;
   2544 		}
   2545 	}
   2546 }
   2547 
   2548 
   2549 /*
   2550  * process M_DATA message
   2551  */
   2552 static int
   2553 usbser_data(usbser_port_t *pp, mblk_t *mp)
   2554 {
   2555 	/* put off until current transfer ends or delay is over */
   2556 	if ((pp->port_act & USBSER_ACT_TX) ||
   2557 	    (pp->port_act & USBSER_ACT_DELAY)) {
   2558 
   2559 		return (USB_FAILURE);
   2560 	}
   2561 	if (MBLKL(mp) <= 0) {
   2562 		freemsg(mp);
   2563 
   2564 		return (USB_SUCCESS);
   2565 	}
   2566 
   2567 	pp->port_act |= USBSER_ACT_TX;
   2568 	pp->port_wq_data_cnt -= msgdsize(mp);
   2569 
   2570 	mutex_exit(&pp->port_mutex);
   2571 	/* DSD is required to accept data block in any case */
   2572 	(void) USBSER_DS_TX(pp, mp);
   2573 	mutex_enter(&pp->port_mutex);
   2574 
   2575 	return (USB_SUCCESS);
   2576 }
   2577 
   2578 
   2579 /*
   2580  * process an M_IOCTL message
   2581  */
   2582 static int
   2583 usbser_ioctl(usbser_port_t *pp, mblk_t *mp)
   2584 {
   2585 	tty_common_t	*tp = &pp->port_ttycommon;
   2586 	queue_t		*q = tp->t_writeq;
   2587 	struct iocblk	*iocp;
   2588 	int		cmd;
   2589 	mblk_t		*datamp;
   2590 	int		error = 0, rval;
   2591 	int		val;
   2592 
   2593 	ASSERT(mutex_owned(&pp->port_mutex));
   2594 	ASSERT(DB_TYPE(mp) == M_IOCTL);
   2595 
   2596 	iocp = (struct iocblk *)mp->b_rptr;
   2597 	cmd = iocp->ioc_cmd;
   2598 
   2599 	USB_DPRINTF_L4(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
   2600 	    "mp=%p %s (0x%x)", (void *)mp, usbser_ioctl2str(cmd), cmd);
   2601 
   2602 	if (tp->t_iocpending != NULL) {
   2603 		/*
   2604 		 * We were holding an ioctl response pending the
   2605 		 * availability of an mblk to hold data to be passed up;
   2606 		 * another ioctl came through, which means that ioctl
   2607 		 * must have timed out or been aborted.
   2608 		 */
   2609 		freemsg(tp->t_iocpending);
   2610 		tp->t_iocpending = NULL;
   2611 	}
   2612 
   2613 	switch (cmd) {
   2614 	case TIOCMGET:
   2615 	case TIOCMBIC:
   2616 	case TIOCMBIS:
   2617 	case TIOCMSET:
   2618 	case CONSOPENPOLLEDIO:
   2619 	case CONSCLOSEPOLLEDIO:
   2620 	case CONSSETABORTENABLE:
   2621 	case CONSGETABORTENABLE:
   2622 		/*
   2623 		 * For the above ioctls do not call ttycommon_ioctl() because
   2624 		 * this function frees up the message block (mp->b_cont) that
   2625 		 * contains the address of the user variable where we need to
   2626 		 * pass back the bit array.
   2627 		 */
   2628 		error = -1;
   2629 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
   2630 		mutex_exit(&pp->port_mutex);
   2631 		break;
   2632 
   2633 	case TCSBRK:
   2634 		/* serialize breaks */
   2635 		if (pp->port_act & USBSER_ACT_BREAK)
   2636 			return (USB_FAILURE);
   2637 		/*FALLTHRU*/
   2638 	default:
   2639 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
   2640 		mutex_exit(&pp->port_mutex);
   2641 		(void) ttycommon_ioctl(tp, q, mp, &error);
   2642 		break;
   2643 	}
   2644 
   2645 	if (error == 0) {
   2646 		/*
   2647 		 * ttycommon_ioctl() did most of the work
   2648 		 * we just use the data it set up
   2649 		 */
   2650 		switch (cmd) {
   2651 		case TCSETSF:
   2652 		case TCSETSW:
   2653 		case TCSETA:
   2654 		case TCSETAW:
   2655 		case TCSETAF:
   2656 			(void) USBSER_DS_FIFO_DRAIN(pp, DS_TX);
   2657 			/*FALLTHRU*/
   2658 
   2659 		case TCSETS:
   2660 			mutex_enter(&pp->port_mutex);
   2661 			error = usbser_port_program(pp);
   2662 			mutex_exit(&pp->port_mutex);
   2663 			break;
   2664 		}
   2665 		goto end;
   2666 
   2667 	} else if (error > 0) {
   2668 		USB_DPRINTF_L3(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
   2669 		    "ttycommon_ioctl returned %d", error);
   2670 		goto end;
   2671 	}
   2672 
   2673 	/*
   2674 	 * error < 0: ttycommon_ioctl() didn't do anything, we process it here
   2675 	 */
   2676 	error = 0;
   2677 	switch (cmd) {
   2678 	case TCSBRK:
   2679 		if ((error = miocpullup(mp, sizeof (int))) != 0)
   2680 			break;
   2681 
   2682 		/* drain output */
   2683 		(void) USBSER_DS_FIFO_DRAIN(pp, USBSER_TX_FIFO_DRAIN_TIMEOUT);
   2684 
   2685 		/*
   2686 		 * if required, set break
   2687 		 */
   2688 		if (*(int *)mp->b_cont->b_rptr == 0) {
   2689 			if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS) {
   2690 				error = EIO;
   2691 				break;
   2692 			}
   2693 
   2694 			mutex_enter(&pp->port_mutex);
   2695 			pp->port_act |= USBSER_ACT_BREAK;
   2696 			pp->port_delay_id = timeout(usbser_restart, pp,
   2697 			    drv_usectohz(250000));
   2698 			mutex_exit(&pp->port_mutex);
   2699 		}
   2700 		mioc2ack(mp, NULL, 0, 0);
   2701 		break;
   2702 
   2703 	case TIOCSBRK:	/* set break */
   2704 		if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS)
   2705 			error = EIO;
   2706 		else
   2707 			mioc2ack(mp, NULL, 0, 0);
   2708 		break;
   2709 
   2710 	case TIOCCBRK:	/* clear break */
   2711 		if (USBSER_DS_BREAK_CTL(pp, DS_OFF) != USB_SUCCESS)
   2712 			error = EIO;
   2713 		else
   2714 			mioc2ack(mp, NULL, 0, 0);
   2715 		break;
   2716 
   2717 	case TIOCMSET:	/* set all modem bits */
   2718 	case TIOCMBIS:	/* bis modem bits */
   2719 	case TIOCMBIC:	/* bic modem bits */
   2720 		if (iocp->ioc_count == TRANSPARENT) {
   2721 			mcopyin(mp, NULL, sizeof (int), NULL);
   2722 			break;
   2723 		}
   2724 		if ((error = miocpullup(mp, sizeof (int))) != 0)
   2725 			break;
   2726 
   2727 		val = *(int *)mp->b_cont->b_rptr;
   2728 		if (cmd == TIOCMSET) {
   2729 			rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
   2730 		} else if (cmd == TIOCMBIS) {
   2731 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
   2732 		} else if (cmd == TIOCMBIC) {
   2733 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
   2734 		}
   2735 		if (rval == USB_SUCCESS)
   2736 			mioc2ack(mp, NULL, 0, 0);
   2737 		else
   2738 			error = EIO;
   2739 		break;
   2740 
   2741 	case TIOCSILOOP:
   2742 		if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
   2743 			if (USBSER_DS_LOOPBACK(pp, DS_ON) == USB_SUCCESS)
   2744 				mioc2ack(mp, NULL, 0, 0);
   2745 			else
   2746 				error = EIO;
   2747 		} else {
   2748 			error = EINVAL;
   2749 		}
   2750 		break;
   2751 
   2752 	case TIOCCILOOP:
   2753 		if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
   2754 			if (USBSER_DS_LOOPBACK(pp, DS_OFF) == USB_SUCCESS)
   2755 				mioc2ack(mp, NULL, 0, 0);
   2756 			else
   2757 				error = EIO;
   2758 		} else {
   2759 			error = EINVAL;
   2760 		}
   2761 		break;
   2762 
   2763 	case TIOCMGET:	/* get all modem bits */
   2764 		if ((datamp = allocb(sizeof (int), BPRI_MED)) == NULL) {
   2765 			error = EAGAIN;
   2766 			break;
   2767 		}
   2768 		rval = USBSER_DS_GET_MODEM_CTL(pp, -1, (int *)datamp->b_rptr);
   2769 		if (rval != USB_SUCCESS) {
   2770 			error = EIO;
   2771 			break;
   2772 		}
   2773 		if (iocp->ioc_count == TRANSPARENT)
   2774 			mcopyout(mp, NULL, sizeof (int), NULL, datamp);
   2775 		else
   2776 			mioc2ack(mp, datamp, sizeof (int), 0);
   2777 		break;
   2778 
   2779 	case CONSOPENPOLLEDIO:
   2780 		error = usbser_polledio_init(pp);
   2781 		if (error != 0)
   2782 			break;
   2783 
   2784 		error = miocpullup(mp, sizeof (struct cons_polledio *));
   2785 		if (error != 0)
   2786 			break;
   2787 
   2788 		*(struct cons_polledio **)mp->b_cont->b_rptr = &usbser_polledio;
   2789 
   2790 		mp->b_datap->db_type = M_IOCACK;
   2791 		break;
   2792 
   2793 	case CONSCLOSEPOLLEDIO:
   2794 		usbser_polledio_fini(pp);
   2795 		mp->b_datap->db_type = M_IOCACK;
   2796 		iocp->ioc_error = 0;
   2797 		iocp->ioc_rval = 0;
   2798 		break;
   2799 
   2800 	case CONSSETABORTENABLE:
   2801 		error = secpolicy_console(iocp->ioc_cr);
   2802 		if (error != 0)
   2803 			break;
   2804 
   2805 		if (iocp->ioc_count != TRANSPARENT) {
   2806 			error = EINVAL;
   2807 			break;
   2808 		}
   2809 
   2810 		/*
   2811 		 * To do: implement console abort support
   2812 		 * This involves adding a console flag to usbser
   2813 		 * state structure. If flag is set, parse input stream
   2814 		 * for abort sequence (see asy for example).
   2815 		 *
   2816 		 * For now, run mdb -K to get kmdb prompt.
   2817 		 */
   2818 		if (*(intptr_t *)mp->b_cont->b_rptr)
   2819 			usbser_console_abort = 1;
   2820 		else
   2821 			usbser_console_abort = 0;
   2822 
   2823 		mp->b_datap->db_type = M_IOCACK;
   2824 		iocp->ioc_error = 0;
   2825 		iocp->ioc_rval = 0;
   2826 		break;
   2827 
   2828 	case CONSGETABORTENABLE:
   2829 		/*CONSTANTCONDITION*/
   2830 		ASSERT(sizeof (boolean_t) <= sizeof (boolean_t *));
   2831 		/*
   2832 		 * Store the return value right in the payload
   2833 		 * we were passed.  Crude.
   2834 		 */
   2835 		mcopyout(mp, NULL, sizeof (boolean_t), NULL, NULL);
   2836 		*(boolean_t *)mp->b_cont->b_rptr = (usbser_console_abort != 0);
   2837 		break;
   2838 
   2839 	default:
   2840 		error = EINVAL;
   2841 		break;
   2842 	}
   2843 end:
   2844 	if (error != 0)
   2845 		miocnak(q, mp, 0, error);
   2846 	else
   2847 		qreply(q, mp);
   2848 
   2849 	mutex_enter(&pp->port_mutex);
   2850 	usbser_release_port_act(pp, USBSER_ACT_CTL);
   2851 
   2852 	return (USB_SUCCESS);
   2853 }
   2854 
   2855 
   2856 /*
   2857  * process M_IOCDATA message
   2858  */
   2859 static void
   2860 usbser_iocdata(usbser_port_t *pp, mblk_t *mp)
   2861 {
   2862 	tty_common_t	*tp = &pp->port_ttycommon;
   2863 	queue_t		*q = tp->t_writeq;
   2864 	struct copyresp	*csp;
   2865 	int		cmd;
   2866 	int		val;
   2867 	int		rval;
   2868 
   2869 	ASSERT(mutex_owned(&pp->port_mutex));
   2870 
   2871 	csp = (struct copyresp *)mp->b_rptr;
   2872 	cmd = csp->cp_cmd;
   2873 
   2874 	if (csp->cp_rval != 0) {
   2875 		freemsg(mp);
   2876 		return;
   2877 	}
   2878 
   2879 	switch (cmd) {
   2880 	case TIOCMSET:	/* set all modem bits */
   2881 	case TIOCMBIS:	/* bis modem bits */
   2882 	case TIOCMBIC:	/* bic modem bits */
   2883 		if ((mp->b_cont == NULL) ||
   2884 		    (MBLKL(mp->b_cont) < sizeof (int))) {
   2885 			miocnak(q, mp, 0, EINVAL);
   2886 			break;
   2887 		}
   2888 		val = *(int *)mp->b_cont->b_rptr;
   2889 
   2890 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
   2891 		mutex_exit(&pp->port_mutex);
   2892 
   2893 		if (cmd == TIOCMSET) {
   2894 			rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
   2895 		} else if (cmd == TIOCMBIS) {
   2896 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
   2897 		} else if (cmd == TIOCMBIC) {
   2898 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
   2899 		}
   2900 
   2901 		if (mp->b_cont) {
   2902 			freemsg(mp->b_cont);
   2903 			mp->b_cont = NULL;
   2904 		}
   2905 
   2906 		if (rval == USB_SUCCESS)
   2907 			miocack(q, mp, 0, 0);
   2908 		else
   2909 			miocnak(q, mp, 0, EIO);
   2910 
   2911 		mutex_enter(&pp->port_mutex);
   2912 		usbser_release_port_act(pp, USBSER_ACT_CTL);
   2913 		break;
   2914 
   2915 	case TIOCMGET:	/* get all modem bits */
   2916 		mutex_exit(&pp->port_mutex);
   2917 		miocack(q, mp, 0, 0);
   2918 		mutex_enter(&pp->port_mutex);
   2919 		break;
   2920 
   2921 	default:
   2922 		mutex_exit(&pp->port_mutex);
   2923 		miocnak(q, mp, 0, EINVAL);
   2924 		mutex_enter(&pp->port_mutex);
   2925 		break;
   2926 	}
   2927 }
   2928 
   2929 
   2930 /*
   2931  * handle M_START[I]/M_STOP[I] messages
   2932  */
   2933 static void
   2934 usbser_stop(usbser_port_t *pp, mblk_t *mp)
   2935 {
   2936 	usbser_st_mstop++;
   2937 	if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
   2938 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
   2939 		pp->port_flags |= USBSER_FL_TX_STOPPED;
   2940 
   2941 		mutex_exit(&pp->port_mutex);
   2942 		USBSER_DS_STOP(pp, DS_TX);
   2943 		mutex_enter(&pp->port_mutex);
   2944 
   2945 		usbser_release_port_act(pp, USBSER_ACT_TX);
   2946 		usbser_release_port_act(pp, USBSER_ACT_CTL);
   2947 	}
   2948 	freemsg(mp);
   2949 }
   2950 
   2951 
   2952 static void
   2953 usbser_start(usbser_port_t *pp, mblk_t *mp)
   2954 {
   2955 	usbser_st_mstart++;
   2956 	if (pp->port_flags & USBSER_FL_TX_STOPPED) {
   2957 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
   2958 		pp->port_flags &= ~USBSER_FL_TX_STOPPED;
   2959 
   2960 		mutex_exit(&pp->port_mutex);
   2961 		USBSER_DS_START(pp, DS_TX);
   2962 		mutex_enter(&pp->port_mutex);
   2963 		usbser_release_port_act(pp, USBSER_ACT_CTL);
   2964 	}
   2965 	freemsg(mp);
   2966 }
   2967 
   2968 
   2969 static void
   2970 usbser_stopi(usbser_port_t *pp, mblk_t *mp)
   2971 {
   2972 	usbser_st_mstopi++;
   2973 	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
   2974 	pp->port_flowc = pp->port_ttycommon.t_stopc;
   2975 	usbser_inbound_flow_ctl(pp);
   2976 	usbser_release_port_act(pp, USBSER_ACT_CTL);
   2977 	freemsg(mp);
   2978 }
   2979 
   2980 static void
   2981 usbser_starti(usbser_port_t *pp, mblk_t *mp)
   2982 {
   2983 	usbser_st_mstarti++;
   2984 	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
   2985 	pp->port_flowc = pp->port_ttycommon.t_startc;
   2986 	usbser_inbound_flow_ctl(pp);
   2987 	usbser_release_port_act(pp, USBSER_ACT_CTL);
   2988 	freemsg(mp);
   2989 }
   2990 
   2991 /*
   2992  * process M_FLUSH message
   2993  */
   2994 static void
   2995 usbser_flush(usbser_port_t *pp, mblk_t *mp)
   2996 {
   2997 	queue_t	*q = pp->port_ttycommon.t_writeq;
   2998 
   2999 	if (*mp->b_rptr & FLUSHW) {
   3000 		mutex_exit(&pp->port_mutex);
   3001 		(void) USBSER_DS_FIFO_FLUSH(pp, DS_TX);	/* flush FIFO buffers */
   3002 		flushq(q, FLUSHDATA);			/* flush write queue */
   3003 		mutex_enter(&pp->port_mutex);
   3004 
   3005 		usbser_release_port_act(pp, USBSER_ACT_TX);
   3006 
   3007 		*mp->b_rptr &= ~FLUSHW;
   3008 	}
   3009 	if (*mp->b_rptr & FLUSHR) {
   3010 		/*
   3011 		 * flush FIFO buffers
   3012 		 */
   3013 		mutex_exit(&pp->port_mutex);
   3014 		(void) USBSER_DS_FIFO_FLUSH(pp, DS_RX);
   3015 		flushq(RD(q), FLUSHDATA);
   3016 		qreply(q, mp);
   3017 		mutex_enter(&pp->port_mutex);
   3018 	} else {
   3019 		freemsg(mp);
   3020 	}
   3021 }
   3022 
   3023 /*
   3024  * process M_BREAK message
   3025  */
   3026 static void
   3027 usbser_break(usbser_port_t *pp, mblk_t *mp)
   3028 {
   3029 	int	rval;
   3030 
   3031 	/*
   3032 	 * set the break and arrange for usbser_restart() to be called in 1/4 s
   3033 	 */
   3034 	mutex_exit(&pp->port_mutex);
   3035 	rval = USBSER_DS_BREAK_CTL(pp, DS_ON);
   3036 	mutex_enter(&pp->port_mutex);
   3037 
   3038 	if (rval == USB_SUCCESS) {
   3039 		pp->port_act |= USBSER_ACT_BREAK;
   3040 		pp->port_delay_id = timeout(usbser_restart, pp,
   3041 		    drv_usectohz(250000));
   3042 	}
   3043 	freemsg(mp);
   3044 }
   3045 
   3046 
   3047 /*
   3048  * process M_DELAY message
   3049  */
   3050 static void
   3051 usbser_delay(usbser_port_t *pp, mblk_t *mp)
   3052 {
   3053 	/*
   3054 	 * arrange for usbser_restart() to be called when the delay expires
   3055 	 */
   3056 	pp->port_act |= USBSER_ACT_DELAY;
   3057 	pp->port_delay_id = timeout(usbser_restart, pp,
   3058 	    (clock_t)(*(uchar_t *)mp->b_rptr + 6));
   3059 	freemsg(mp);
   3060 }
   3061 
   3062 
   3063 /*
   3064  * restart output on a line after a delay or break timer expired
   3065  */
   3066 static void
   3067 usbser_restart(void *arg)
   3068 {
   3069 	usbser_port_t	*pp = (usbser_port_t *)arg;
   3070 
   3071 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_restart");
   3072 
   3073 	mutex_enter(&pp->port_mutex);
   3074 	/* if cancelled, return immediately */
   3075 	if (pp->port_delay_id == 0) {
   3076 		mutex_exit(&pp->port_mutex);
   3077 
   3078 		return;
   3079 	}
   3080 	pp->port_delay_id = 0;
   3081 
   3082 	/* clear break if necessary */
   3083 	if (pp->port_act & USBSER_ACT_BREAK) {
   3084 		mutex_exit(&pp->port_mutex);
   3085 		(void) USBSER_DS_BREAK_CTL(pp, DS_OFF);
   3086 		mutex_enter(&pp->port_mutex);
   3087 	}
   3088 
   3089 	usbser_release_port_act(pp, USBSER_ACT_BREAK | USBSER_ACT_DELAY);
   3090 
   3091 	/* wake wq thread to resume message processing */
   3092 	usbser_thr_wake(&pp->port_wq_thread);
   3093 	mutex_exit(&pp->port_mutex);
   3094 }
   3095 
   3096 
   3097 /*
   3098  * program port hardware with the chosen parameters
   3099  * most of the operation is based on the values of 'c_iflag' and 'c_cflag'
   3100  */
   3101 static int
   3102 usbser_port_program(usbser_port_t *pp)
   3103 {
   3104 	tty_common_t		*tp = &pp->port_ttycommon;
   3105 	int			baudrate;
   3106 	int			c_flag;
   3107 	ds_port_param_entry_t	pe[6];
   3108 	ds_port_params_t	params;
   3109 	int			flow_ctl, ctl_val;
   3110 	int			err = 0;
   3111 
   3112 	baudrate = tp->t_cflag & CBAUD;
   3113 	if (tp->t_cflag & CBAUDEXT) {
   3114 		baudrate += 16;
   3115 	}
   3116 
   3117 	/*
   3118 	 * set input speed same as output, as split speed not supported
   3119 	 */
   3120 	if (tp->t_cflag & (CIBAUD|CIBAUDEXT)) {
   3121 		tp->t_cflag &= ~(CIBAUD);
   3122 		if (baudrate > CBAUD) {
   3123 			tp->t_cflag |= CIBAUDEXT;
   3124 			tp->t_cflag |=
   3125 			    (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD);
   3126 		} else {
   3127 			tp->t_cflag &= ~CIBAUDEXT;
   3128 			tp->t_cflag |= ((baudrate << IBSHIFT) & CIBAUD);
   3129 		}
   3130 	}
   3131 
   3132 	c_flag = tp->t_cflag;
   3133 
   3134 	/*
   3135 	 * flow control
   3136 	 */
   3137 	flow_ctl = tp->t_iflag & (IXON | IXANY | IXOFF);
   3138 	if (c_flag & CRTSCTS) {
   3139 		flow_ctl |= CTSXON;
   3140 	}
   3141 	if (c_flag & CRTSXOFF) {
   3142 		flow_ctl |= RTSXOFF;
   3143 	}
   3144 
   3145 	/*
   3146 	 * fill in port parameters we need to set:
   3147 	 *
   3148 	 * baud rate
   3149 	 */
   3150 	pe[0].param = DS_PARAM_BAUD;
   3151 	pe[0].val.ui = baudrate;
   3152 
   3153 	/* stop bits */
   3154 	pe[1].param = DS_PARAM_STOPB;
   3155 	pe[1].val.ui = c_flag & CSTOPB;
   3156 
   3157 	/* parity */
   3158 	pe[2].param = DS_PARAM_PARITY;
   3159 	pe[2].val.ui = c_flag & (PARENB | PARODD);
   3160 
   3161 	/* char size */
   3162 	pe[3].param = DS_PARAM_CHARSZ;
   3163 	pe[3].val.ui = c_flag & CSIZE;
   3164 
   3165 	/* start & stop chars */
   3166 	pe[4].param = DS_PARAM_XON_XOFF;
   3167 	pe[4].val.uc[0] = tp->t_startc;
   3168 	pe[4].val.uc[1] = tp->t_stopc;
   3169 
   3170 	/* flow control */
   3171 	pe[5].param = DS_PARAM_FLOW_CTL;
   3172 	pe[5].val.ui = flow_ctl;
   3173 
   3174 	params.tp_entries = &pe[0];
   3175 	params.tp_cnt = 6;
   3176 
   3177 	/* control signals */
   3178 	ctl_val = TIOCM_DTR | TIOCM_RTS;
   3179 	if (baudrate == 0) {
   3180 		ctl_val &= ~TIOCM_DTR;	/* zero baudrate means drop DTR */
   3181 	}
   3182 	if (pp->port_flags & USBSER_FL_RX_STOPPED) {
   3183 		ctl_val &= ~TIOCM_RTS;
   3184 	}
   3185 
   3186 	/* submit */
   3187 	mutex_exit(&pp->port_mutex);
   3188 	err = USBSER_DS_SET_PORT_PARAMS(pp, &params);
   3189 	if (err != USB_SUCCESS) {
   3190 		mutex_enter(&pp->port_mutex);
   3191 
   3192 		return (EINVAL);
   3193 	}
   3194 
   3195 	err = USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR | TIOCM_RTS, ctl_val);
   3196 	mutex_enter(&pp->port_mutex);
   3197 
   3198 	return ((err == USB_SUCCESS) ? 0 : EIO);
   3199 }
   3200 
   3201 
   3202 /*
   3203  * check if any inbound flow control action needed
   3204  */
   3205 static void
   3206 usbser_inbound_flow_ctl(usbser_port_t *pp)
   3207 {
   3208 	tcflag_t	need_hw;
   3209 	int		rts;
   3210 	char		c = pp->port_flowc;
   3211 	mblk_t		*mp = NULL;
   3212 
   3213 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
   3214 	    "usbser_inbound_flow_ctl: c=%x cflag=%x port_flags=%x",
   3215 	    c, pp->port_ttycommon.t_cflag, pp->port_flags);
   3216 
   3217 	if (c == '\0') {
   3218 
   3219 		return;
   3220 	}
   3221 	pp->port_flowc = '\0';
   3222 
   3223 	/*
   3224 	 * if inbound hardware flow control enabled, we need to frob RTS
   3225 	 */
   3226 	need_hw = (pp->port_ttycommon.t_cflag & CRTSXOFF);
   3227 	if (c == pp->port_ttycommon.t_startc) {
   3228 		rts = TIOCM_RTS;
   3229 		pp->port_flags &= ~USBSER_FL_RX_STOPPED;
   3230 	} else {
   3231 		rts = 0;
   3232 		pp->port_flags |= USBSER_FL_RX_STOPPED;
   3233 	}
   3234 
   3235 	/*
   3236 	 * if character flow control active, transmit a start or stop char,
   3237 	 */
   3238 	if (pp->port_ttycommon.t_iflag & IXOFF) {
   3239 		if ((mp = allocb(1, BPRI_LO)) == NULL) {
   3240 			USB_DPRINTF_L2(DPRINT_WQ, pp->port_lh,
   3241 			    "usbser_inbound_flow_ctl: allocb failed");
   3242 		} else {
   3243 			*mp->b_wptr++ = c;
   3244 			pp->port_flags |= USBSER_ACT_TX;
   3245 		}
   3246 	}
   3247 
   3248 	mutex_exit(&pp->port_mutex);
   3249 	if (need_hw) {
   3250 		(void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_RTS, rts);
   3251 	}
   3252 	if (mp) {
   3253 		(void) USBSER_DS_TX(pp, mp);
   3254 	}
   3255 	mutex_enter(&pp->port_mutex);
   3256 }
   3257 
   3258 
   3259 /*
   3260  * misc
   3261  * ----
   3262  *
   3263  *
   3264  * returns != 0 if device is online, 0 otherwise
   3265  */
   3266 static int
   3267 usbser_dev_is_online(usbser_state_t *usp)
   3268 {
   3269 	int	rval;
   3270 
   3271 	mutex_enter(&usp->us_mutex);
   3272 	rval = (usp->us_dev_state == USB_DEV_ONLINE);
   3273 	mutex_exit(&usp->us_mutex);
   3274 
   3275 	return (rval);
   3276 }
   3277 
   3278 /*
   3279  * serialize port activities defined by 'act' mask
   3280  */
   3281 static void
   3282 usbser_serialize_port_act(usbser_port_t *pp, int act)
   3283 {
   3284 	while (pp->port_act & act)
   3285 		cv_wait(&pp->port_act_cv, &pp->port_mutex);
   3286 	pp->port_act |= act;
   3287 }
   3288 
   3289 
   3290 /*
   3291  * indicate that port activity is finished
   3292  */
   3293 static void
   3294 usbser_release_port_act(usbser_port_t *pp, int act)
   3295 {
   3296 	pp->port_act &= ~act;
   3297 	cv_broadcast(&pp->port_act_cv);
   3298 }
   3299 
   3300 
   3301 /*
   3302  * message type to string and back conversion.
   3303  *
   3304  * pardon breaks on the same line, but as long as cstyle doesn't
   3305  * complain, I'd like to keep this form for trivial cases like this.
   3306  * associative arrays in the kernel, anyone?
   3307  */
   3308 static char *
   3309 usbser_msgtype2str(int type)
   3310 {
   3311 	char	*str;
   3312 
   3313 	switch (type) {
   3314 	case M_STOP:	str = "M_STOP";		break;
   3315 	case M_START:	str = "M_START";	break;
   3316 	case M_STOPI:	str = "M_STOPI";	break;
   3317 	case M_STARTI:	str = "M_STARTI";	break;
   3318 	case M_DATA:	str = "M_DATA";		break;
   3319 	case M_DELAY:	str = "M_DELAY";	break;
   3320 	case M_BREAK:	str = "M_BREAK";	break;
   3321 	case M_IOCTL:	str = "M_IOCTL";	break;
   3322 	case M_IOCDATA:	str = "M_IOCDATA";	break;
   3323 	case M_FLUSH:	str = "M_FLUSH";	break;
   3324 	case M_CTL:	str = "M_CTL";		break;
   3325 	case M_READ:	str = "M_READ";		break;
   3326 	default:	str = "unknown";	break;
   3327 	}
   3328 
   3329 	return (str);
   3330 }
   3331 
   3332 
   3333 static char *
   3334 usbser_ioctl2str(int ioctl)
   3335 {
   3336 	char	*str;
   3337 
   3338 	switch (ioctl) {
   3339 	case TCGETA:	str = "TCGETA";		break;
   3340 	case TCSETA:	str = "TCSETA";		break;
   3341 	case TCSETAF:	str = "TCSETAF";	break;
   3342 	case TCSETAW:	str = "TCSETAW";	break;
   3343 	case TCSBRK:	str = "TCSBRK";		break;
   3344 	case TCXONC:	str = "TCXONC";		break;
   3345 	case TCFLSH:	str = "TCFLSH";		break;
   3346 	case TCGETS:	str = "TCGETS";		break;
   3347 	case TCSETS:	str = "TCSETS";		break;
   3348 	case TCSETSF:	str = "TCSETSF";	break;
   3349 	case TCSETSW:	str = "TCSETSW";	break;
   3350 	case TIOCSBRK:	str = "TIOCSBRK";	break;
   3351 	case TIOCCBRK:	str = "TIOCCBRK";	break;
   3352 	case TIOCMSET:	str = "TIOCMSET";	break;
   3353 	case TIOCMBIS:	str = "TIOCMBIS";	break;
   3354 	case TIOCMBIC:	str = "TIOCMBIC";	break;
   3355 	case TIOCMGET:	str = "TIOCMGET";	break;
   3356 	case TIOCSILOOP: str = "TIOCSILOOP";	break;
   3357 	case TIOCCILOOP: str = "TIOCCILOOP";	break;
   3358 	case TCGETX:	str = "TCGETX";		break;
   3359 	case TCSETX:	str = "TCGETX";		break;
   3360 	case TCSETXW:	str = "TCGETX";		break;
   3361 	case TCSETXF:	str = "TCGETX";		break;
   3362 	default:	str = "unknown";	break;
   3363 	}
   3364 
   3365 	return (str);
   3366 }
   3367 
   3368 /*
   3369  * Polled IO support
   3370  */
   3371 
   3372 /* called once	by consconfig() when polledio is opened */
   3373 static int
   3374 usbser_polledio_init(usbser_port_t *pp)
   3375 {
   3376 	int err;
   3377 	usb_pipe_handle_t hdl;
   3378 	ds_ops_t *ds_ops = pp->port_ds_ops;
   3379 
   3380 	/* only one serial line console supported */
   3381 	if (console_input != NULL)
   3382 		return (USB_FAILURE);
   3383 
   3384 	/* check if underlying driver supports polled io */
   3385 	if (ds_ops->ds_version < DS_OPS_VERSION_V1 ||
   3386 	    ds_ops->ds_out_pipe == NULL || ds_ops->ds_in_pipe == NULL)
   3387 		return (USB_FAILURE);
   3388 
   3389 	/* init polled input pipe */
   3390 	hdl = ds_ops->ds_in_pipe(pp->port_ds_hdl, pp->port_num);
   3391 	err = usb_console_input_init(pp->port_usp->us_dip, hdl,
   3392 	    &console_input_buf, &console_input);
   3393 	if (err)
   3394 		return (USB_FAILURE);
   3395 
   3396 	/* init polled output pipe */
   3397 	hdl = ds_ops->ds_out_pipe(pp->port_ds_hdl, pp->port_num);
   3398 	err = usb_console_output_init(pp->port_usp->us_dip, hdl,
   3399 	    &console_output);
   3400 	if (err) {
   3401 		(void) usb_console_input_fini(console_input);
   3402 		console_input = NULL;
   3403 		return (USB_FAILURE);
   3404 	}
   3405 
   3406 	return (USB_SUCCESS);
   3407 }
   3408 
   3409 /* called once	by consconfig() when polledio is closed */
   3410 /*ARGSUSED*/
   3411 static void usbser_polledio_fini(usbser_port_t *pp)
   3412 {
   3413 	/* Since we can't move the console, there is nothing to do. */
   3414 }
   3415 
   3416 /*ARGSUSED*/
   3417 static void
   3418 usbser_polledio_enter(cons_polledio_arg_t arg)
   3419 {
   3420 	(void) usb_console_input_enter(console_input);
   3421 	(void) usb_console_output_enter(console_output);
   3422 }
   3423 
   3424 /*ARGSUSED*/
   3425 static void
   3426 usbser_polledio_exit(cons_polledio_arg_t arg)
   3427 {
   3428 	(void) usb_console_output_exit(console_output);
   3429 	(void) usb_console_input_exit(console_input);
   3430 }
   3431 
   3432 /*ARGSUSED*/
   3433 static void
   3434 usbser_putchar(cons_polledio_arg_t arg, uchar_t c)
   3435 {
   3436 	static uchar_t cr[2] = {'\r', '\n'};
   3437 	uint_t nout;
   3438 
   3439 	if (c == '\n')
   3440 		(void) usb_console_write(console_output, cr, 2, &nout);
   3441 	else
   3442 		(void) usb_console_write(console_output, &c, 1, &nout);
   3443 }
   3444 
   3445 /*ARGSUSED*/
   3446 static int
   3447 usbser_getchar(cons_polledio_arg_t arg)
   3448 {
   3449 	while (!usbser_ischar(arg))
   3450 		;
   3451 
   3452 	return (*console_input_start++);
   3453 }
   3454 
   3455 /*ARGSUSED*/
   3456 static boolean_t
   3457 usbser_ischar(cons_polledio_arg_t arg)
   3458 {
   3459 	uint_t num_bytes;
   3460 
   3461 	if (console_input_start < console_input_end)
   3462 		return (B_TRUE);
   3463 
   3464 	if (usb_console_read(console_input, &num_bytes) != USB_SUCCESS)
   3465 		return (B_FALSE);
   3466 
   3467 	console_input_start = console_input_buf;
   3468 	console_input_end = console_input_buf + num_bytes;
   3469 
   3470 	return (num_bytes != 0);
   3471 }
   3472