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