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