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