xref: /illumos-gate/usr/src/uts/common/io/usb/clients/usbser/usbser.c (revision 80ab886d233f514d54c2a6bdeb9fdfd951bd6881)
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 		cv_wait(&thr->thr_cv, &pp->port_mutex);
1778 
1779 	} while ((thr->thr_flags & USBSER_THR_EXITED) == 0);
1780 }
1781 
1782 
1783 /*
1784  * wake thread
1785  */
1786 static void
1787 usbser_thr_wake(usbser_thread_t *thr)
1788 {
1789 	usbser_port_t	*pp = thr->thr_port;
1790 
1791 	ASSERT(mutex_owned(&pp->port_mutex));
1792 
1793 	thr->thr_flags |= USBSER_THR_WAKE;
1794 	cv_signal(&thr->thr_cv);
1795 }
1796 
1797 
1798 /*
1799  * thread handling write queue requests
1800  */
1801 static void
1802 usbser_wq_thread(void *arg)
1803 {
1804 	usbser_thread_t	*thr = (usbser_thread_t *)arg;
1805 	usbser_port_t	*pp = thr->thr_port;
1806 
1807 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wq_thread: enter");
1808 
1809 	mutex_enter(&pp->port_mutex);
1810 	while (thr->thr_flags & USBSER_THR_RUNNING) {
1811 		/*
1812 		 * when woken, see what we should do
1813 		 */
1814 		if (thr->thr_flags & USBSER_THR_WAKE) {
1815 			thr->thr_flags &= ~USBSER_THR_WAKE;
1816 
1817 			/*
1818 			 * status callback pending?
1819 			 */
1820 			if (pp->port_flags & USBSER_FL_STATUS_CB) {
1821 				usbser_status_proc_cb(pp);
1822 			}
1823 
1824 			usbser_wmsg(pp);
1825 		} else {
1826 			/*
1827 			 * sleep until woken up to do some work, e.g:
1828 			 * - new message arrives;
1829 			 * - data transmit completes;
1830 			 * - status callback pending;
1831 			 * - wq thread is cancelled;
1832 			 */
1833 			cv_wait(&thr->thr_cv, &pp->port_mutex);
1834 			USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
1835 			    "usbser_wq_thread: wakeup");
1836 		}
1837 	}
1838 	thr->thr_flags |= USBSER_THR_EXITED;
1839 	cv_signal(&thr->thr_cv);
1840 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wq_thread: exit");
1841 	mutex_exit(&pp->port_mutex);
1842 }
1843 
1844 
1845 /*
1846  * thread handling read queue requests
1847  */
1848 static void
1849 usbser_rq_thread(void *arg)
1850 {
1851 	usbser_thread_t	*thr = (usbser_thread_t *)arg;
1852 	usbser_port_t	*pp = thr->thr_port;
1853 
1854 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_rq_thread: enter");
1855 
1856 	mutex_enter(&pp->port_mutex);
1857 	while (thr->thr_flags & USBSER_THR_RUNNING) {
1858 		/*
1859 		 * read service routine will wake us when
1860 		 * more space is available on the read queue
1861 		 */
1862 		if (thr->thr_flags & USBSER_THR_WAKE) {
1863 			thr->thr_flags &= ~USBSER_THR_WAKE;
1864 
1865 			/*
1866 			 * don't process messages until queue is enabled
1867 			 */
1868 			if (!pp->port_ttycommon.t_readq) {
1869 
1870 				continue;
1871 			}
1872 
1873 			/*
1874 			 * check whether we need to resume receive
1875 			 */
1876 			if (pp->port_flags & USBSER_FL_RX_STOPPED) {
1877 				pp->port_flowc = pp->port_ttycommon.t_startc;
1878 				usbser_inbound_flow_ctl(pp);
1879 			}
1880 
1881 			/*
1882 			 * grab more data if available
1883 			 */
1884 			mutex_exit(&pp->port_mutex);
1885 			usbser_rx_cb((caddr_t)pp);
1886 			mutex_enter(&pp->port_mutex);
1887 		} else {
1888 			cv_wait(&thr->thr_cv, &pp->port_mutex);
1889 			USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
1890 			    "usbser_rq_thread: wakeup");
1891 		}
1892 	}
1893 	thr->thr_flags |= USBSER_THR_EXITED;
1894 	cv_signal(&thr->thr_cv);
1895 	USB_DPRINTF_L4(DPRINT_RQ, pp->port_lh, "usbser_rq_thread: exit");
1896 	mutex_exit(&pp->port_mutex);
1897 }
1898 
1899 
1900 /*
1901  * DSD callbacks
1902  * -------------
1903  *
1904  * Note: to avoid deadlocks with DSD, these callbacks
1905  * should not call DSD functions that can block.
1906  *
1907  *
1908  * transmit callback
1909  *
1910  * invoked by DSD when the last byte of data is transmitted over USB
1911  */
1912 static void
1913 usbser_tx_cb(caddr_t arg)
1914 {
1915 	usbser_port_t	*pp = (usbser_port_t *)arg;
1916 	int		online;
1917 
1918 	online = usbser_dev_is_online(pp->port_usp);
1919 
1920 	mutex_enter(&pp->port_mutex);
1921 	USB_DPRINTF_L4(DPRINT_TX_CB, pp->port_lh,
1922 	    "usbser_tx_cb: act=%x curthread=%p", pp->port_act, curthread);
1923 
1924 	usbser_release_port_act(pp, USBSER_ACT_TX);
1925 
1926 	if (online && USBSER_PORT_ACCESS_OK(pp) && !USBSER_PORT_IS_BUSY(pp)) {
1927 		/*
1928 		 * wake wq thread for further data/ioctl processing
1929 		 */
1930 		usbser_thr_wake(&pp->port_wq_thread);
1931 	}
1932 	mutex_exit(&pp->port_mutex);
1933 }
1934 
1935 
1936 /*
1937  * receive callback
1938  *
1939  * invoked by DSD when there is more data for us to pick
1940  */
1941 static void
1942 usbser_rx_cb(caddr_t arg)
1943 {
1944 	usbser_port_t	*pp = (usbser_port_t *)arg;
1945 	queue_t		*rq, *wq;
1946 	mblk_t		*mp;		/* current mblk */
1947 	mblk_t		*data, *data_tail; /* M_DATA mblk list and its tail */
1948 	mblk_t		*emp;		/* error (M_BREAK) mblk */
1949 
1950 	USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh, "usbser_rx_cb");
1951 
1952 	if (!usbser_dev_is_online(pp->port_usp)) {
1953 
1954 		return;
1955 	}
1956 
1957 	/* get data from DSD */
1958 	if ((mp = USBSER_DS_RX(pp)) == NULL) {
1959 
1960 		return;
1961 	}
1962 
1963 	mutex_enter(&pp->port_mutex);
1964 	if ((!USBSER_PORT_ACCESS_OK(pp)) ||
1965 	    ((pp->port_ttycommon.t_cflag & CREAD) == 0)) {
1966 		freemsg(mp);
1967 		mutex_exit(&pp->port_mutex);
1968 		USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
1969 		    "usbser_rx_cb: access not ok or receiver disabled");
1970 
1971 		return;
1972 	}
1973 
1974 	usbser_serialize_port_act(pp, USBSER_ACT_RX);
1975 
1976 	rq = pp->port_ttycommon.t_readq;
1977 	wq = pp->port_ttycommon.t_writeq;
1978 	mutex_exit(&pp->port_mutex);
1979 
1980 	/*
1981 	 * DSD data is a b_cont-linked list of M_DATA and M_BREAK blocks.
1982 	 * M_DATA is correctly received data.
1983 	 * M_BREAK is a character with either framing or parity error.
1984 	 *
1985 	 * this loop runs through the list of mblks. when it meets an M_BREAK,
1986 	 * it sends all leading M_DATA's in one shot, then sends M_BREAK.
1987 	 * in the trivial case when list contains only M_DATA's, the loop
1988 	 * does nothing but set data variable.
1989 	 */
1990 	data = data_tail = NULL;
1991 	while (mp) {
1992 		/*
1993 		 * skip data until we meet M_BREAK or end of list
1994 		 */
1995 		if (DB_TYPE(mp) == M_DATA) {
1996 			if (data == NULL) {
1997 				data = mp;
1998 			}
1999 			data_tail = mp;
2000 			mp = mp->b_cont;
2001 
2002 			continue;
2003 		}
2004 
2005 		/* detach data list from mp */
2006 		if (data_tail) {
2007 			data_tail->b_cont = NULL;
2008 		}
2009 		/* detach emp from the list */
2010 		emp = mp;
2011 		mp = mp->b_cont;
2012 		emp->b_cont = NULL;
2013 
2014 		/* DSD shouldn't send anything but M_DATA or M_BREAK */
2015 		if ((DB_TYPE(emp) != M_BREAK) || (MBLKL(emp) != 2)) {
2016 			freemsg(emp);
2017 			USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
2018 			    "usbser_rx_cb: bad message");
2019 
2020 			continue;
2021 		}
2022 
2023 		/*
2024 		 * first tweak and send M_DATA's
2025 		 */
2026 		if (data) {
2027 			usbser_rx_massage_data(pp, data);
2028 			usbser_rx_cb_put(pp, rq, wq, data);
2029 			data = data_tail = NULL;
2030 		}
2031 
2032 		/*
2033 		 * now tweak and send M_BREAK
2034 		 */
2035 		mutex_enter(&pp->port_mutex);
2036 		usbser_rx_massage_mbreak(pp, emp);
2037 		mutex_exit(&pp->port_mutex);
2038 		usbser_rx_cb_put(pp, rq, wq, emp);
2039 	}
2040 
2041 	/* send the rest of the data, if any */
2042 	if (data) {
2043 		usbser_rx_massage_data(pp, data);
2044 		usbser_rx_cb_put(pp, rq, wq, data);
2045 	}
2046 
2047 	mutex_enter(&pp->port_mutex);
2048 	usbser_release_port_act(pp, USBSER_ACT_RX);
2049 	mutex_exit(&pp->port_mutex);
2050 }
2051 
2052 /*
2053  * the joys of termio -- this is to accomodate Unix98 assertion:
2054  *
2055  *   If PARENB is supported and is set, when PARMRK is set, and CSIZE is
2056  *   set to CS8, and IGNPAR is clear, and ISTRIP is clear, a valid
2057  *   character of '\377' is read as '\377', '\377'.
2058  *
2059  *   Posix Ref: Assertion 7.1.2.2-16(C)
2060  *
2061  * this requires the driver to scan every incoming valid character
2062  */
2063 static void
2064 usbser_rx_massage_data(usbser_port_t *pp, mblk_t *mp)
2065 {
2066 	tty_common_t	*tp = &pp->port_ttycommon;
2067 	uchar_t		*p;
2068 	mblk_t		*newmp;
2069 	int		tailsz;
2070 
2071 	/* avoid scanning if possible */
2072 	mutex_enter(&pp->port_mutex);
2073 	if (!((tp->t_cflag & PARENB) && (tp->t_iflag & PARMRK) &&
2074 	    ((tp->t_cflag & CSIZE) == CS8) &&
2075 	    ((tp->t_iflag & (IGNPAR|ISTRIP)) == 0))) {
2076 		mutex_exit(&pp->port_mutex);
2077 
2078 		return;
2079 	}
2080 	mutex_exit(&pp->port_mutex);
2081 
2082 	while (mp) {
2083 		for (p = mp->b_rptr; p < mp->b_wptr; ) {
2084 			if (*p++ != 0377) {
2085 
2086 				continue;
2087 			}
2088 			USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
2089 			    "usbser_rx_massage_data: mp=%p off=%d(%d)",
2090 			    mp, p - mp->b_rptr - 1, MBLKL(mp));
2091 
2092 			/*
2093 			 * insert another 0377 after this one. all data after
2094 			 * the original 0377 have to be copied to the new mblk
2095 			 */
2096 			tailsz = mp->b_wptr - p;
2097 			if ((newmp = allocb(tailsz + 1, BPRI_HI)) == NULL) {
2098 				USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
2099 				    "usbser_rx_massage_data: allocb failed");
2100 
2101 				continue;
2102 			}
2103 
2104 			/* fill in the new mblk */
2105 			*newmp->b_wptr++ = 0377;
2106 			if (tailsz > 0) {
2107 				bcopy(p, newmp->b_wptr, tailsz);
2108 				newmp->b_wptr += tailsz;
2109 			}
2110 			/* shrink the original mblk */
2111 			mp->b_wptr = p;
2112 
2113 			newmp->b_cont = mp->b_cont;
2114 			mp->b_cont = newmp;
2115 			p = newmp->b_rptr + 1;
2116 			mp = newmp;
2117 		}
2118 		mp = mp->b_cont;
2119 	}
2120 }
2121 
2122 /*
2123  * more joys of termio
2124  */
2125 static void
2126 usbser_rx_massage_mbreak(usbser_port_t *pp, mblk_t *mp)
2127 {
2128 	tty_common_t	*tp = &pp->port_ttycommon;
2129 	uchar_t		err, c;
2130 
2131 	err = *mp->b_rptr;
2132 	c = *(mp->b_rptr + 1);
2133 
2134 	if ((err & (DS_FRAMING_ERR | DS_BREAK_ERR)) && (c == 0)) {
2135 		/* break */
2136 		mp->b_rptr += 2;
2137 	} else if (!(tp->t_iflag & INPCK) && (err & (DS_PARITY_ERR))) {
2138 		/* Posix Ref: Assertion 7.1.2.2-20(C) */
2139 		mp->b_rptr++;
2140 		DB_TYPE(mp) = M_DATA;
2141 	} else {
2142 		/* for ldterm to handle */
2143 		mp->b_rptr++;
2144 	}
2145 
2146 	USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
2147 	    "usbser_rx_massage_mbreak: type=%x len=%d [0]=0%o",
2148 	    DB_TYPE(mp), MBLKL(mp), (MBLKL(mp) > 0) ? *mp->b_rptr : 45);
2149 }
2150 
2151 
2152 /*
2153  * in rx callback, try to send an mblk upstream
2154  */
2155 static void
2156 usbser_rx_cb_put(usbser_port_t *pp, queue_t *rq, queue_t *wq, mblk_t *mp)
2157 {
2158 	if (canputnext(rq)) {
2159 		putnext(rq, mp);
2160 	} else if (canput(rq) && putq(rq, mp)) {
2161 		/*
2162 		 * full queue indicates the need for inbound flow control
2163 		 */
2164 		(void) putctl(wq, M_STOPI);
2165 		usbser_st_put_stopi++;
2166 
2167 		USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
2168 		    "usbser_rx_cb: cannot putnext, flow ctl");
2169 	} else {
2170 		freemsg(mp);
2171 		usbser_st_rx_data_loss++;
2172 		(void) putctl(wq, M_STOPI);
2173 		usbser_st_put_stopi++;
2174 
2175 		USB_DPRINTF_L1(DPRINT_RX_CB, pp->port_lh,
2176 		    "input overrun");
2177 	}
2178 }
2179 
2180 
2181 /*
2182  * modem status change callback
2183  *
2184  * each time external status lines are changed, DSD calls this routine
2185  */
2186 static void
2187 usbser_status_cb(caddr_t arg)
2188 {
2189 	usbser_port_t	*pp = (usbser_port_t *)arg;
2190 
2191 	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_cb");
2192 
2193 	if (!usbser_dev_is_online(pp->port_usp)) {
2194 
2195 		return;
2196 	}
2197 
2198 	/*
2199 	 * actual processing will be done in usbser_status_proc_cb()
2200 	 * running in wq thread
2201 	 */
2202 	mutex_enter(&pp->port_mutex);
2203 	if (USBSER_PORT_ACCESS_OK(pp) || USBSER_IS_OPENING(pp)) {
2204 		pp->port_flags |= USBSER_FL_STATUS_CB;
2205 		usbser_thr_wake(&pp->port_wq_thread);
2206 	}
2207 	mutex_exit(&pp->port_mutex);
2208 }
2209 
2210 
2211 /*
2212  * modem status change
2213  */
2214 static void
2215 usbser_status_proc_cb(usbser_port_t *pp)
2216 {
2217 	tty_common_t	*tp = &pp->port_ttycommon;
2218 	queue_t		*rq, *wq;
2219 	int		status;
2220 	int		drop_dtr = 0;
2221 	int		rq_msg = 0, wq_msg = 0;
2222 
2223 	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_proc_cb");
2224 
2225 	pp->port_flags &= ~USBSER_FL_STATUS_CB;
2226 
2227 	mutex_exit(&pp->port_mutex);
2228 	if (!usbser_dev_is_online(pp->port_usp)) {
2229 		mutex_enter(&pp->port_mutex);
2230 
2231 		return;
2232 	}
2233 
2234 	/* get modem status */
2235 	if (USBSER_DS_GET_MODEM_CTL(pp, -1, &status) != USB_SUCCESS) {
2236 		mutex_enter(&pp->port_mutex);
2237 
2238 		return;
2239 	}
2240 
2241 	mutex_enter(&pp->port_mutex);
2242 	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2243 
2244 	rq = pp->port_ttycommon.t_readq;
2245 	wq = pp->port_ttycommon.t_writeq;
2246 
2247 	/*
2248 	 * outbound flow control
2249 	 */
2250 	if (tp->t_cflag & CRTSCTS) {
2251 		if (!(status & TIOCM_CTS)) {
2252 			/*
2253 			 * CTS dropped, stop xmit
2254 			 */
2255 			if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
2256 				wq_msg = M_STOP;
2257 			}
2258 		} else if (pp->port_flags & USBSER_FL_TX_STOPPED) {
2259 			/*
2260 			 * CTS raised, resume xmit
2261 			 */
2262 			wq_msg = M_START;
2263 		}
2264 	}
2265 
2266 	/*
2267 	 * check carrier
2268 	 */
2269 	if ((status & TIOCM_CD) || (tp->t_flags & TS_SOFTCAR)) {
2270 		/*
2271 		 * carrier present
2272 		 */
2273 		if ((pp->port_flags & USBSER_FL_CARR_ON) == 0) {
2274 			pp->port_flags |= USBSER_FL_CARR_ON;
2275 
2276 			rq_msg = M_UNHANGUP;
2277 			/*
2278 			 * wake open
2279 			 */
2280 			if (pp->port_flags & USBSER_FL_WOPEN) {
2281 				cv_broadcast(&pp->port_car_cv);
2282 			}
2283 
2284 			USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2285 			    "usbser_status_cb: carr on");
2286 		}
2287 	} else if (pp->port_flags & USBSER_FL_CARR_ON) {
2288 		pp->port_flags &= ~USBSER_FL_CARR_ON;
2289 		/*
2290 		 * carrier went away: if not local line, drop DTR
2291 		 */
2292 		if (!(tp->t_cflag & CLOCAL)) {
2293 			drop_dtr = 1;
2294 			rq_msg = M_HANGUP;
2295 		}
2296 		if ((pp->port_flags & USBSER_FL_TX_STOPPED) && (wq_msg == 0)) {
2297 			wq_msg = M_START;
2298 		}
2299 
2300 		USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2301 		    "usbser_status_cb: carr off");
2302 	}
2303 	mutex_exit(&pp->port_mutex);
2304 
2305 	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2306 	    "usbser_status_cb: rq_msg=%d wq_msg=%d", rq_msg, wq_msg);
2307 
2308 	/*
2309 	 * commit postponed actions now
2310 	 * do so only if port is fully open (queues are enabled)
2311 	 */
2312 	if (rq) {
2313 		if (rq_msg) {
2314 			(void) putnextctl(rq, rq_msg);
2315 		}
2316 		if (drop_dtr) {
2317 			(void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR, 0);
2318 		}
2319 		if (wq_msg) {
2320 			(void) putctl(wq, wq_msg);
2321 		}
2322 	}
2323 
2324 	mutex_enter(&pp->port_mutex);
2325 	usbser_release_port_act(pp, USBSER_ACT_CTL);
2326 }
2327 
2328 
2329 /*
2330  * serial support
2331  * --------------
2332  *
2333  *
2334  * this routine is run by wq thread every time it's woken,
2335  * i.e. when the queue contains messages to process
2336  */
2337 static void
2338 usbser_wmsg(usbser_port_t *pp)
2339 {
2340 	queue_t		*q = pp->port_ttycommon.t_writeq;
2341 	mblk_t		*mp;
2342 	int		msgtype;
2343 
2344 	ASSERT(mutex_owned(&pp->port_mutex));
2345 
2346 	if (q == NULL) {
2347 		USB_DPRINTF_L3(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=NULL");
2348 
2349 		return;
2350 	}
2351 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=%p act=%x 0x%x",
2352 	    q, pp->port_act, q->q_first ? DB_TYPE(q->q_first) : 0xff);
2353 
2354 	while ((mp = getq(q)) != NULL) {
2355 		msgtype = DB_TYPE(mp);
2356 		USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: "
2357 		    "type=%s (0x%x)", usbser_msgtype2str(msgtype), msgtype);
2358 
2359 		switch (msgtype) {
2360 		/*
2361 		 * high-priority messages
2362 		 */
2363 		case M_STOP:
2364 			usbser_stop(pp, mp);
2365 
2366 			break;
2367 		case M_START:
2368 			usbser_start(pp, mp);
2369 
2370 			break;
2371 		case M_STOPI:
2372 			usbser_stopi(pp, mp);
2373 
2374 			break;
2375 		case M_STARTI:
2376 			usbser_starti(pp, mp);
2377 
2378 			break;
2379 		case M_IOCDATA:
2380 			usbser_iocdata(pp, mp);
2381 
2382 			break;
2383 		case M_FLUSH:
2384 			usbser_flush(pp, mp);
2385 
2386 			break;
2387 		/*
2388 		 * normal-priority messages
2389 		 */
2390 		case M_BREAK:
2391 			usbser_break(pp, mp);
2392 
2393 			break;
2394 		case M_DELAY:
2395 			usbser_delay(pp, mp);
2396 
2397 			break;
2398 		case M_DATA:
2399 			if (usbser_data(pp, mp) != USB_SUCCESS) {
2400 				(void) putbq(q, mp);
2401 
2402 				return;
2403 			}
2404 
2405 			break;
2406 		case M_IOCTL:
2407 			if (usbser_ioctl(pp, mp) != USB_SUCCESS) {
2408 				(void) putbq(q, mp);
2409 
2410 				return;
2411 			}
2412 
2413 			break;
2414 		default:
2415 			freemsg(mp);
2416 
2417 			break;
2418 		}
2419 	}
2420 }
2421 
2422 
2423 /*
2424  * process M_DATA message
2425  */
2426 static int
2427 usbser_data(usbser_port_t *pp, mblk_t *mp)
2428 {
2429 	/* put off until current transfer ends or delay is over */
2430 	if ((pp->port_act & USBSER_ACT_TX) ||
2431 	    (pp->port_act & USBSER_ACT_DELAY)) {
2432 
2433 		return (USB_FAILURE);
2434 	}
2435 	if ((MBLKL(mp) <= 0)) {
2436 		freemsg(mp);
2437 
2438 		return (USB_SUCCESS);
2439 	}
2440 
2441 	pp->port_act |= USBSER_ACT_TX;
2442 	pp->port_wq_data_cnt -= msgdsize(mp);
2443 
2444 	mutex_exit(&pp->port_mutex);
2445 	/* DSD is required to accept data block in any case */
2446 	(void) USBSER_DS_TX(pp, mp);
2447 	mutex_enter(&pp->port_mutex);
2448 
2449 	return (USB_SUCCESS);
2450 }
2451 
2452 
2453 /*
2454  * process an M_IOCTL message
2455  */
2456 static int
2457 usbser_ioctl(usbser_port_t *pp, mblk_t *mp)
2458 {
2459 	tty_common_t	*tp = &pp->port_ttycommon;
2460 	queue_t		*q = tp->t_writeq;
2461 	struct iocblk	*iocp;
2462 	int		cmd;
2463 	mblk_t		*datamp;
2464 	int		error = 0, rval;
2465 	int		val;
2466 
2467 	ASSERT(mutex_owned(&pp->port_mutex));
2468 	ASSERT(DB_TYPE(mp) == M_IOCTL);
2469 
2470 	iocp = (struct iocblk *)mp->b_rptr;
2471 	cmd = iocp->ioc_cmd;
2472 
2473 	USB_DPRINTF_L4(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
2474 	    "mp=%p %s (0x%x)", mp, usbser_ioctl2str(cmd), cmd);
2475 
2476 	if (tp->t_iocpending != NULL) {
2477 		/*
2478 		 * We were holding an ioctl response pending the
2479 		 * availability of an mblk to hold data to be passed up;
2480 		 * another ioctl came through, which means that ioctl
2481 		 * must have timed out or been aborted.
2482 		 */
2483 		freemsg(tp->t_iocpending);
2484 		tp->t_iocpending = NULL;
2485 	}
2486 
2487 	switch (cmd) {
2488 	case TIOCMGET:
2489 	case TIOCMBIC:
2490 	case TIOCMBIS:
2491 	case TIOCMSET:
2492 		/*
2493 		 * For the above ioctls do not call ttycommon_ioctl() because
2494 		 * this function frees up the message block (mp->b_cont) that
2495 		 * contains the address of the user variable where we need to
2496 		 * pass back the bit array.
2497 		 */
2498 		error = -1;
2499 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2500 		mutex_exit(&pp->port_mutex);
2501 
2502 		break;
2503 	case TCSBRK:
2504 		/* serialize breaks */
2505 		if (pp->port_act & USBSER_ACT_BREAK) {
2506 
2507 			return (USB_FAILURE);
2508 		}
2509 	default:
2510 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2511 		mutex_exit(&pp->port_mutex);
2512 		(void) ttycommon_ioctl(tp, q, mp, &error);
2513 	}
2514 
2515 	if (error == 0) {
2516 		/*
2517 		 * ttycommon_ioctl() did most of the work
2518 		 * we just use the data it set up
2519 		 */
2520 		switch (cmd) {
2521 		case TCSETSF:
2522 		case TCSETSW:
2523 		case TCSETA:
2524 		case TCSETAW:
2525 		case TCSETAF:
2526 			(void) USBSER_DS_FIFO_DRAIN(pp, DS_TX);
2527 
2528 			/* FALLTHRU */
2529 		case TCSETS:
2530 			mutex_enter(&pp->port_mutex);
2531 			error = usbser_port_program(pp);
2532 			mutex_exit(&pp->port_mutex);
2533 
2534 			break;
2535 		}
2536 
2537 		goto end;
2538 	} else if (error > 0) {
2539 		USB_DPRINTF_L3(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
2540 		    "ttycommon_ioctl returned %d", error);
2541 
2542 		goto end;
2543 	}
2544 
2545 	/*
2546 	 * error < 0: ttycommon_ioctl() didn't do anything, we process it here
2547 	 */
2548 	error = 0;
2549 	switch (cmd) {
2550 	case TCSBRK:
2551 		if ((error = miocpullup(mp, sizeof (int))) != 0) {
2552 
2553 			break;
2554 		}
2555 		/* drain output */
2556 		(void) USBSER_DS_FIFO_DRAIN(pp, USBSER_TX_FIFO_DRAIN_TIMEOUT);
2557 		/*
2558 		 * if required, set break
2559 		 */
2560 		if (*(int *)mp->b_cont->b_rptr == 0) {
2561 			if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS) {
2562 				error = EIO;
2563 
2564 				break;
2565 			}
2566 			mutex_enter(&pp->port_mutex);
2567 			pp->port_act |= USBSER_ACT_BREAK;
2568 			pp->port_delay_id = timeout(usbser_restart, pp,
2569 							drv_usectohz(250000));
2570 			mutex_exit(&pp->port_mutex);
2571 		}
2572 
2573 		break;
2574 	case TIOCSBRK:
2575 		/* set break */
2576 		if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS) {
2577 			error = EIO;
2578 		}
2579 
2580 		break;
2581 	case TIOCCBRK:
2582 		/* clear break */
2583 		if (USBSER_DS_BREAK_CTL(pp, DS_OFF) != USB_SUCCESS) {
2584 			error = EIO;
2585 		}
2586 
2587 		break;
2588 	case TIOCMSET:
2589 	case TIOCMBIS:
2590 	case TIOCMBIC:
2591 		if (iocp->ioc_count == TRANSPARENT) {
2592 			mcopyin(mp, NULL, sizeof (int), NULL);
2593 
2594 			break;
2595 		}
2596 		if ((error = miocpullup(mp, sizeof (int))) != 0) {
2597 
2598 			break;
2599 		}
2600 
2601 		val = *(int *)mp->b_cont->b_rptr;
2602 		if (cmd == TIOCMSET) {
2603 			rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
2604 		} else if (cmd == TIOCMBIS) {
2605 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
2606 		} else if (cmd == TIOCMBIC) {
2607 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
2608 		}
2609 		if (rval != USB_SUCCESS) {
2610 			error = EIO;
2611 		}
2612 
2613 		break;
2614 	case (tIOC | 109):		/* TIOCSILOOP */
2615 		if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
2616 			if (USBSER_DS_LOOPBACK(pp, DS_ON) != USB_SUCCESS) {
2617 				error = EIO;
2618 			} else {
2619 				iocp->ioc_error = 0;
2620 				mp->b_datap->db_type = M_IOCACK;
2621 			}
2622 		} else {
2623 			error = EINVAL;
2624 		}
2625 
2626 		break;
2627 	case (tIOC | 108):		/* TIOCCILOOP */
2628 		if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
2629 			if (USBSER_DS_LOOPBACK(pp, DS_OFF) != USB_SUCCESS) {
2630 				error = EIO;
2631 			} else {
2632 				iocp->ioc_error = 0;
2633 				mp->b_datap->db_type = M_IOCACK;
2634 			}
2635 		} else {
2636 			error = EINVAL;
2637 		}
2638 
2639 		break;
2640 	case TIOCMGET:
2641 		datamp = allocb(sizeof (int), BPRI_MED);
2642 		if (datamp == NULL) {
2643 			error = EAGAIN;
2644 
2645 			break;
2646 		}
2647 
2648 		rval = USBSER_DS_GET_MODEM_CTL(pp, -1, (int *)datamp->b_rptr);
2649 		if (rval != USB_SUCCESS) {
2650 			error = EIO;
2651 
2652 			break;
2653 		}
2654 
2655 		if (iocp->ioc_count == TRANSPARENT) {
2656 			mcopyout(mp, NULL, sizeof (int), NULL, datamp);
2657 		} else {
2658 			if (mp->b_cont != NULL) {
2659 				freemsg(mp->b_cont);
2660 			}
2661 			mp->b_cont = datamp;
2662 			mp->b_cont->b_wptr += sizeof (int);
2663 			iocp->ioc_count = sizeof (int);
2664 		}
2665 
2666 		break;
2667 	default:
2668 		error = EINVAL;
2669 
2670 		break;
2671 	}
2672 end:
2673 	if (error != 0) {
2674 		iocp->ioc_error = error;
2675 		mp->b_datap->db_type = M_IOCNAK;
2676 	}
2677 	qreply(q, mp);
2678 
2679 	mutex_enter(&pp->port_mutex);
2680 	usbser_release_port_act(pp, USBSER_ACT_CTL);
2681 
2682 	return (USB_SUCCESS);
2683 }
2684 
2685 
2686 /*
2687  * process M_IOCDATA message
2688  */
2689 static void
2690 usbser_iocdata(usbser_port_t *pp, mblk_t *mp)
2691 {
2692 	tty_common_t	*tp = &pp->port_ttycommon;
2693 	queue_t		*q = tp->t_writeq;
2694 	struct iocblk	*ip;
2695 	struct copyresp	*csp;
2696 	int		cmd;
2697 	int		val;
2698 	int		rval;
2699 
2700 	ASSERT(mutex_owned(&pp->port_mutex));
2701 
2702 	ip = (struct iocblk *)mp->b_rptr;
2703 	csp = (struct copyresp *)mp->b_rptr;
2704 	cmd = csp->cp_cmd;
2705 
2706 	if (csp->cp_rval != 0) {
2707 		freemsg(mp);
2708 
2709 		return;
2710 	}
2711 
2712 	switch (cmd) {
2713 	case TIOCMSET:
2714 	case TIOCMBIS:
2715 	case TIOCMBIC:
2716 		if ((mp->b_cont == NULL) ||
2717 		    (MBLKL(mp->b_cont) < sizeof (int))) {
2718 			miocnak(q, mp, 0, EINVAL);
2719 
2720 			break;
2721 		}
2722 		val = *(int *)mp->b_cont->b_rptr;
2723 
2724 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2725 
2726 		mutex_exit(&pp->port_mutex);
2727 		if (cmd == TIOCMSET) {
2728 			rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
2729 		} else if (cmd == TIOCMBIS) {
2730 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
2731 		} else if (cmd == TIOCMBIC) {
2732 			rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
2733 		}
2734 
2735 		if (mp->b_cont) {
2736 			freemsg(mp->b_cont);
2737 			mp->b_cont = NULL;
2738 		}
2739 		ip->ioc_rval = 0;
2740 		if (rval == USB_SUCCESS) {
2741 			miocack(q, mp, 0, 0);
2742 		} else {
2743 			miocnak(q, mp, 0, EIO);
2744 		}
2745 		mutex_enter(&pp->port_mutex);
2746 
2747 		usbser_release_port_act(pp, USBSER_ACT_CTL);
2748 
2749 		break;
2750 	case TIOCMGET:
2751 		mutex_exit(&pp->port_mutex);
2752 		if (mp->b_cont) {
2753 			freemsg(mp->b_cont);
2754 			mp->b_cont = NULL;
2755 		}
2756 		ip->ioc_rval = 0;
2757 		miocack(q, mp, 0, 0);
2758 		mutex_enter(&pp->port_mutex);
2759 
2760 		break;
2761 	default:
2762 		mutex_exit(&pp->port_mutex);
2763 		miocnak(q, mp, 0, EINVAL);
2764 		mutex_enter(&pp->port_mutex);
2765 
2766 		break;
2767 	}
2768 }
2769 
2770 
2771 /*
2772  * handle M_START[I]/M_STOP[I] messages
2773  */
2774 static void
2775 usbser_stop(usbser_port_t *pp, mblk_t *mp)
2776 {
2777 	usbser_st_mstop++;
2778 	if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
2779 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2780 		pp->port_flags |= USBSER_FL_TX_STOPPED;
2781 
2782 		mutex_exit(&pp->port_mutex);
2783 		USBSER_DS_STOP(pp, DS_TX);
2784 		mutex_enter(&pp->port_mutex);
2785 
2786 		usbser_release_port_act(pp, USBSER_ACT_TX);
2787 		usbser_release_port_act(pp, USBSER_ACT_CTL);
2788 	}
2789 	freemsg(mp);
2790 }
2791 
2792 
2793 static void
2794 usbser_start(usbser_port_t *pp, mblk_t *mp)
2795 {
2796 	usbser_st_mstart++;
2797 	if (pp->port_flags & USBSER_FL_TX_STOPPED) {
2798 		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2799 		pp->port_flags &= ~USBSER_FL_TX_STOPPED;
2800 
2801 		mutex_exit(&pp->port_mutex);
2802 		USBSER_DS_START(pp, DS_TX);
2803 		mutex_enter(&pp->port_mutex);
2804 		usbser_release_port_act(pp, USBSER_ACT_CTL);
2805 	}
2806 	freemsg(mp);
2807 }
2808 
2809 
2810 static void
2811 usbser_stopi(usbser_port_t *pp, mblk_t *mp)
2812 {
2813 	usbser_st_mstopi++;
2814 	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2815 	pp->port_flowc = pp->port_ttycommon.t_stopc;
2816 	usbser_inbound_flow_ctl(pp);
2817 	usbser_release_port_act(pp, USBSER_ACT_CTL);
2818 	freemsg(mp);
2819 }
2820 
2821 static void
2822 usbser_starti(usbser_port_t *pp, mblk_t *mp)
2823 {
2824 	usbser_st_mstarti++;
2825 	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2826 	pp->port_flowc = pp->port_ttycommon.t_startc;
2827 	usbser_inbound_flow_ctl(pp);
2828 	usbser_release_port_act(pp, USBSER_ACT_CTL);
2829 	freemsg(mp);
2830 }
2831 
2832 /*
2833  * process M_FLUSH message
2834  */
2835 static void
2836 usbser_flush(usbser_port_t *pp, mblk_t *mp)
2837 {
2838 	queue_t	*q = pp->port_ttycommon.t_writeq;
2839 
2840 	if (*mp->b_rptr & FLUSHW) {
2841 		mutex_exit(&pp->port_mutex);
2842 		(void) USBSER_DS_FIFO_FLUSH(pp, DS_TX);	/* flush FIFO buffers */
2843 		flushq(q, FLUSHDATA);			/* flush write queue */
2844 		mutex_enter(&pp->port_mutex);
2845 
2846 		usbser_release_port_act(pp, USBSER_ACT_TX);
2847 
2848 		*mp->b_rptr &= ~FLUSHW;
2849 	}
2850 	if (*mp->b_rptr & FLUSHR) {
2851 		/*
2852 		 * flush FIFO buffers
2853 		 */
2854 		mutex_exit(&pp->port_mutex);
2855 		(void) USBSER_DS_FIFO_FLUSH(pp, DS_RX);
2856 		flushq(RD(q), FLUSHDATA);
2857 		qreply(q, mp);
2858 		mutex_enter(&pp->port_mutex);
2859 	} else {
2860 		freemsg(mp);
2861 	}
2862 }
2863 
2864 /*
2865  * process M_BREAK message
2866  */
2867 static void
2868 usbser_break(usbser_port_t *pp, mblk_t *mp)
2869 {
2870 	int	rval;
2871 
2872 	/*
2873 	 * set the break and arrange for usbser_restart() to be called in 1/4 s
2874 	 */
2875 	mutex_exit(&pp->port_mutex);
2876 	rval = USBSER_DS_BREAK_CTL(pp, DS_ON);
2877 	mutex_enter(&pp->port_mutex);
2878 
2879 	if (rval == USB_SUCCESS) {
2880 		pp->port_act |= USBSER_ACT_BREAK;
2881 		pp->port_delay_id = timeout(usbser_restart, pp,
2882 						drv_usectohz(250000));
2883 	}
2884 	freemsg(mp);
2885 }
2886 
2887 
2888 /*
2889  * process M_DELAY message
2890  */
2891 static void
2892 usbser_delay(usbser_port_t *pp, mblk_t *mp)
2893 {
2894 	/*
2895 	 * arrange for usbser_restart() to be called when the delay expires
2896 	 */
2897 	pp->port_act |= USBSER_ACT_DELAY;
2898 	pp->port_delay_id = timeout(usbser_restart, pp,
2899 			(clock_t)(*(uchar_t *)mp->b_rptr + 6));
2900 	freemsg(mp);
2901 }
2902 
2903 
2904 /*
2905  * restart output on a line after a delay or break timer expired
2906  */
2907 static void
2908 usbser_restart(void *arg)
2909 {
2910 	usbser_port_t	*pp = (usbser_port_t *)arg;
2911 
2912 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_restart");
2913 
2914 	mutex_enter(&pp->port_mutex);
2915 	/* if cancelled, return immediately */
2916 	if (pp->port_delay_id == 0) {
2917 		mutex_exit(&pp->port_mutex);
2918 
2919 		return;
2920 	}
2921 	pp->port_delay_id = 0;
2922 
2923 	/* clear break if necessary */
2924 	if (pp->port_act & USBSER_ACT_BREAK) {
2925 		mutex_exit(&pp->port_mutex);
2926 		(void) USBSER_DS_BREAK_CTL(pp, DS_OFF);
2927 		mutex_enter(&pp->port_mutex);
2928 	}
2929 
2930 	usbser_release_port_act(pp, USBSER_ACT_BREAK | USBSER_ACT_DELAY);
2931 
2932 	/* wake wq thread to resume message processing */
2933 	usbser_thr_wake(&pp->port_wq_thread);
2934 	mutex_exit(&pp->port_mutex);
2935 }
2936 
2937 
2938 /*
2939  * program port hardware with the chosen parameters
2940  * most of the operation is based on the values of 'c_iflag' and 'c_cflag'
2941  */
2942 static int
2943 usbser_port_program(usbser_port_t *pp)
2944 {
2945 	tty_common_t		*tp = &pp->port_ttycommon;
2946 	int			baudrate;
2947 	int			c_flag;
2948 	ds_port_param_entry_t	pe[6];
2949 	ds_port_params_t	params;
2950 	int			flow_ctl, ctl_val;
2951 	int			err = 0;
2952 
2953 	baudrate = tp->t_cflag & CBAUD;
2954 	if (tp->t_cflag & CBAUDEXT) {
2955 		baudrate += 16;
2956 	}
2957 
2958 	/*
2959 	 * set input speed same as output, as split speed not supported
2960 	 */
2961 	if (tp->t_cflag & (CIBAUD|CIBAUDEXT)) {
2962 		tp->t_cflag &= ~(CIBAUD);
2963 		if (baudrate > CBAUD) {
2964 			tp->t_cflag |= CIBAUDEXT;
2965 			tp->t_cflag |=
2966 				(((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD);
2967 		} else {
2968 			tp->t_cflag &= ~CIBAUDEXT;
2969 			tp->t_cflag |= ((baudrate << IBSHIFT) & CIBAUD);
2970 		}
2971 	}
2972 
2973 	c_flag = tp->t_cflag;
2974 
2975 	/*
2976 	 * flow control
2977 	 */
2978 	flow_ctl = tp->t_iflag & (IXON | IXANY | IXOFF);
2979 	if (c_flag & CRTSCTS) {
2980 		flow_ctl |= CTSXON;
2981 	}
2982 	if (c_flag & CRTSXOFF) {
2983 		flow_ctl |= RTSXOFF;
2984 	}
2985 
2986 	/*
2987 	 * fill in port parameters we need to set:
2988 	 *
2989 	 * baud rate
2990 	 */
2991 	pe[0].param = DS_PARAM_BAUD;
2992 	pe[0].val.ui = baudrate;
2993 
2994 	/* stop bits */
2995 	pe[1].param = DS_PARAM_STOPB;
2996 	pe[1].val.ui = c_flag & CSTOPB;
2997 
2998 	/* parity */
2999 	pe[2].param = DS_PARAM_PARITY;
3000 	pe[2].val.ui = c_flag & (PARENB | PARODD);
3001 
3002 	/* char size */
3003 	pe[3].param = DS_PARAM_CHARSZ;
3004 	pe[3].val.ui = c_flag & CSIZE;
3005 
3006 	/* start & stop chars */
3007 	pe[4].param = DS_PARAM_XON_XOFF;
3008 	pe[4].val.uc[0] = tp->t_startc;
3009 	pe[4].val.uc[1] = tp->t_stopc;
3010 
3011 	/* flow control */
3012 	pe[5].param = DS_PARAM_FLOW_CTL;
3013 	pe[5].val.ui = flow_ctl;
3014 
3015 	params.tp_entries = &pe[0];
3016 	params.tp_cnt = 6;
3017 
3018 	/* control signals */
3019 	ctl_val = TIOCM_DTR | TIOCM_RTS;
3020 	if (baudrate == 0) {
3021 		ctl_val &= ~TIOCM_DTR;	/* zero baudrate means drop DTR */
3022 	}
3023 	if (pp->port_flags & USBSER_FL_RX_STOPPED) {
3024 		ctl_val &= ~TIOCM_RTS;
3025 	}
3026 
3027 	/* submit */
3028 	mutex_exit(&pp->port_mutex);
3029 	err = USBSER_DS_SET_PORT_PARAMS(pp, &params);
3030 	if (err != USB_SUCCESS) {
3031 		mutex_enter(&pp->port_mutex);
3032 
3033 		return (EINVAL);
3034 	}
3035 
3036 	err = USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR | TIOCM_RTS, ctl_val);
3037 	mutex_enter(&pp->port_mutex);
3038 
3039 	return ((err == USB_SUCCESS) ? 0 : EIO);
3040 }
3041 
3042 
3043 /*
3044  * check if any inbound flow control action needed
3045  */
3046 static void
3047 usbser_inbound_flow_ctl(usbser_port_t *pp)
3048 {
3049 	tcflag_t	need_hw;
3050 	int		rts;
3051 	char		c = pp->port_flowc;
3052 	mblk_t		*mp = NULL;
3053 
3054 	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
3055 	    "usbser_inbound_flow_ctl: c=%x cflag=%x port_flags=%x",
3056 	    c, pp->port_ttycommon.t_cflag, pp->port_flags);
3057 
3058 	if (c == '\0') {
3059 
3060 		return;
3061 	}
3062 	pp->port_flowc = '\0';
3063 
3064 	/*
3065 	 * if inbound hardware flow control enabled, we need to frob RTS
3066 	 */
3067 	need_hw = (pp->port_ttycommon.t_cflag & CRTSXOFF);
3068 	if (c == pp->port_ttycommon.t_startc) {
3069 		rts = TIOCM_RTS;
3070 		pp->port_flags &= ~USBSER_FL_RX_STOPPED;
3071 	} else {
3072 		rts = 0;
3073 		pp->port_flags |= USBSER_FL_RX_STOPPED;
3074 	}
3075 
3076 	/*
3077 	 * if character flow control active, transmit a start or stop char,
3078 	 */
3079 	if (pp->port_ttycommon.t_iflag & IXOFF) {
3080 		if ((mp = allocb(1, BPRI_LO)) == NULL) {
3081 			USB_DPRINTF_L2(DPRINT_WQ, pp->port_lh,
3082 			    "usbser_inbound_flow_ctl: allocb failed");
3083 		} else {
3084 			*mp->b_wptr++ = c;
3085 			pp->port_flags |= USBSER_ACT_TX;
3086 		}
3087 	}
3088 
3089 	mutex_exit(&pp->port_mutex);
3090 	if (need_hw) {
3091 		(void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_RTS, rts);
3092 	}
3093 	if (mp) {
3094 		(void) USBSER_DS_TX(pp, mp);
3095 	}
3096 	mutex_enter(&pp->port_mutex);
3097 }
3098 
3099 
3100 /*
3101  * misc
3102  * ----
3103  *
3104  *
3105  * returns !=0 if device is online, 0 otherwise
3106  */
3107 static int
3108 usbser_dev_is_online(usbser_state_t *usp)
3109 {
3110 	int	rval;
3111 
3112 	mutex_enter(&usp->us_mutex);
3113 	rval = (usp->us_dev_state == USB_DEV_ONLINE);
3114 	mutex_exit(&usp->us_mutex);
3115 
3116 	return (rval);
3117 }
3118 
3119 /*
3120  * serialize port activities defined by 'act' mask
3121  */
3122 static void
3123 usbser_serialize_port_act(usbser_port_t *pp, int act)
3124 {
3125 	while (pp->port_act & act) {
3126 		cv_wait(&pp->port_act_cv, &pp->port_mutex);
3127 	}
3128 
3129 	pp->port_act |= act;
3130 }
3131 
3132 
3133 /*
3134  * indicate that port activity is finished
3135  */
3136 static void
3137 usbser_release_port_act(usbser_port_t *pp, int act)
3138 {
3139 	pp->port_act &= ~act;
3140 	cv_broadcast(&pp->port_act_cv);
3141 }
3142 
3143 
3144 /*
3145  * message type to string and back conversion.
3146  *
3147  * pardon breaks on the same line, but as long as cstyle doesn't
3148  * complain, I'd like to keep this form for trivial cases like this.
3149  * associative arrays in the kernel, anyone?
3150  */
3151 static char *
3152 usbser_msgtype2str(int type)
3153 {
3154 	char	*str;
3155 
3156 	switch (type) {
3157 	case M_STOP:	str = "M_STOP";		break;
3158 	case M_START:	str = "M_START";	break;
3159 	case M_STOPI:	str = "M_STOPI";	break;
3160 	case M_STARTI:	str = "M_STARTI";	break;
3161 	case M_DATA:	str = "M_DATA";		break;
3162 	case M_DELAY:	str = "M_DELAY";	break;
3163 	case M_BREAK:	str = "M_BREAK";	break;
3164 	case M_IOCTL:	str = "M_IOCTL";	break;
3165 	case M_IOCDATA:	str = "M_IOCDATA";	break;
3166 	case M_FLUSH:	str = "M_FLUSH";	break;
3167 	case M_CTL:	str = "M_CTL";		break;
3168 	case M_READ:	str = "M_READ";		break;
3169 	default:	str = "unknown";	break;
3170 	}
3171 
3172 	return (str);
3173 }
3174 
3175 
3176 static char *
3177 usbser_ioctl2str(int ioctl)
3178 {
3179 	char	*str;
3180 
3181 	switch (ioctl) {
3182 	case TCGETA:	str = "TCGETA";		break;
3183 	case TCSETA:	str = "TCSETA";		break;
3184 	case TCSETAF:	str = "TCSETAF";	break;
3185 	case TCSETAW:	str = "TCSETAW";	break;
3186 	case TCSBRK:	str = "TCSBRK";		break;
3187 	case TCXONC:	str = "TCXONC";		break;
3188 	case TCFLSH:	str = "TCFLSH";		break;
3189 	case TCGETS:	str = "TCGETS";		break;
3190 	case TCSETS:	str = "TCSETS";		break;
3191 	case TCSETSF:	str = "TCSETSF";	break;
3192 	case TCSETSW:	str = "TCSETSW";	break;
3193 	case TIOCSBRK:	str = "TIOCSBRK";	break;
3194 	case TIOCCBRK:	str = "TIOCCBRK";	break;
3195 	case TIOCMSET:	str = "TIOCMSET";	break;
3196 	case TIOCMBIS:	str = "TIOCMBIS";	break;
3197 	case TIOCMBIC:	str = "TIOCMBIC";	break;
3198 	case TIOCMGET:	str = "TIOCMGET";	break;
3199 	case (tIOC | 109): str = "TIOCSILOOP";	break;
3200 	case (tIOC | 108): str = "TIOCCILOOP";	break;
3201 	case TCGETX:	str = "TCGETX";		break;
3202 	case TCSETX:	str = "TCGETX";		break;
3203 	case TCSETXW:	str = "TCGETX";		break;
3204 	case TCSETXF:	str = "TCGETX";		break;
3205 	default:	str = "unknown";	break;
3206 	}
3207 
3208 	return (str);
3209 }
3210