xref: /illumos-gate/usr/src/uts/common/io/usb/clients/usbser/usbser.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
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 2008 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 	if (online && USBSER_PORT_ACCESS_OK(pp) && !USBSER_PORT_IS_BUSY(pp)) {
2046 		/*
2047 		 * wake wq thread for further data/ioctl processing
2048 		 */
2049 		usbser_thr_wake(&pp->port_wq_thread);
2050 	}
2051 	mutex_exit(&pp->port_mutex);
2052 }
2053 
2054 
2055 /*
2056  * receive callback
2057  *
2058  * invoked by DSD when there is more data for us to pick
2059  */
2060 static void
2061 usbser_rx_cb(caddr_t arg)
2062 {
2063 	usbser_port_t	*pp = (usbser_port_t *)arg;
2064 	queue_t		*rq, *wq;
2065 	mblk_t		*mp;		/* current mblk */
2066 	mblk_t		*data, *data_tail; /* M_DATA mblk list and its tail */
2067 	mblk_t		*emp;		/* error (M_BREAK) mblk */
2068 
2069 	USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh, "usbser_rx_cb");
2070 
2071 	if (!usbser_dev_is_online(pp->port_usp)) {
2072 
2073 		return;
2074 	}
2075 
2076 	/* get data from DSD */
2077 	if ((mp = USBSER_DS_RX(pp)) == NULL) {
2078 
2079 		return;
2080 	}
2081 
2082 	mutex_enter(&pp->port_mutex);
2083 	if ((!USBSER_PORT_ACCESS_OK(pp)) ||
2084 	    ((pp->port_ttycommon.t_cflag & CREAD) == 0)) {
2085 		freemsg(mp);
2086 		mutex_exit(&pp->port_mutex);
2087 		USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
2088 		    "usbser_rx_cb: access not ok or receiver disabled");
2089 
2090 		return;
2091 	}
2092 
2093 	usbser_serialize_port_act(pp, USBSER_ACT_RX);
2094 
2095 	rq = pp->port_ttycommon.t_readq;
2096 	wq = pp->port_ttycommon.t_writeq;
2097 	mutex_exit(&pp->port_mutex);
2098 
2099 	/*
2100 	 * DSD data is a b_cont-linked list of M_DATA and M_BREAK blocks.
2101 	 * M_DATA is correctly received data.
2102 	 * M_BREAK is a character with either framing or parity error.
2103 	 *
2104 	 * this loop runs through the list of mblks. when it meets an M_BREAK,
2105 	 * it sends all leading M_DATA's in one shot, then sends M_BREAK.
2106 	 * in the trivial case when list contains only M_DATA's, the loop
2107 	 * does nothing but set data variable.
2108 	 */
2109 	data = data_tail = NULL;
2110 	while (mp) {
2111 		/*
2112 		 * skip data until we meet M_BREAK or end of list
2113 		 */
2114 		if (DB_TYPE(mp) == M_DATA) {
2115 			if (data == NULL) {
2116 				data = mp;
2117 			}
2118 			data_tail = mp;
2119 			mp = mp->b_cont;
2120 
2121 			continue;
2122 		}
2123 
2124 		/* detach data list from mp */
2125 		if (data_tail) {
2126 			data_tail->b_cont = NULL;
2127 		}
2128 		/* detach emp from the list */
2129 		emp = mp;
2130 		mp = mp->b_cont;
2131 		emp->b_cont = NULL;
2132 
2133 		/* DSD shouldn't send anything but M_DATA or M_BREAK */
2134 		if ((DB_TYPE(emp) != M_BREAK) || (MBLKL(emp) != 2)) {
2135 			freemsg(emp);
2136 			USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
2137 			    "usbser_rx_cb: bad message");
2138 
2139 			continue;
2140 		}
2141 
2142 		/*
2143 		 * first tweak and send M_DATA's
2144 		 */
2145 		if (data) {
2146 			usbser_rx_massage_data(pp, data);
2147 			usbser_rx_cb_put(pp, rq, wq, data);
2148 			data = data_tail = NULL;
2149 		}
2150 
2151 		/*
2152 		 * now tweak and send M_BREAK
2153 		 */
2154 		mutex_enter(&pp->port_mutex);
2155 		usbser_rx_massage_mbreak(pp, emp);
2156 		mutex_exit(&pp->port_mutex);
2157 		usbser_rx_cb_put(pp, rq, wq, emp);
2158 	}
2159 
2160 	/* send the rest of the data, if any */
2161 	if (data) {
2162 		usbser_rx_massage_data(pp, data);
2163 		usbser_rx_cb_put(pp, rq, wq, data);
2164 	}
2165 
2166 	mutex_enter(&pp->port_mutex);
2167 	usbser_release_port_act(pp, USBSER_ACT_RX);
2168 	mutex_exit(&pp->port_mutex);
2169 }
2170 
2171 /*
2172  * the joys of termio -- this is to accomodate Unix98 assertion:
2173  *
2174  *   If PARENB is supported and is set, when PARMRK is set, and CSIZE is
2175  *   set to CS8, and IGNPAR is clear, and ISTRIP is clear, a valid
2176  *   character of '\377' is read as '\377', '\377'.
2177  *
2178  *   Posix Ref: Assertion 7.1.2.2-16(C)
2179  *
2180  * this requires the driver to scan every incoming valid character
2181  */
2182 static void
2183 usbser_rx_massage_data(usbser_port_t *pp, mblk_t *mp)
2184 {
2185 	tty_common_t	*tp = &pp->port_ttycommon;
2186 	uchar_t		*p;
2187 	mblk_t		*newmp;
2188 	int		tailsz;
2189 
2190 	/* avoid scanning if possible */
2191 	mutex_enter(&pp->port_mutex);
2192 	if (!((tp->t_cflag & PARENB) && (tp->t_iflag & PARMRK) &&
2193 	    ((tp->t_cflag & CSIZE) == CS8) &&
2194 	    ((tp->t_iflag & (IGNPAR|ISTRIP)) == 0))) {
2195 		mutex_exit(&pp->port_mutex);
2196 
2197 		return;
2198 	}
2199 	mutex_exit(&pp->port_mutex);
2200 
2201 	while (mp) {
2202 		for (p = mp->b_rptr; p < mp->b_wptr; ) {
2203 			if (*p++ != 0377) {
2204 
2205 				continue;
2206 			}
2207 			USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
2208 			    "usbser_rx_massage_data: mp=%p off=%ld(%ld)",
2209 			    (void *)mp, _PTRDIFF(p,  mp->b_rptr) - 1,
2210 			    (long)MBLKL(mp));
2211 
2212 			/*
2213 			 * insert another 0377 after this one. all data after
2214 			 * the original 0377 have to be copied to the new mblk
2215 			 */
2216 			tailsz = _PTRDIFF(mp->b_wptr, p);
2217 			if ((newmp = allocb(tailsz + 1, BPRI_HI)) == NULL) {
2218 				USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
2219 				    "usbser_rx_massage_data: allocb failed");
2220 
2221 				continue;
2222 			}
2223 
2224 			/* fill in the new mblk */
2225 			*newmp->b_wptr++ = 0377;
2226 			if (tailsz > 0) {
2227 				bcopy(p, newmp->b_wptr, tailsz);
2228 				newmp->b_wptr += tailsz;
2229 			}
2230 			/* shrink the original mblk */
2231 			mp->b_wptr = p;
2232 
2233 			newmp->b_cont = mp->b_cont;
2234 			mp->b_cont = newmp;
2235 			p = newmp->b_rptr + 1;
2236 			mp = newmp;
2237 		}
2238 		mp = mp->b_cont;
2239 	}
2240 }
2241 
2242 /*
2243  * more joys of termio
2244  */
2245 static void
2246 usbser_rx_massage_mbreak(usbser_port_t *pp, mblk_t *mp)
2247 {
2248 	tty_common_t	*tp = &pp->port_ttycommon;
2249 	uchar_t		err, c;
2250 
2251 	err = *mp->b_rptr;
2252 	c = *(mp->b_rptr + 1);
2253 
2254 	if ((err & (DS_FRAMING_ERR | DS_BREAK_ERR)) && (c == 0)) {
2255 		/* break */
2256 		mp->b_rptr += 2;
2257 	} else if (!(tp->t_iflag & INPCK) && (err & (DS_PARITY_ERR))) {
2258 		/* Posix Ref: Assertion 7.1.2.2-20(C) */
2259 		mp->b_rptr++;
2260 		DB_TYPE(mp) = M_DATA;
2261 	} else {
2262 		/* for ldterm to handle */
2263 		mp->b_rptr++;
2264 	}
2265 
2266 	USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
2267 	    "usbser_rx_massage_mbreak: type=%x len=%ld [0]=0%o",
2268 	    DB_TYPE(mp), (long)MBLKL(mp), (MBLKL(mp) > 0) ? *mp->b_rptr : 45);
2269 }
2270 
2271 
2272 /*
2273  * in rx callback, try to send an mblk upstream
2274  */
2275 static void
2276 usbser_rx_cb_put(usbser_port_t *pp, queue_t *rq, queue_t *wq, mblk_t *mp)
2277 {
2278 	if (canputnext(rq)) {
2279 		putnext(rq, mp);
2280 	} else if (canput(rq) && putq(rq, mp)) {
2281 		/*
2282 		 * full queue indicates the need for inbound flow control
2283 		 */
2284 		(void) putctl(wq, M_STOPI);
2285 		usbser_st_put_stopi++;
2286 
2287 		USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
2288 		    "usbser_rx_cb: cannot putnext, flow ctl");
2289 	} else {
2290 		freemsg(mp);
2291 		usbser_st_rx_data_loss++;
2292 		(void) putctl(wq, M_STOPI);
2293 		usbser_st_put_stopi++;
2294 
2295 		USB_DPRINTF_L1(DPRINT_RX_CB, pp->port_lh,
2296 		    "input overrun");
2297 	}
2298 }
2299 
2300 
2301 /*
2302  * modem status change callback
2303  *
2304  * each time external status lines are changed, DSD calls this routine
2305  */
2306 static void
2307 usbser_status_cb(caddr_t arg)
2308 {
2309 	usbser_port_t	*pp = (usbser_port_t *)arg;
2310 
2311 	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_cb");
2312 
2313 	if (!usbser_dev_is_online(pp->port_usp)) {
2314 
2315 		return;
2316 	}
2317 
2318 	/*
2319 	 * actual processing will be done in usbser_status_proc_cb()
2320 	 * running in wq thread
2321 	 */
2322 	mutex_enter(&pp->port_mutex);
2323 	if (USBSER_PORT_ACCESS_OK(pp) || USBSER_IS_OPENING(pp)) {
2324 		pp->port_flags |= USBSER_FL_STATUS_CB;
2325 		usbser_thr_wake(&pp->port_wq_thread);
2326 	}
2327 	mutex_exit(&pp->port_mutex);
2328 }
2329 
2330 
2331 /*
2332  * modem status change
2333  */
2334 static void
2335 usbser_status_proc_cb(usbser_port_t *pp)
2336 {
2337 	tty_common_t	*tp = &pp->port_ttycommon;
2338 	queue_t		*rq, *wq;
2339 	int		status;
2340 	int		drop_dtr = 0;
2341 	int		rq_msg = 0, wq_msg = 0;
2342 
2343 	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_proc_cb");
2344 
2345 	pp->port_flags &= ~USBSER_FL_STATUS_CB;
2346 
2347 	mutex_exit(&pp->port_mutex);
2348 	if (!usbser_dev_is_online(pp->port_usp)) {
2349 		mutex_enter(&pp->port_mutex);
2350 
2351 		return;
2352 	}
2353 
2354 	/* get modem status */
2355 	if (USBSER_DS_GET_MODEM_CTL(pp, -1, &status) != USB_SUCCESS) {
2356 		mutex_enter(&pp->port_mutex);
2357 
2358 		return;
2359 	}
2360 
2361 	mutex_enter(&pp->port_mutex);
2362 	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2363 
2364 	rq = pp->port_ttycommon.t_readq;
2365 	wq = pp->port_ttycommon.t_writeq;
2366 
2367 	/*
2368 	 * outbound flow control
2369 	 */
2370 	if (tp->t_cflag & CRTSCTS) {
2371 		if (!(status & TIOCM_CTS)) {
2372 			/*
2373 			 * CTS dropped, stop xmit
2374 			 */
2375 			if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
2376 				wq_msg = M_STOP;
2377 			}
2378 		} else if (pp->port_flags & USBSER_FL_TX_STOPPED) {
2379 			/*
2380 			 * CTS raised, resume xmit
2381 			 */
2382 			wq_msg = M_START;
2383 		}
2384 	}
2385 
2386 	/*
2387 	 * check carrier
2388 	 */
2389 	if ((status & TIOCM_CD) || (tp->t_flags & TS_SOFTCAR)) {
2390 		/*
2391 		 * carrier present
2392 		 */
2393 		if ((pp->port_flags & USBSER_FL_CARR_ON) == 0) {
2394 			pp->port_flags |= USBSER_FL_CARR_ON;
2395 
2396 			rq_msg = M_UNHANGUP;
2397 			/*
2398 			 * wake open
2399 			 */
2400 			if (pp->port_flags & USBSER_FL_WOPEN) {
2401 				cv_broadcast(&pp->port_car_cv);
2402 			}
2403 
2404 			USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2405 			    "usbser_status_cb: carr on");
2406 		}
2407 	} else if (pp->port_flags & USBSER_FL_CARR_ON) {
2408 		pp->port_flags &= ~USBSER_FL_CARR_ON;
2409 		/*
2410 		 * carrier went away: if not local line, drop DTR
2411 		 */
2412 		if (!(tp->t_cflag & CLOCAL)) {
2413 			drop_dtr = 1;
2414 			rq_msg = M_HANGUP;
2415 		}
2416 		if ((pp->port_flags & USBSER_FL_TX_STOPPED) && (wq_msg == 0)) {
2417 			wq_msg = M_START;
2418 		}
2419 
2420 		USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2421 		    "usbser_status_cb: carr off");
2422 	}
2423 	mutex_exit(&pp->port_mutex);
2424 
2425 	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2426 	    "usbser_status_cb: rq_msg=%d wq_msg=%d", rq_msg, wq_msg);
2427 
2428 	/*
2429 	 * commit postponed actions now
2430 	 * do so only if port is fully open (queues are enabled)
2431 	 */
2432 	if (rq) {
2433 		if (rq_msg) {
2434 			(void) putnextctl(rq, rq_msg);
2435 		}
2436 		if (drop_dtr) {
2437 			(void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR, 0);
2438 		}
2439 		if (wq_msg) {
2440 			(void) putctl(wq, wq_msg);
2441 		}
2442 	}
2443 
2444 	mutex_enter(&pp->port_mutex);
2445 	usbser_release_port_act(pp, USBSER_ACT_CTL);
2446 }
2447 
2448 
2449 /*
2450  * serial support
2451  * --------------
2452  *
2453  *
2454  * this routine is run by wq thread every time it's woken,
2455  * i.e. when the queue contains messages to process
2456  */
2457 static void
2458 usbser_wmsg(usbser_port_t *pp)
2459 {
2460 	queue_t		*q = pp->port_ttycommon.t_writeq;
2461 	mblk_t		*mp;
2462 	int		msgtype;
2463 
2464 	ASSERT(mutex_owned(&pp->port_mutex));
2465 
2466 	if (q == NULL) {
2467 		USB_DPRINTF_L3(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=NULL");
2468 
2469 		return;
2470 	}
2471 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=%p act=%x 0x%x",
2472 	    (void *)q, pp->port_act, q->q_first ? DB_TYPE(q->q_first) : 0xff);
2473 
2474 	while ((mp = getq(q)) != NULL) {
2475 		msgtype = DB_TYPE(mp);
2476 		USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: "
2477 		    "type=%s (0x%x)", usbser_msgtype2str(msgtype), msgtype);
2478 
2479 		switch (msgtype) {
2480 		/*
2481 		 * high-priority messages
2482 		 */
2483 		case M_STOP:
2484 			usbser_stop(pp, mp);
2485 
2486 			break;
2487 		case M_START:
2488 			usbser_start(pp, mp);
2489 
2490 			break;
2491 		case M_STOPI:
2492 			usbser_stopi(pp, mp);
2493 
2494 			break;
2495 		case M_STARTI:
2496 			usbser_starti(pp, mp);
2497 
2498 			break;
2499 		case M_IOCDATA:
2500 			usbser_iocdata(pp, mp);
2501 
2502 			break;
2503 		case M_FLUSH:
2504 			usbser_flush(pp, mp);
2505 
2506 			break;
2507 		/*
2508 		 * normal-priority messages
2509 		 */
2510 		case M_BREAK:
2511 			usbser_break(pp, mp);
2512 
2513 			break;
2514 		case M_DELAY:
2515 			usbser_delay(pp, mp);
2516 
2517 			break;
2518 		case M_DATA:
2519 			if (usbser_data(pp, mp) != USB_SUCCESS) {
2520 				(void) putbq(q, mp);
2521 
2522 				return;
2523 			}
2524 
2525 			break;
2526 		case M_IOCTL:
2527 			if (usbser_ioctl(pp, mp) != USB_SUCCESS) {
2528 				(void) putbq(q, mp);
2529 
2530 				return;
2531 			}
2532 
2533 			break;
2534 		default:
2535 			freemsg(mp);
2536 
2537 			break;
2538 		}
2539 	}
2540 }
2541 
2542 
2543 /*
2544  * process M_DATA message
2545  */
2546 static int
2547 usbser_data(usbser_port_t *pp, mblk_t *mp)
2548 {
2549 	/* put off until current transfer ends or delay is over */
2550 	if ((pp->port_act & USBSER_ACT_TX) ||
2551 	    (pp->port_act & USBSER_ACT_DELAY)) {
2552 
2553 		return (USB_FAILURE);
2554 	}
2555 	if (MBLKL(mp) <= 0) {
2556 		freemsg(mp);
2557 
2558 		return (USB_SUCCESS);
2559 	}
2560 
2561 	pp->port_act |= USBSER_ACT_TX;
2562 	pp->port_wq_data_cnt -= msgdsize(mp);
2563 
2564 	mutex_exit(&pp->port_mutex);
2565 	/* DSD is required to accept data block in any case */
2566 	(void) USBSER_DS_TX(pp, mp);
2567 	mutex_enter(&pp->port_mutex);
2568 
2569 	return (USB_SUCCESS);
2570 }
2571 
2572 
2573 /*
2574  * process an M_IOCTL message
2575  */
2576 static int
2577 usbser_ioctl(usbser_port_t *pp, mblk_t *mp)
2578 {
2579 	tty_common_t	*tp = &pp->port_ttycommon;
2580 	queue_t		*q = tp->t_writeq;
2581 	struct iocblk	*iocp;
2582 	int		cmd;
2583 	mblk_t		*datamp;
2584 	int		error = 0, rval;
2585 	int		val;
2586 
2587 	ASSERT(mutex_owned(&pp->port_mutex));
2588 	ASSERT(DB_TYPE(mp) == M_IOCTL);
2589 
2590 	iocp = (struct iocblk *)mp->b_rptr;
2591 	cmd = iocp->ioc_cmd;
2592 
2593 	USB_DPRINTF_L4(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
2594 	    "mp=%p %s (0x%x)", (void *)mp, usbser_ioctl2str(cmd), cmd);
2595 
2596 	if (tp->t_iocpending != NULL) {
2597 		/*
2598 		 * We were holding an ioctl response pending the
2599 		 * availability of an mblk to hold data to be passed up;
2600 		 * another ioctl came through, which means that ioctl
2601 		 * must have timed out or been aborted.
2602 		 */
2603 		freemsg(tp->t_iocpending);
2604 		tp->t_iocpending = NULL;
2605 	}
2606 
2607 	switch (cmd) {
2608 	case TIOCMGET:
2609 	case TIOCMBIC:
2610 	case TIOCMBIS:
2611 	case TIOCMSET:
2612 	case CONSOPENPOLLEDIO:
2613 	case CONSCLOSEPOLLEDIO:
2614 	case CONSSETABORTENABLE:
2615 	case CONSGETABORTENABLE:
2616 		/*
2617 		 * For the above ioctls do not call ttycommon_ioctl() because
2618 		 * this function frees up the message block (mp->b_cont) that
2619 		 * contains the address of the user variable where we need to
2620 		 * pass back the bit array.
2621 		 */
2622 		error = -1;
2623 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2624 		mutex_exit(&pp->port_mutex);
2625 
2626 		break;
2627 	case TCSBRK:
2628 		/* serialize breaks */
2629 		if (pp->port_act & USBSER_ACT_BREAK) {
2630 
2631 			return (USB_FAILURE);
2632 		}
2633 	default:
2634 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2635 		mutex_exit(&pp->port_mutex);
2636 		(void) ttycommon_ioctl(tp, q, mp, &error);
2637 	}
2638 
2639 	if (error == 0) {
2640 		/*
2641 		 * ttycommon_ioctl() did most of the work
2642 		 * we just use the data it set up
2643 		 */
2644 		switch (cmd) {
2645 		case TCSETSF:
2646 		case TCSETSW:
2647 		case TCSETA:
2648 		case TCSETAW:
2649 		case TCSETAF:
2650 			(void) USBSER_DS_FIFO_DRAIN(pp, DS_TX);
2651 
2652 			/* FALLTHRU */
2653 		case TCSETS:
2654 			mutex_enter(&pp->port_mutex);
2655 			error = usbser_port_program(pp);
2656 			mutex_exit(&pp->port_mutex);
2657 
2658 			break;
2659 		}
2660 
2661 		goto end;
2662 	} else if (error > 0) {
2663 		USB_DPRINTF_L3(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
2664 		    "ttycommon_ioctl returned %d", error);
2665 
2666 		goto end;
2667 	}
2668 
2669 	/*
2670 	 * error < 0: ttycommon_ioctl() didn't do anything, we process it here
2671 	 */
2672 	error = 0;
2673 	switch (cmd) {
2674 	case TCSBRK:
2675 		if ((error = miocpullup(mp, sizeof (int))) != 0) {
2676 
2677 			break;
2678 		}
2679 		/* drain output */
2680 		(void) USBSER_DS_FIFO_DRAIN(pp, USBSER_TX_FIFO_DRAIN_TIMEOUT);
2681 		/*
2682 		 * if required, set break
2683 		 */
2684 		if (*(int *)mp->b_cont->b_rptr == 0) {
2685 			if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS) {
2686 				error = EIO;
2687 
2688 				break;
2689 			}
2690 			mutex_enter(&pp->port_mutex);
2691 			pp->port_act |= USBSER_ACT_BREAK;
2692 			pp->port_delay_id = timeout(usbser_restart, pp,
2693 			    drv_usectohz(250000));
2694 			mutex_exit(&pp->port_mutex);
2695 		}
2696 
2697 		break;
2698 	case TIOCSBRK:
2699 		/* set break */
2700 		if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS) {
2701 			error = EIO;
2702 		}
2703 
2704 		break;
2705 	case TIOCCBRK:
2706 		/* clear break */
2707 		if (USBSER_DS_BREAK_CTL(pp, DS_OFF) != USB_SUCCESS) {
2708 			error = EIO;
2709 		}
2710 
2711 		break;
2712 	case TIOCMSET:
2713 	case TIOCMBIS:
2714 	case TIOCMBIC:
2715 		if (iocp->ioc_count == TRANSPARENT) {
2716 			mcopyin(mp, NULL, sizeof (int), NULL);
2717 
2718 			break;
2719 		}
2720 		if ((error = miocpullup(mp, sizeof (int))) != 0) {
2721 
2722 			break;
2723 		}
2724 
2725 		val = *(int *)mp->b_cont->b_rptr;
2726 		if (cmd == TIOCMSET) {
2727 			rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
2728 		} else if (cmd == TIOCMBIS) {
2729 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
2730 		} else if (cmd == TIOCMBIC) {
2731 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
2732 		}
2733 		if (rval != USB_SUCCESS) {
2734 			error = EIO;
2735 		}
2736 
2737 		break;
2738 	case (tIOC | 109):		/* TIOCSILOOP */
2739 		if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
2740 			if (USBSER_DS_LOOPBACK(pp, DS_ON) != USB_SUCCESS) {
2741 				error = EIO;
2742 			} else {
2743 				iocp->ioc_error = 0;
2744 				mp->b_datap->db_type = M_IOCACK;
2745 			}
2746 		} else {
2747 			error = EINVAL;
2748 		}
2749 
2750 		break;
2751 	case (tIOC | 108):		/* TIOCCILOOP */
2752 		if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
2753 			if (USBSER_DS_LOOPBACK(pp, DS_OFF) != USB_SUCCESS) {
2754 				error = EIO;
2755 			} else {
2756 				iocp->ioc_error = 0;
2757 				mp->b_datap->db_type = M_IOCACK;
2758 			}
2759 		} else {
2760 			error = EINVAL;
2761 		}
2762 
2763 		break;
2764 	case TIOCMGET:
2765 		datamp = allocb(sizeof (int), BPRI_MED);
2766 		if (datamp == NULL) {
2767 			error = EAGAIN;
2768 
2769 			break;
2770 		}
2771 
2772 		rval = USBSER_DS_GET_MODEM_CTL(pp, -1, (int *)datamp->b_rptr);
2773 		if (rval != USB_SUCCESS) {
2774 			error = EIO;
2775 
2776 			break;
2777 		}
2778 
2779 		if (iocp->ioc_count == TRANSPARENT) {
2780 			mcopyout(mp, NULL, sizeof (int), NULL, datamp);
2781 		} else {
2782 			if (mp->b_cont != NULL) {
2783 				freemsg(mp->b_cont);
2784 			}
2785 			mp->b_cont = datamp;
2786 			mp->b_cont->b_wptr += sizeof (int);
2787 			iocp->ioc_count = sizeof (int);
2788 		}
2789 
2790 		break;
2791 	case CONSOPENPOLLEDIO:
2792 		error = usbser_polledio_init(pp);
2793 		if (error != 0)
2794 
2795 			break;
2796 
2797 		error = miocpullup(mp, sizeof (struct cons_polledio *));
2798 		if (error != 0)
2799 
2800 			break;
2801 
2802 		*(struct cons_polledio **)mp->b_cont->b_rptr = &usbser_polledio;
2803 
2804 		mp->b_datap->db_type = M_IOCACK;
2805 
2806 		break;
2807 	case CONSCLOSEPOLLEDIO:
2808 		usbser_polledio_fini(pp);
2809 		mp->b_datap->db_type = M_IOCACK;
2810 		mp->b_datap->db_type = M_IOCACK;
2811 		iocp->ioc_error = 0;
2812 		iocp->ioc_rval = 0;
2813 
2814 		break;
2815 	case CONSSETABORTENABLE:
2816 		error = secpolicy_console(iocp->ioc_cr);
2817 		if (error != 0)
2818 
2819 			break;
2820 
2821 		if (iocp->ioc_count != TRANSPARENT) {
2822 			error = EINVAL;
2823 
2824 			break;
2825 		}
2826 
2827 		/*
2828 		 * To do: implement console abort support
2829 		 * This involves adding a console flag to usbser
2830 		 * state structure. If flag is set, parse input stream
2831 		 * for abort sequence (see asy for example).
2832 		 *
2833 		 * For now, run mdb -K to get kmdb prompt.
2834 		 */
2835 		if (*(intptr_t *)mp->b_cont->b_rptr)
2836 			usbser_console_abort = 1;
2837 		else
2838 			usbser_console_abort = 0;
2839 
2840 		mp->b_datap->db_type = M_IOCACK;
2841 		iocp->ioc_error = 0;
2842 		iocp->ioc_rval = 0;
2843 
2844 		break;
2845 	case CONSGETABORTENABLE:
2846 		/*CONSTANTCONDITION*/
2847 		ASSERT(sizeof (boolean_t) <= sizeof (boolean_t *));
2848 		/*
2849 		 * Store the return value right in the payload
2850 		 * we were passed.  Crude.
2851 		 */
2852 		mcopyout(mp, NULL, sizeof (boolean_t), NULL, NULL);
2853 		*(boolean_t *)mp->b_cont->b_rptr = (usbser_console_abort != 0);
2854 
2855 		break;
2856 	default:
2857 		error = EINVAL;
2858 
2859 		break;
2860 	}
2861 end:
2862 	if (error != 0) {
2863 		iocp->ioc_error = error;
2864 		mp->b_datap->db_type = M_IOCNAK;
2865 	}
2866 	qreply(q, mp);
2867 
2868 	mutex_enter(&pp->port_mutex);
2869 	usbser_release_port_act(pp, USBSER_ACT_CTL);
2870 
2871 	return (USB_SUCCESS);
2872 }
2873 
2874 
2875 /*
2876  * process M_IOCDATA message
2877  */
2878 static void
2879 usbser_iocdata(usbser_port_t *pp, mblk_t *mp)
2880 {
2881 	tty_common_t	*tp = &pp->port_ttycommon;
2882 	queue_t		*q = tp->t_writeq;
2883 	struct iocblk	*ip;
2884 	struct copyresp	*csp;
2885 	int		cmd;
2886 	int		val;
2887 	int		rval;
2888 
2889 	ASSERT(mutex_owned(&pp->port_mutex));
2890 
2891 	ip = (struct iocblk *)mp->b_rptr;
2892 	csp = (struct copyresp *)mp->b_rptr;
2893 	cmd = csp->cp_cmd;
2894 
2895 	if (csp->cp_rval != 0) {
2896 		freemsg(mp);
2897 
2898 		return;
2899 	}
2900 
2901 	switch (cmd) {
2902 	case TIOCMSET:
2903 	case TIOCMBIS:
2904 	case TIOCMBIC:
2905 		if ((mp->b_cont == NULL) ||
2906 		    (MBLKL(mp->b_cont) < sizeof (int))) {
2907 			miocnak(q, mp, 0, EINVAL);
2908 
2909 			break;
2910 		}
2911 		val = *(int *)mp->b_cont->b_rptr;
2912 
2913 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2914 
2915 		mutex_exit(&pp->port_mutex);
2916 		if (cmd == TIOCMSET) {
2917 			rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
2918 		} else if (cmd == TIOCMBIS) {
2919 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
2920 		} else if (cmd == TIOCMBIC) {
2921 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
2922 		}
2923 
2924 		if (mp->b_cont) {
2925 			freemsg(mp->b_cont);
2926 			mp->b_cont = NULL;
2927 		}
2928 		ip->ioc_rval = 0;
2929 		if (rval == USB_SUCCESS) {
2930 			miocack(q, mp, 0, 0);
2931 		} else {
2932 			miocnak(q, mp, 0, EIO);
2933 		}
2934 		mutex_enter(&pp->port_mutex);
2935 
2936 		usbser_release_port_act(pp, USBSER_ACT_CTL);
2937 
2938 		break;
2939 	case TIOCMGET:
2940 		mutex_exit(&pp->port_mutex);
2941 		if (mp->b_cont) {
2942 			freemsg(mp->b_cont);
2943 			mp->b_cont = NULL;
2944 		}
2945 		ip->ioc_rval = 0;
2946 		miocack(q, mp, 0, 0);
2947 		mutex_enter(&pp->port_mutex);
2948 
2949 		break;
2950 	default:
2951 		mutex_exit(&pp->port_mutex);
2952 		miocnak(q, mp, 0, EINVAL);
2953 		mutex_enter(&pp->port_mutex);
2954 
2955 		break;
2956 	}
2957 }
2958 
2959 
2960 /*
2961  * handle M_START[I]/M_STOP[I] messages
2962  */
2963 static void
2964 usbser_stop(usbser_port_t *pp, mblk_t *mp)
2965 {
2966 	usbser_st_mstop++;
2967 	if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
2968 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2969 		pp->port_flags |= USBSER_FL_TX_STOPPED;
2970 
2971 		mutex_exit(&pp->port_mutex);
2972 		USBSER_DS_STOP(pp, DS_TX);
2973 		mutex_enter(&pp->port_mutex);
2974 
2975 		usbser_release_port_act(pp, USBSER_ACT_TX);
2976 		usbser_release_port_act(pp, USBSER_ACT_CTL);
2977 	}
2978 	freemsg(mp);
2979 }
2980 
2981 
2982 static void
2983 usbser_start(usbser_port_t *pp, mblk_t *mp)
2984 {
2985 	usbser_st_mstart++;
2986 	if (pp->port_flags & USBSER_FL_TX_STOPPED) {
2987 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2988 		pp->port_flags &= ~USBSER_FL_TX_STOPPED;
2989 
2990 		mutex_exit(&pp->port_mutex);
2991 		USBSER_DS_START(pp, DS_TX);
2992 		mutex_enter(&pp->port_mutex);
2993 		usbser_release_port_act(pp, USBSER_ACT_CTL);
2994 	}
2995 	freemsg(mp);
2996 }
2997 
2998 
2999 static void
3000 usbser_stopi(usbser_port_t *pp, mblk_t *mp)
3001 {
3002 	usbser_st_mstopi++;
3003 	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
3004 	pp->port_flowc = pp->port_ttycommon.t_stopc;
3005 	usbser_inbound_flow_ctl(pp);
3006 	usbser_release_port_act(pp, USBSER_ACT_CTL);
3007 	freemsg(mp);
3008 }
3009 
3010 static void
3011 usbser_starti(usbser_port_t *pp, mblk_t *mp)
3012 {
3013 	usbser_st_mstarti++;
3014 	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
3015 	pp->port_flowc = pp->port_ttycommon.t_startc;
3016 	usbser_inbound_flow_ctl(pp);
3017 	usbser_release_port_act(pp, USBSER_ACT_CTL);
3018 	freemsg(mp);
3019 }
3020 
3021 /*
3022  * process M_FLUSH message
3023  */
3024 static void
3025 usbser_flush(usbser_port_t *pp, mblk_t *mp)
3026 {
3027 	queue_t	*q = pp->port_ttycommon.t_writeq;
3028 
3029 	if (*mp->b_rptr & FLUSHW) {
3030 		mutex_exit(&pp->port_mutex);
3031 		(void) USBSER_DS_FIFO_FLUSH(pp, DS_TX);	/* flush FIFO buffers */
3032 		flushq(q, FLUSHDATA);			/* flush write queue */
3033 		mutex_enter(&pp->port_mutex);
3034 
3035 		usbser_release_port_act(pp, USBSER_ACT_TX);
3036 
3037 		*mp->b_rptr &= ~FLUSHW;
3038 	}
3039 	if (*mp->b_rptr & FLUSHR) {
3040 		/*
3041 		 * flush FIFO buffers
3042 		 */
3043 		mutex_exit(&pp->port_mutex);
3044 		(void) USBSER_DS_FIFO_FLUSH(pp, DS_RX);
3045 		flushq(RD(q), FLUSHDATA);
3046 		qreply(q, mp);
3047 		mutex_enter(&pp->port_mutex);
3048 	} else {
3049 		freemsg(mp);
3050 	}
3051 }
3052 
3053 /*
3054  * process M_BREAK message
3055  */
3056 static void
3057 usbser_break(usbser_port_t *pp, mblk_t *mp)
3058 {
3059 	int	rval;
3060 
3061 	/*
3062 	 * set the break and arrange for usbser_restart() to be called in 1/4 s
3063 	 */
3064 	mutex_exit(&pp->port_mutex);
3065 	rval = USBSER_DS_BREAK_CTL(pp, DS_ON);
3066 	mutex_enter(&pp->port_mutex);
3067 
3068 	if (rval == USB_SUCCESS) {
3069 		pp->port_act |= USBSER_ACT_BREAK;
3070 		pp->port_delay_id = timeout(usbser_restart, pp,
3071 		    drv_usectohz(250000));
3072 	}
3073 	freemsg(mp);
3074 }
3075 
3076 
3077 /*
3078  * process M_DELAY message
3079  */
3080 static void
3081 usbser_delay(usbser_port_t *pp, mblk_t *mp)
3082 {
3083 	/*
3084 	 * arrange for usbser_restart() to be called when the delay expires
3085 	 */
3086 	pp->port_act |= USBSER_ACT_DELAY;
3087 	pp->port_delay_id = timeout(usbser_restart, pp,
3088 	    (clock_t)(*(uchar_t *)mp->b_rptr + 6));
3089 	freemsg(mp);
3090 }
3091 
3092 
3093 /*
3094  * restart output on a line after a delay or break timer expired
3095  */
3096 static void
3097 usbser_restart(void *arg)
3098 {
3099 	usbser_port_t	*pp = (usbser_port_t *)arg;
3100 
3101 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_restart");
3102 
3103 	mutex_enter(&pp->port_mutex);
3104 	/* if cancelled, return immediately */
3105 	if (pp->port_delay_id == 0) {
3106 		mutex_exit(&pp->port_mutex);
3107 
3108 		return;
3109 	}
3110 	pp->port_delay_id = 0;
3111 
3112 	/* clear break if necessary */
3113 	if (pp->port_act & USBSER_ACT_BREAK) {
3114 		mutex_exit(&pp->port_mutex);
3115 		(void) USBSER_DS_BREAK_CTL(pp, DS_OFF);
3116 		mutex_enter(&pp->port_mutex);
3117 	}
3118 
3119 	usbser_release_port_act(pp, USBSER_ACT_BREAK | USBSER_ACT_DELAY);
3120 
3121 	/* wake wq thread to resume message processing */
3122 	usbser_thr_wake(&pp->port_wq_thread);
3123 	mutex_exit(&pp->port_mutex);
3124 }
3125 
3126 
3127 /*
3128  * program port hardware with the chosen parameters
3129  * most of the operation is based on the values of 'c_iflag' and 'c_cflag'
3130  */
3131 static int
3132 usbser_port_program(usbser_port_t *pp)
3133 {
3134 	tty_common_t		*tp = &pp->port_ttycommon;
3135 	int			baudrate;
3136 	int			c_flag;
3137 	ds_port_param_entry_t	pe[6];
3138 	ds_port_params_t	params;
3139 	int			flow_ctl, ctl_val;
3140 	int			err = 0;
3141 
3142 	baudrate = tp->t_cflag & CBAUD;
3143 	if (tp->t_cflag & CBAUDEXT) {
3144 		baudrate += 16;
3145 	}
3146 
3147 	/*
3148 	 * set input speed same as output, as split speed not supported
3149 	 */
3150 	if (tp->t_cflag & (CIBAUD|CIBAUDEXT)) {
3151 		tp->t_cflag &= ~(CIBAUD);
3152 		if (baudrate > CBAUD) {
3153 			tp->t_cflag |= CIBAUDEXT;
3154 			tp->t_cflag |=
3155 			    (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD);
3156 		} else {
3157 			tp->t_cflag &= ~CIBAUDEXT;
3158 			tp->t_cflag |= ((baudrate << IBSHIFT) & CIBAUD);
3159 		}
3160 	}
3161 
3162 	c_flag = tp->t_cflag;
3163 
3164 	/*
3165 	 * flow control
3166 	 */
3167 	flow_ctl = tp->t_iflag & (IXON | IXANY | IXOFF);
3168 	if (c_flag & CRTSCTS) {
3169 		flow_ctl |= CTSXON;
3170 	}
3171 	if (c_flag & CRTSXOFF) {
3172 		flow_ctl |= RTSXOFF;
3173 	}
3174 
3175 	/*
3176 	 * fill in port parameters we need to set:
3177 	 *
3178 	 * baud rate
3179 	 */
3180 	pe[0].param = DS_PARAM_BAUD;
3181 	pe[0].val.ui = baudrate;
3182 
3183 	/* stop bits */
3184 	pe[1].param = DS_PARAM_STOPB;
3185 	pe[1].val.ui = c_flag & CSTOPB;
3186 
3187 	/* parity */
3188 	pe[2].param = DS_PARAM_PARITY;
3189 	pe[2].val.ui = c_flag & (PARENB | PARODD);
3190 
3191 	/* char size */
3192 	pe[3].param = DS_PARAM_CHARSZ;
3193 	pe[3].val.ui = c_flag & CSIZE;
3194 
3195 	/* start & stop chars */
3196 	pe[4].param = DS_PARAM_XON_XOFF;
3197 	pe[4].val.uc[0] = tp->t_startc;
3198 	pe[4].val.uc[1] = tp->t_stopc;
3199 
3200 	/* flow control */
3201 	pe[5].param = DS_PARAM_FLOW_CTL;
3202 	pe[5].val.ui = flow_ctl;
3203 
3204 	params.tp_entries = &pe[0];
3205 	params.tp_cnt = 6;
3206 
3207 	/* control signals */
3208 	ctl_val = TIOCM_DTR | TIOCM_RTS;
3209 	if (baudrate == 0) {
3210 		ctl_val &= ~TIOCM_DTR;	/* zero baudrate means drop DTR */
3211 	}
3212 	if (pp->port_flags & USBSER_FL_RX_STOPPED) {
3213 		ctl_val &= ~TIOCM_RTS;
3214 	}
3215 
3216 	/* submit */
3217 	mutex_exit(&pp->port_mutex);
3218 	err = USBSER_DS_SET_PORT_PARAMS(pp, &params);
3219 	if (err != USB_SUCCESS) {
3220 		mutex_enter(&pp->port_mutex);
3221 
3222 		return (EINVAL);
3223 	}
3224 
3225 	err = USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR | TIOCM_RTS, ctl_val);
3226 	mutex_enter(&pp->port_mutex);
3227 
3228 	return ((err == USB_SUCCESS) ? 0 : EIO);
3229 }
3230 
3231 
3232 /*
3233  * check if any inbound flow control action needed
3234  */
3235 static void
3236 usbser_inbound_flow_ctl(usbser_port_t *pp)
3237 {
3238 	tcflag_t	need_hw;
3239 	int		rts;
3240 	char		c = pp->port_flowc;
3241 	mblk_t		*mp = NULL;
3242 
3243 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
3244 	    "usbser_inbound_flow_ctl: c=%x cflag=%x port_flags=%x",
3245 	    c, pp->port_ttycommon.t_cflag, pp->port_flags);
3246 
3247 	if (c == '\0') {
3248 
3249 		return;
3250 	}
3251 	pp->port_flowc = '\0';
3252 
3253 	/*
3254 	 * if inbound hardware flow control enabled, we need to frob RTS
3255 	 */
3256 	need_hw = (pp->port_ttycommon.t_cflag & CRTSXOFF);
3257 	if (c == pp->port_ttycommon.t_startc) {
3258 		rts = TIOCM_RTS;
3259 		pp->port_flags &= ~USBSER_FL_RX_STOPPED;
3260 	} else {
3261 		rts = 0;
3262 		pp->port_flags |= USBSER_FL_RX_STOPPED;
3263 	}
3264 
3265 	/*
3266 	 * if character flow control active, transmit a start or stop char,
3267 	 */
3268 	if (pp->port_ttycommon.t_iflag & IXOFF) {
3269 		if ((mp = allocb(1, BPRI_LO)) == NULL) {
3270 			USB_DPRINTF_L2(DPRINT_WQ, pp->port_lh,
3271 			    "usbser_inbound_flow_ctl: allocb failed");
3272 		} else {
3273 			*mp->b_wptr++ = c;
3274 			pp->port_flags |= USBSER_ACT_TX;
3275 		}
3276 	}
3277 
3278 	mutex_exit(&pp->port_mutex);
3279 	if (need_hw) {
3280 		(void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_RTS, rts);
3281 	}
3282 	if (mp) {
3283 		(void) USBSER_DS_TX(pp, mp);
3284 	}
3285 	mutex_enter(&pp->port_mutex);
3286 }
3287 
3288 
3289 /*
3290  * misc
3291  * ----
3292  *
3293  *
3294  * returns !=0 if device is online, 0 otherwise
3295  */
3296 static int
3297 usbser_dev_is_online(usbser_state_t *usp)
3298 {
3299 	int	rval;
3300 
3301 	mutex_enter(&usp->us_mutex);
3302 	rval = (usp->us_dev_state == USB_DEV_ONLINE);
3303 	mutex_exit(&usp->us_mutex);
3304 
3305 	return (rval);
3306 }
3307 
3308 /*
3309  * serialize port activities defined by 'act' mask
3310  */
3311 static void
3312 usbser_serialize_port_act(usbser_port_t *pp, int act)
3313 {
3314 	while (pp->port_act & act) {
3315 		cv_wait(&pp->port_act_cv, &pp->port_mutex);
3316 	}
3317 
3318 	pp->port_act |= act;
3319 }
3320 
3321 
3322 /*
3323  * indicate that port activity is finished
3324  */
3325 static void
3326 usbser_release_port_act(usbser_port_t *pp, int act)
3327 {
3328 	pp->port_act &= ~act;
3329 	cv_broadcast(&pp->port_act_cv);
3330 }
3331 
3332 
3333 /*
3334  * message type to string and back conversion.
3335  *
3336  * pardon breaks on the same line, but as long as cstyle doesn't
3337  * complain, I'd like to keep this form for trivial cases like this.
3338  * associative arrays in the kernel, anyone?
3339  */
3340 static char *
3341 usbser_msgtype2str(int type)
3342 {
3343 	char	*str;
3344 
3345 	switch (type) {
3346 	case M_STOP:	str = "M_STOP";		break;
3347 	case M_START:	str = "M_START";	break;
3348 	case M_STOPI:	str = "M_STOPI";	break;
3349 	case M_STARTI:	str = "M_STARTI";	break;
3350 	case M_DATA:	str = "M_DATA";		break;
3351 	case M_DELAY:	str = "M_DELAY";	break;
3352 	case M_BREAK:	str = "M_BREAK";	break;
3353 	case M_IOCTL:	str = "M_IOCTL";	break;
3354 	case M_IOCDATA:	str = "M_IOCDATA";	break;
3355 	case M_FLUSH:	str = "M_FLUSH";	break;
3356 	case M_CTL:	str = "M_CTL";		break;
3357 	case M_READ:	str = "M_READ";		break;
3358 	default:	str = "unknown";	break;
3359 	}
3360 
3361 	return (str);
3362 }
3363 
3364 
3365 static char *
3366 usbser_ioctl2str(int ioctl)
3367 {
3368 	char	*str;
3369 
3370 	switch (ioctl) {
3371 	case TCGETA:	str = "TCGETA";		break;
3372 	case TCSETA:	str = "TCSETA";		break;
3373 	case TCSETAF:	str = "TCSETAF";	break;
3374 	case TCSETAW:	str = "TCSETAW";	break;
3375 	case TCSBRK:	str = "TCSBRK";		break;
3376 	case TCXONC:	str = "TCXONC";		break;
3377 	case TCFLSH:	str = "TCFLSH";		break;
3378 	case TCGETS:	str = "TCGETS";		break;
3379 	case TCSETS:	str = "TCSETS";		break;
3380 	case TCSETSF:	str = "TCSETSF";	break;
3381 	case TCSETSW:	str = "TCSETSW";	break;
3382 	case TIOCSBRK:	str = "TIOCSBRK";	break;
3383 	case TIOCCBRK:	str = "TIOCCBRK";	break;
3384 	case TIOCMSET:	str = "TIOCMSET";	break;
3385 	case TIOCMBIS:	str = "TIOCMBIS";	break;
3386 	case TIOCMBIC:	str = "TIOCMBIC";	break;
3387 	case TIOCMGET:	str = "TIOCMGET";	break;
3388 	case (tIOC | 109): str = "TIOCSILOOP";	break;
3389 	case (tIOC | 108): str = "TIOCCILOOP";	break;
3390 	case TCGETX:	str = "TCGETX";		break;
3391 	case TCSETX:	str = "TCGETX";		break;
3392 	case TCSETXW:	str = "TCGETX";		break;
3393 	case TCSETXF:	str = "TCGETX";		break;
3394 	default:	str = "unknown";	break;
3395 	}
3396 
3397 	return (str);
3398 }
3399 
3400 /*
3401  * Polled IO support
3402  */
3403 
3404 /* called once	by consconfig() when polledio is opened */
3405 static int
3406 usbser_polledio_init(usbser_port_t *pp)
3407 {
3408 	int err;
3409 	usb_pipe_handle_t hdl;
3410 	ds_ops_t *ds_ops = pp->port_ds_ops;
3411 
3412 	/* only one serial line console supported */
3413 	if (console_input != NULL)
3414 
3415 		return (USB_FAILURE);
3416 
3417 	/* check if underlying driver supports polled io */
3418 	if (ds_ops->ds_version < DS_OPS_VERSION_V1 ||
3419 	    ds_ops->ds_out_pipe == NULL || ds_ops->ds_in_pipe == NULL)
3420 
3421 		return (USB_FAILURE);
3422 
3423 	/* init polled input pipe */
3424 	hdl = ds_ops->ds_in_pipe(pp->port_ds_hdl, pp->port_num);
3425 	err = usb_console_input_init(pp->port_usp->us_dip, hdl,
3426 	    &console_input_buf, &console_input);
3427 	if (err)
3428 
3429 		return (USB_FAILURE);
3430 
3431 	/* init polled output pipe */
3432 	hdl = ds_ops->ds_out_pipe(pp->port_ds_hdl, pp->port_num);
3433 	err = usb_console_output_init(pp->port_usp->us_dip, hdl,
3434 	    &console_output);
3435 	if (err) {
3436 		(void) usb_console_input_fini(console_input);
3437 		console_input = NULL;
3438 
3439 		return (USB_FAILURE);
3440 	}
3441 
3442 	return (USB_SUCCESS);
3443 }
3444 
3445 /* called once	by consconfig() when polledio is closed */
3446 /*ARGSUSED*/
3447 static void usbser_polledio_fini(usbser_port_t *pp)
3448 {
3449 	/* Since we can't move the console, there is nothing to do. */
3450 }
3451 
3452 /*ARGSUSED*/
3453 static void
3454 usbser_polledio_enter(cons_polledio_arg_t arg)
3455 {
3456 	(void) usb_console_input_enter(console_input);
3457 	(void) usb_console_output_enter(console_output);
3458 }
3459 
3460 /*ARGSUSED*/
3461 static void
3462 usbser_polledio_exit(cons_polledio_arg_t arg)
3463 {
3464 	(void) usb_console_output_exit(console_output);
3465 	(void) usb_console_input_exit(console_input);
3466 }
3467 
3468 /*ARGSUSED*/
3469 static void
3470 usbser_putchar(cons_polledio_arg_t arg, uchar_t c)
3471 {
3472 	static uchar_t cr[2] = {'\r', '\n'};
3473 	uint_t nout;
3474 
3475 	if (c == '\n')
3476 		(void) usb_console_write(console_output, cr, 2, &nout);
3477 	else
3478 		(void) usb_console_write(console_output, &c, 1, &nout);
3479 }
3480 
3481 /*ARGSUSED*/
3482 static int
3483 usbser_getchar(cons_polledio_arg_t arg)
3484 {
3485 	while (!usbser_ischar(arg))
3486 		;
3487 
3488 	return (*console_input_start++);
3489 }
3490 
3491 /*ARGSUSED*/
3492 static boolean_t
3493 usbser_ischar(cons_polledio_arg_t arg)
3494 {
3495 	uint_t num_bytes;
3496 
3497 	if (console_input_start < console_input_end)
3498 
3499 		return (1);
3500 
3501 	if (usb_console_read(console_input, &num_bytes) != USB_SUCCESS)
3502 
3503 		return (0);
3504 
3505 	console_input_start = console_input_buf;
3506 	console_input_end = console_input_buf + num_bytes;
3507 
3508 	return (num_bytes != 0);
3509 }
3510