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