usbser.c revision 10481:5edad2f503c3
1162413Ssam/*
2178354Ssam * CDDL HEADER START
3162413Ssam *
4162413Ssam * The contents of this file are subject to the terms of the
5162413Ssam * Common Development and Distribution License (the "License").
6162413Ssam * You may not use this file except in compliance with the License.
7162413Ssam *
8162413Ssam * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9162413Ssam * or http://www.opensolaris.org/os/licensing.
10162413Ssam * See the License for the specific language governing permissions
11162413Ssam * and limitations under the License.
12162413Ssam *
13162413Ssam * When distributing Covered Code, include this CDDL HEADER in each
14162413Ssam * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15162413Ssam * If applicable, add the following below this CDDL HEADER, with the
16162413Ssam * fields enclosed by brackets "[]" replaced with your own identifying
17162413Ssam * information: Portions Copyright [yyyy] [name of copyright owner]
18162413Ssam *
19162413Ssam * CDDL HEADER END
20162413Ssam */
21162413Ssam/*
22162413Ssam * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23162413Ssam * Use is subject to license terms.
24162413Ssam */
25162413Ssam
26162413Ssam
27162413Ssam/*
28162413Ssam *
29162413Ssam * USB generic serial driver (GSD)
30162413Ssam *
31162413Ssam */
32162413Ssam#include <sys/types.h>
33162413Ssam#include <sys/param.h>
34162413Ssam#include <sys/stream.h>
35162413Ssam#include <sys/stropts.h>
36162413Ssam#include <sys/errno.h>
37162413Ssam#include <sys/cred.h>
38162413Ssam#include <sys/conf.h>
39162413Ssam#include <sys/stat.h>
40162413Ssam#include <sys/modctl.h>
41162413Ssam#include <sys/ddi.h>
42162413Ssam#include <sys/sunddi.h>
43162413Ssam#include <sys/sunndi.h>
44162413Ssam#include <sys/termio.h>
45162413Ssam#include <sys/termiox.h>
46185522Ssam#include <sys/stropts.h>
47162413Ssam#include <sys/stream.h>
48162413Ssam#include <sys/strsubr.h>
49162413Ssam#include <sys/strsun.h>
50162413Ssam#include <sys/strtty.h>
51162413Ssam#include <sys/policy.h>
52162413Ssam#include <sys/consdev.h>
53162413Ssam
54162413Ssam#include <sys/usb/usba.h>
55162413Ssam#include <sys/usb/clients/usbser/usbser_var.h>
56162413Ssam#include <sys/usb/clients/usbser/usbser_dsdi.h>
57162413Ssam#include <sys/usb/clients/usbser/usbser_rseq.h>
58162413Ssam#include <sys/usb/usba/genconsole.h>
59185522Ssam
60162413Ssam/* autoconfiguration subroutines */
61162413Ssamstatic int	usbser_rseq_do_cb(rseq_t *, int, uintptr_t);
62162413Ssamstatic int	usbser_free_soft_state(usbser_state_t *);
63162413Ssamstatic int	usbser_init_soft_state(usbser_state_t *);
64162413Ssamstatic int	usbser_fini_soft_state(usbser_state_t *);
65162413Ssamstatic int	usbser_attach_dev(usbser_state_t *);
66162413Ssamstatic void	usbser_detach_dev(usbser_state_t *);
67162413Ssamstatic int	usbser_attach_ports(usbser_state_t *);
68162413Ssamstatic int	usbser_create_port_minor_nodes(usbser_state_t *, int);
69162413Ssamstatic void	usbser_detach_ports(usbser_state_t *);
70162413Ssamstatic int	usbser_create_taskq(usbser_state_t *);
71162413Ssamstatic void	usbser_destroy_taskq(usbser_state_t *);
72162413Ssamstatic void	usbser_set_dev_state_init(usbser_state_t *);
73162413Ssam
74219315Sadrian/* hotplugging and power management */
75162413Ssamstatic int	usbser_disconnect_cb(dev_info_t *);
76162413Ssamstatic int	usbser_reconnect_cb(dev_info_t *);
77162413Ssamstatic void	usbser_disconnect_ports(usbser_state_t *);
78162413Ssamstatic int	usbser_cpr_suspend(dev_info_t *);
79162413Ssamstatic int	usbser_suspend_ports(usbser_state_t *);
80162413Ssamstatic void	usbser_cpr_resume(dev_info_t *);
81162413Ssamstatic int	usbser_restore_device_state(usbser_state_t *);
82219315Sadrianstatic void	usbser_restore_ports_state(usbser_state_t *);
83162413Ssam
84162413Ssam/* STREAMS subroutines */
85162413Ssamstatic int	usbser_open_setup(queue_t *, usbser_port_t *, int, int,
86162413Ssam		cred_t *);
87162413Ssamstatic int	usbser_open_init(usbser_port_t *, int);
88219942Sadrianstatic void	usbser_check_port_props(usbser_port_t *);
89219942Sadrianstatic void	usbser_open_fini(usbser_port_t *);
90219942Sadrianstatic int	usbser_open_line_setup(usbser_port_t *, int, int);
91219942Sadrianstatic int	usbser_open_carrier_check(usbser_port_t *, int, int);
92219942Sadrianstatic void	usbser_open_queues_init(usbser_port_t *, queue_t *);
93162413Ssamstatic void	usbser_open_queues_fini(usbser_port_t *);
94162413Ssamstatic void	usbser_close_drain(usbser_port_t *);
95162413Ssamstatic void	usbser_close_cancel_break(usbser_port_t *);
96162413Ssamstatic void	usbser_close_hangup(usbser_port_t *);
97162413Ssamstatic void	usbser_close_cleanup(usbser_port_t *);
98162413Ssam
99162413Ssam/* threads */
100162413Ssamstatic void	usbser_thr_dispatch(usbser_thread_t *);
101162413Ssamstatic void	usbser_thr_cancel(usbser_thread_t *);
102162413Ssamstatic void	usbser_thr_wake(usbser_thread_t *);
103162413Ssamstatic void	usbser_wq_thread(void *);
104162413Ssamstatic void	usbser_rq_thread(void *);
105162413Ssam
106162413Ssam/* DSD callbacks */
107162413Ssamstatic void	usbser_tx_cb(caddr_t);
108162413Ssamstatic void	usbser_rx_cb(caddr_t);
109162413Ssamstatic void	usbser_rx_massage_data(usbser_port_t *, mblk_t *);
110162413Ssamstatic void	usbser_rx_massage_mbreak(usbser_port_t *, mblk_t *);
111162413Ssamstatic void	usbser_rx_cb_put(usbser_port_t *, queue_t *, queue_t *,
112162413Ssam		mblk_t *);
113162413Ssamstatic void	usbser_status_cb(caddr_t);
114162413Ssamstatic void	usbser_status_proc_cb(usbser_port_t *);
115162413Ssam
116162413Ssam/* serial support */
117162413Ssamstatic void	usbser_wmsg(usbser_port_t *);
118196935Ssamstatic int	usbser_data(usbser_port_t *, mblk_t *);
119162413Ssamstatic int	usbser_ioctl(usbser_port_t *, mblk_t *);
120162413Ssamstatic void	usbser_iocdata(usbser_port_t *, mblk_t *);
121162413Ssamstatic void	usbser_stop(usbser_port_t *, mblk_t *);
122162413Ssamstatic void	usbser_start(usbser_port_t *, mblk_t *);
123162413Ssamstatic void	usbser_stopi(usbser_port_t *, mblk_t *);
124162413Ssamstatic void	usbser_starti(usbser_port_t *, mblk_t *);
125162413Ssamstatic void	usbser_flush(usbser_port_t *, mblk_t *);
126162413Ssamstatic void	usbser_break(usbser_port_t *, mblk_t *);
127162413Ssamstatic void	usbser_delay(usbser_port_t *, mblk_t *);
128162413Ssamstatic void	usbser_restart(void *);
129162413Ssamstatic int	usbser_port_program(usbser_port_t *);
130162413Ssamstatic void	usbser_inbound_flow_ctl(usbser_port_t *);
131162413Ssam
132162413Ssam/* misc */
133162413Ssamstatic int	usbser_dev_is_online(usbser_state_t *);
134162413Ssamstatic void	usbser_serialize_port_act(usbser_port_t *, int);
135162413Ssamstatic void	usbser_release_port_act(usbser_port_t *, int);
136162413Ssamstatic char	*usbser_msgtype2str(int);
137162413Ssamstatic char	*usbser_ioctl2str(int);
138162413Ssam
139162413Ssam
140162413Ssam/* USBA events */
141162413Ssamusb_event_t usbser_usb_events = {
142162413Ssam	usbser_disconnect_cb,	/* disconnect */
143162413Ssam	usbser_reconnect_cb,	/* reconnect */
144219315Sadrian	NULL,			/* pre-suspend */
145184369Ssam	NULL,			/* pre-resume */
146184369Ssam};
147184369Ssam
148184369Ssam/* debug support */
149184369Ssamuint_t	 usbser_errlevel = USB_LOG_L4;
150184369Ssamuint_t	 usbser_errmask = DPRINT_MASK_ALL;
151184369Ssamuint_t	 usbser_instance_debug = (uint_t)-1;
152184369Ssam
153162413Ssam/* usb serial console */
154162413Ssamstatic struct usbser_state *usbser_list;
155162413Ssamstatic kmutex_t usbser_lock;
156162413Ssamstatic int usbser_console_abort;
157162413Ssamstatic usb_console_info_t console_input, console_output;
158162413Ssamstatic uchar_t *console_input_buf;
159162413Ssamstatic uchar_t *console_input_start, *console_input_end;
160162413Ssam
161162413Ssam_NOTE(SCHEME_PROTECTS_DATA("unshared", usbser_console_abort))
162162413Ssam_NOTE(SCHEME_PROTECTS_DATA("unshared", console_input))
163162413Ssam_NOTE(SCHEME_PROTECTS_DATA("unshared", console_output))
164162413Ssam_NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_start))
165162413Ssam_NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_end))
166162413Ssam
167162413Ssamstatic void usbser_putchar(cons_polledio_arg_t, uchar_t);
168162413Ssamstatic int usbser_getchar(cons_polledio_arg_t);
169162413Ssamstatic boolean_t usbser_ischar(cons_polledio_arg_t);
170162413Ssamstatic void usbser_polledio_enter(cons_polledio_arg_t);
171185522Ssamstatic void usbser_polledio_exit(cons_polledio_arg_t);
172162413Ssamstatic int usbser_polledio_init(usbser_port_t *);
173162413Ssamstatic void usbser_polledio_fini(usbser_port_t *);
174162413Ssam
175162413Ssamstatic struct cons_polledio usbser_polledio = {
176162413Ssam	CONSPOLLEDIO_V1,
177162413Ssam	NULL,	/* to be set later */
178162413Ssam	usbser_putchar,
179162413Ssam	usbser_getchar,
180162413Ssam	usbser_ischar,
181162413Ssam	usbser_polledio_enter,
182162413Ssam	usbser_polledio_exit
183162413Ssam};
184162413Ssam
185168589Srwatson/* various statistics. TODO: replace with kstats */
186168589Srwatsonstatic int usbser_st_tx_data_loss = 0;
187168589Srwatsonstatic int usbser_st_rx_data_loss = 0;
188168589Srwatsonstatic int usbser_st_put_stopi = 0;
189168589Srwatsonstatic int usbser_st_mstop = 0;
190168589Srwatsonstatic int usbser_st_mstart = 0;
191168589Srwatsonstatic int usbser_st_mstopi = 0;
192162413Ssamstatic int usbser_st_mstarti = 0;
193162413Ssamstatic int usbser_st_rsrv = 0;
194162413Ssam_NOTE(SCHEME_PROTECTS_DATA("monotonic stats", usbser_st_{
195162413Ssam	tx_data_loss rx_data_loss put_stopi mstop mstart mstopi mstarti rsrv}))
196162413Ssam_NOTE(SCHEME_PROTECTS_DATA("unshared", usb_bulk_req_t))
197162413Ssam_NOTE(SCHEME_PROTECTS_DATA("unshared", usb_intr_req_t))
198162413Ssam
199162413Ssam/* taskq parameter */
200162413Ssamextern pri_t minclsyspri;
201162413Ssam
202162413Ssam/*
203162413Ssam * tell warlock not to worry about STREAMS structures
204162413Ssam */
205162413Ssam_NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk datab msgb queue copyreq))
206162413Ssam
207162413Ssam/*
208162413Ssam * modload support
209162413Ssam */
210162413Ssamextern struct mod_ops mod_miscops;
211162413Ssam
212162413Ssamstatic struct modlmisc modlmisc = {
213162413Ssam	&mod_miscops,	/* Type of module */
214162413Ssam	"USB generic serial module"
215162413Ssam};
216162413Ssam
217162413Ssamstatic struct modlinkage modlinkage = {
218162413Ssam	MODREV_1, (void *)&modlmisc, NULL
219162413Ssam};
220162413Ssam
221162413Ssam
222162413Ssam#define	RSEQ(f1, f2) RSEQE(f1, usbser_rseq_do_cb, f2, NULL)
223162413Ssam
224162413Ssam
225162413Ssam/*
226162413Ssam * loadable module entry points
227162413Ssam * ----------------------------
228162413Ssam */
229162413Ssam
230162413Ssamint
231162413Ssam_init(void)
232162413Ssam{
233162413Ssam	int err;
234162413Ssam
235162413Ssam	mutex_init(&usbser_lock, NULL, MUTEX_DRIVER, (void *)NULL);
236162413Ssam	if (err = mod_install(&modlinkage))
237162413Ssam		mutex_destroy(&usbser_lock);
238162413Ssam
239162413Ssam	return (err);
240162413Ssam}
241162413Ssam
242162413Ssam
243162413Ssamint
244162413Ssam_fini(void)
245162413Ssam{
246162413Ssam	int err;
247162413Ssam
248162413Ssam	if (err = mod_remove(&modlinkage))
249185522Ssam
250162413Ssam		return (err);
251162413Ssam
252162413Ssam	mutex_destroy(&usbser_lock);
253162413Ssam
254162413Ssam	return (0);
255162413Ssam}
256162413Ssam
257162413Ssam
258162413Ssamint
259162413Ssam_info(struct modinfo *modinfop)
260162413Ssam{
261162413Ssam	return (mod_info(&modlinkage, modinfop));
262195418Ssam}
263162413Ssam
264162413Ssam
265162413Ssam/*
266162413Ssam * soft state size
267162413Ssam */
268162413Ssamint
269162413Ssamusbser_soft_state_size()
270162413Ssam{
271162413Ssam	return (sizeof (usbser_state_t));
272162413Ssam}
273185522Ssam
274162413Ssam
275162413Ssam/*
276162413Ssam * autoconfiguration entry points
277195418Ssam * ------------------------------
278162413Ssam */
279162413Ssam
280162413Ssam/*ARGSUSED*/
281162413Ssamint
282162413Ssamusbser_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
283162413Ssam		void **result, void *statep)
284162413Ssam{
285162413Ssam	int		instance;
286162413Ssam	int		ret = DDI_FAILURE;
287162413Ssam	usbser_state_t	*usbserp;
288162413Ssam
289162413Ssam	instance = USBSER_MINOR2INST(getminor((dev_t)arg));
290162413Ssam
291162413Ssam	switch (infocmd) {
292162413Ssam	case DDI_INFO_DEVT2DEVINFO:
293162413Ssam		*result = NULL;
294162413Ssam		usbserp = ddi_get_soft_state(statep, instance);
295162413Ssam		if (usbserp != NULL) {
296162413Ssam			*result = usbserp->us_dip;
297162413Ssam			if (*result != NULL) {
298162413Ssam				ret = DDI_SUCCESS;
299162413Ssam			}
300162413Ssam		}
301162413Ssam
302162413Ssam		break;
303162413Ssam	case DDI_INFO_DEVT2INSTANCE:
304162413Ssam		*result = (void *)(uintptr_t)instance;
305162413Ssam		ret = DDI_SUCCESS;
306162413Ssam
307162413Ssam		break;
308162413Ssam	default:
309162413Ssam		break;
310162413Ssam	}
311162413Ssam
312162413Ssam	return (ret);
313162413Ssam}
314162413Ssam
315162413Ssam/*
316162413Ssam * device attach
317162413Ssam */
318162413Ssamstatic rseq_t rseq_att[] = {
319162413Ssam	RSEQ(NULL,			usbser_free_soft_state),
320162413Ssam	RSEQ(usbser_init_soft_state,	usbser_fini_soft_state),
321162413Ssam	RSEQ(usbser_attach_dev,		usbser_detach_dev),
322162413Ssam	RSEQ(usbser_attach_ports,	usbser_detach_ports),
323162413Ssam	RSEQ(usbser_create_taskq,	usbser_destroy_taskq),
324162413Ssam	RSEQ(NULL,			usbser_set_dev_state_init)
325185522Ssam};
326162413Ssam
327162413Ssamstatic void
328195418Ssamusbser_insert(struct usbser_state *usp)
329162413Ssam{
330162413Ssam	struct usbser_state *tmp;
331162413Ssam
332162413Ssam	mutex_enter(&usbser_lock);
333162413Ssam	tmp = usbser_list;
334162413Ssam	if (tmp == NULL)
335162413Ssam		usbser_list = usp;
336162413Ssam	else {
337162413Ssam		while (tmp->us_next)
338162413Ssam			tmp = tmp->us_next;
339185522Ssam		tmp->us_next = usp;
340162413Ssam	}
341162413Ssam	mutex_exit(&usbser_lock);
342162413Ssam}
343195418Ssam
344162413Ssamstatic void
345162413Ssamusbser_remove(struct usbser_state *usp)
346162413Ssam{
347162413Ssam	struct usbser_state *tmp, *prev = NULL;
348162413Ssam
349162413Ssam	mutex_enter(&usbser_lock);
350162413Ssam	tmp = usbser_list;
351162413Ssam	while (tmp != usp) {
352162413Ssam		prev = tmp;
353162413Ssam		tmp = tmp->us_next;
354162413Ssam	}
355162413Ssam	ASSERT(tmp == usp);	/* must exist, else attach/detach wrong */
356162413Ssam	if (prev)
357162413Ssam		prev->us_next = usp->us_next;
358162413Ssam	else
359162413Ssam		usbser_list = usp->us_next;
360162413Ssam	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	/*
2046	 * as long as port access is ok and the port is not busy on
2047	 * TX, break, ctrl or delay, the wq_thread should be waken
2048	 * to do further process for next message
2049	 */
2050	if (online && USBSER_PORT_ACCESS_OK(pp) &&
2051	    !USBSER_PORT_IS_BUSY_NON_RX(pp)) {
2052		/*
2053		 * wake wq thread for further data/ioctl processing
2054		 */
2055		usbser_thr_wake(&pp->port_wq_thread);
2056	}
2057	mutex_exit(&pp->port_mutex);
2058}
2059
2060
2061/*
2062 * receive callback
2063 *
2064 * invoked by DSD when there is more data for us to pick
2065 */
2066static void
2067usbser_rx_cb(caddr_t arg)
2068{
2069	usbser_port_t	*pp = (usbser_port_t *)arg;
2070	queue_t		*rq, *wq;
2071	mblk_t		*mp;		/* current mblk */
2072	mblk_t		*data, *data_tail; /* M_DATA mblk list and its tail */
2073	mblk_t		*emp;		/* error (M_BREAK) mblk */
2074
2075	USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh, "usbser_rx_cb");
2076
2077	if (!usbser_dev_is_online(pp->port_usp)) {
2078
2079		return;
2080	}
2081
2082	/* get data from DSD */
2083	if ((mp = USBSER_DS_RX(pp)) == NULL) {
2084
2085		return;
2086	}
2087
2088	mutex_enter(&pp->port_mutex);
2089	if ((!USBSER_PORT_ACCESS_OK(pp)) ||
2090	    ((pp->port_ttycommon.t_cflag & CREAD) == 0)) {
2091		freemsg(mp);
2092		mutex_exit(&pp->port_mutex);
2093		USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
2094		    "usbser_rx_cb: access not ok or receiver disabled");
2095
2096		return;
2097	}
2098
2099	usbser_serialize_port_act(pp, USBSER_ACT_RX);
2100
2101	rq = pp->port_ttycommon.t_readq;
2102	wq = pp->port_ttycommon.t_writeq;
2103	mutex_exit(&pp->port_mutex);
2104
2105	/*
2106	 * DSD data is a b_cont-linked list of M_DATA and M_BREAK blocks.
2107	 * M_DATA is correctly received data.
2108	 * M_BREAK is a character with either framing or parity error.
2109	 *
2110	 * this loop runs through the list of mblks. when it meets an M_BREAK,
2111	 * it sends all leading M_DATA's in one shot, then sends M_BREAK.
2112	 * in the trivial case when list contains only M_DATA's, the loop
2113	 * does nothing but set data variable.
2114	 */
2115	data = data_tail = NULL;
2116	while (mp) {
2117		/*
2118		 * skip data until we meet M_BREAK or end of list
2119		 */
2120		if (DB_TYPE(mp) == M_DATA) {
2121			if (data == NULL) {
2122				data = mp;
2123			}
2124			data_tail = mp;
2125			mp = mp->b_cont;
2126
2127			continue;
2128		}
2129
2130		/* detach data list from mp */
2131		if (data_tail) {
2132			data_tail->b_cont = NULL;
2133		}
2134		/* detach emp from the list */
2135		emp = mp;
2136		mp = mp->b_cont;
2137		emp->b_cont = NULL;
2138
2139		/* DSD shouldn't send anything but M_DATA or M_BREAK */
2140		if ((DB_TYPE(emp) != M_BREAK) || (MBLKL(emp) != 2)) {
2141			freemsg(emp);
2142			USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
2143			    "usbser_rx_cb: bad message");
2144
2145			continue;
2146		}
2147
2148		/*
2149		 * first tweak and send M_DATA's
2150		 */
2151		if (data) {
2152			usbser_rx_massage_data(pp, data);
2153			usbser_rx_cb_put(pp, rq, wq, data);
2154			data = data_tail = NULL;
2155		}
2156
2157		/*
2158		 * now tweak and send M_BREAK
2159		 */
2160		mutex_enter(&pp->port_mutex);
2161		usbser_rx_massage_mbreak(pp, emp);
2162		mutex_exit(&pp->port_mutex);
2163		usbser_rx_cb_put(pp, rq, wq, emp);
2164	}
2165
2166	/* send the rest of the data, if any */
2167	if (data) {
2168		usbser_rx_massage_data(pp, data);
2169		usbser_rx_cb_put(pp, rq, wq, data);
2170	}
2171
2172	mutex_enter(&pp->port_mutex);
2173	usbser_release_port_act(pp, USBSER_ACT_RX);
2174	mutex_exit(&pp->port_mutex);
2175}
2176
2177/*
2178 * the joys of termio -- this is to accomodate Unix98 assertion:
2179 *
2180 *   If PARENB is supported and is set, when PARMRK is set, and CSIZE is
2181 *   set to CS8, and IGNPAR is clear, and ISTRIP is clear, a valid
2182 *   character of '\377' is read as '\377', '\377'.
2183 *
2184 *   Posix Ref: Assertion 7.1.2.2-16(C)
2185 *
2186 * this requires the driver to scan every incoming valid character
2187 */
2188static void
2189usbser_rx_massage_data(usbser_port_t *pp, mblk_t *mp)
2190{
2191	tty_common_t	*tp = &pp->port_ttycommon;
2192	uchar_t		*p;
2193	mblk_t		*newmp;
2194	int		tailsz;
2195
2196	/* avoid scanning if possible */
2197	mutex_enter(&pp->port_mutex);
2198	if (!((tp->t_cflag & PARENB) && (tp->t_iflag & PARMRK) &&
2199	    ((tp->t_cflag & CSIZE) == CS8) &&
2200	    ((tp->t_iflag & (IGNPAR|ISTRIP)) == 0))) {
2201		mutex_exit(&pp->port_mutex);
2202
2203		return;
2204	}
2205	mutex_exit(&pp->port_mutex);
2206
2207	while (mp) {
2208		for (p = mp->b_rptr; p < mp->b_wptr; ) {
2209			if (*p++ != 0377) {
2210
2211				continue;
2212			}
2213			USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
2214			    "usbser_rx_massage_data: mp=%p off=%ld(%ld)",
2215			    (void *)mp, _PTRDIFF(p,  mp->b_rptr) - 1,
2216			    (long)MBLKL(mp));
2217
2218			/*
2219			 * insert another 0377 after this one. all data after
2220			 * the original 0377 have to be copied to the new mblk
2221			 */
2222			tailsz = _PTRDIFF(mp->b_wptr, p);
2223			if ((newmp = allocb(tailsz + 1, BPRI_HI)) == NULL) {
2224				USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
2225				    "usbser_rx_massage_data: allocb failed");
2226
2227				continue;
2228			}
2229
2230			/* fill in the new mblk */
2231			*newmp->b_wptr++ = 0377;
2232			if (tailsz > 0) {
2233				bcopy(p, newmp->b_wptr, tailsz);
2234				newmp->b_wptr += tailsz;
2235			}
2236			/* shrink the original mblk */
2237			mp->b_wptr = p;
2238
2239			newmp->b_cont = mp->b_cont;
2240			mp->b_cont = newmp;
2241			p = newmp->b_rptr + 1;
2242			mp = newmp;
2243		}
2244		mp = mp->b_cont;
2245	}
2246}
2247
2248/*
2249 * more joys of termio
2250 */
2251static void
2252usbser_rx_massage_mbreak(usbser_port_t *pp, mblk_t *mp)
2253{
2254	tty_common_t	*tp = &pp->port_ttycommon;
2255	uchar_t		err, c;
2256
2257	err = *mp->b_rptr;
2258	c = *(mp->b_rptr + 1);
2259
2260	if ((err & (DS_FRAMING_ERR | DS_BREAK_ERR)) && (c == 0)) {
2261		/* break */
2262		mp->b_rptr += 2;
2263	} else if (!(tp->t_iflag & INPCK) && (err & (DS_PARITY_ERR))) {
2264		/* Posix Ref: Assertion 7.1.2.2-20(C) */
2265		mp->b_rptr++;
2266		DB_TYPE(mp) = M_DATA;
2267	} else {
2268		/* for ldterm to handle */
2269		mp->b_rptr++;
2270	}
2271
2272	USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
2273	    "usbser_rx_massage_mbreak: type=%x len=%ld [0]=0%o",
2274	    DB_TYPE(mp), (long)MBLKL(mp), (MBLKL(mp) > 0) ? *mp->b_rptr : 45);
2275}
2276
2277
2278/*
2279 * in rx callback, try to send an mblk upstream
2280 */
2281static void
2282usbser_rx_cb_put(usbser_port_t *pp, queue_t *rq, queue_t *wq, mblk_t *mp)
2283{
2284	if (canputnext(rq)) {
2285		putnext(rq, mp);
2286	} else if (canput(rq) && putq(rq, mp)) {
2287		/*
2288		 * full queue indicates the need for inbound flow control
2289		 */
2290		(void) putctl(wq, M_STOPI);
2291		usbser_st_put_stopi++;
2292
2293		USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
2294		    "usbser_rx_cb: cannot putnext, flow ctl");
2295	} else {
2296		freemsg(mp);
2297		usbser_st_rx_data_loss++;
2298		(void) putctl(wq, M_STOPI);
2299		usbser_st_put_stopi++;
2300
2301		USB_DPRINTF_L1(DPRINT_RX_CB, pp->port_lh,
2302		    "input overrun");
2303	}
2304}
2305
2306
2307/*
2308 * modem status change callback
2309 *
2310 * each time external status lines are changed, DSD calls this routine
2311 */
2312static void
2313usbser_status_cb(caddr_t arg)
2314{
2315	usbser_port_t	*pp = (usbser_port_t *)arg;
2316
2317	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_cb");
2318
2319	if (!usbser_dev_is_online(pp->port_usp)) {
2320
2321		return;
2322	}
2323
2324	/*
2325	 * actual processing will be done in usbser_status_proc_cb()
2326	 * running in wq thread
2327	 */
2328	mutex_enter(&pp->port_mutex);
2329	if (USBSER_PORT_ACCESS_OK(pp) || USBSER_IS_OPENING(pp)) {
2330		pp->port_flags |= USBSER_FL_STATUS_CB;
2331		usbser_thr_wake(&pp->port_wq_thread);
2332	}
2333	mutex_exit(&pp->port_mutex);
2334}
2335
2336
2337/*
2338 * modem status change
2339 */
2340static void
2341usbser_status_proc_cb(usbser_port_t *pp)
2342{
2343	tty_common_t	*tp = &pp->port_ttycommon;
2344	queue_t		*rq, *wq;
2345	int		status;
2346	int		drop_dtr = 0;
2347	int		rq_msg = 0, wq_msg = 0;
2348
2349	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_proc_cb");
2350
2351	pp->port_flags &= ~USBSER_FL_STATUS_CB;
2352
2353	mutex_exit(&pp->port_mutex);
2354	if (!usbser_dev_is_online(pp->port_usp)) {
2355		mutex_enter(&pp->port_mutex);
2356
2357		return;
2358	}
2359
2360	/* get modem status */
2361	if (USBSER_DS_GET_MODEM_CTL(pp, -1, &status) != USB_SUCCESS) {
2362		mutex_enter(&pp->port_mutex);
2363
2364		return;
2365	}
2366
2367	mutex_enter(&pp->port_mutex);
2368	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2369
2370	rq = pp->port_ttycommon.t_readq;
2371	wq = pp->port_ttycommon.t_writeq;
2372
2373	/*
2374	 * outbound flow control
2375	 */
2376	if (tp->t_cflag & CRTSCTS) {
2377		if (!(status & TIOCM_CTS)) {
2378			/*
2379			 * CTS dropped, stop xmit
2380			 */
2381			if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
2382				wq_msg = M_STOP;
2383			}
2384		} else if (pp->port_flags & USBSER_FL_TX_STOPPED) {
2385			/*
2386			 * CTS raised, resume xmit
2387			 */
2388			wq_msg = M_START;
2389		}
2390	}
2391
2392	/*
2393	 * check carrier
2394	 */
2395	if ((status & TIOCM_CD) || (tp->t_flags & TS_SOFTCAR)) {
2396		/*
2397		 * carrier present
2398		 */
2399		if ((pp->port_flags & USBSER_FL_CARR_ON) == 0) {
2400			pp->port_flags |= USBSER_FL_CARR_ON;
2401
2402			rq_msg = M_UNHANGUP;
2403			/*
2404			 * wake open
2405			 */
2406			if (pp->port_flags & USBSER_FL_WOPEN) {
2407				cv_broadcast(&pp->port_car_cv);
2408			}
2409
2410			USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2411			    "usbser_status_cb: carr on");
2412		}
2413	} else if (pp->port_flags & USBSER_FL_CARR_ON) {
2414		pp->port_flags &= ~USBSER_FL_CARR_ON;
2415		/*
2416		 * carrier went away: if not local line, drop DTR
2417		 */
2418		if (!(tp->t_cflag & CLOCAL)) {
2419			drop_dtr = 1;
2420			rq_msg = M_HANGUP;
2421		}
2422		if ((pp->port_flags & USBSER_FL_TX_STOPPED) && (wq_msg == 0)) {
2423			wq_msg = M_START;
2424		}
2425
2426		USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2427		    "usbser_status_cb: carr off");
2428	}
2429	mutex_exit(&pp->port_mutex);
2430
2431	USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2432	    "usbser_status_cb: rq_msg=%d wq_msg=%d", rq_msg, wq_msg);
2433
2434	/*
2435	 * commit postponed actions now
2436	 * do so only if port is fully open (queues are enabled)
2437	 */
2438	if (rq) {
2439		if (rq_msg) {
2440			(void) putnextctl(rq, rq_msg);
2441		}
2442		if (drop_dtr) {
2443			(void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR, 0);
2444		}
2445		if (wq_msg) {
2446			(void) putctl(wq, wq_msg);
2447		}
2448	}
2449
2450	mutex_enter(&pp->port_mutex);
2451	usbser_release_port_act(pp, USBSER_ACT_CTL);
2452}
2453
2454
2455/*
2456 * serial support
2457 * --------------
2458 *
2459 *
2460 * this routine is run by wq thread every time it's woken,
2461 * i.e. when the queue contains messages to process
2462 */
2463static void
2464usbser_wmsg(usbser_port_t *pp)
2465{
2466	queue_t		*q = pp->port_ttycommon.t_writeq;
2467	mblk_t		*mp;
2468	int		msgtype;
2469
2470	ASSERT(mutex_owned(&pp->port_mutex));
2471
2472	if (q == NULL) {
2473		USB_DPRINTF_L3(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=NULL");
2474
2475		return;
2476	}
2477	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=%p act=%x 0x%x",
2478	    (void *)q, pp->port_act, q->q_first ? DB_TYPE(q->q_first) : 0xff);
2479
2480	while ((mp = getq(q)) != NULL) {
2481		msgtype = DB_TYPE(mp);
2482		USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: "
2483		    "type=%s (0x%x)", usbser_msgtype2str(msgtype), msgtype);
2484
2485		switch (msgtype) {
2486		/*
2487		 * high-priority messages
2488		 */
2489		case M_STOP:
2490			usbser_stop(pp, mp);
2491
2492			break;
2493		case M_START:
2494			usbser_start(pp, mp);
2495
2496			break;
2497		case M_STOPI:
2498			usbser_stopi(pp, mp);
2499
2500			break;
2501		case M_STARTI:
2502			usbser_starti(pp, mp);
2503
2504			break;
2505		case M_IOCDATA:
2506			usbser_iocdata(pp, mp);
2507
2508			break;
2509		case M_FLUSH:
2510			usbser_flush(pp, mp);
2511
2512			break;
2513		/*
2514		 * normal-priority messages
2515		 */
2516		case M_BREAK:
2517			usbser_break(pp, mp);
2518
2519			break;
2520		case M_DELAY:
2521			usbser_delay(pp, mp);
2522
2523			break;
2524		case M_DATA:
2525			if (usbser_data(pp, mp) != USB_SUCCESS) {
2526				(void) putbq(q, mp);
2527
2528				return;
2529			}
2530
2531			break;
2532		case M_IOCTL:
2533			if (usbser_ioctl(pp, mp) != USB_SUCCESS) {
2534				(void) putbq(q, mp);
2535
2536				return;
2537			}
2538
2539			break;
2540		default:
2541			freemsg(mp);
2542
2543			break;
2544		}
2545	}
2546}
2547
2548
2549/*
2550 * process M_DATA message
2551 */
2552static int
2553usbser_data(usbser_port_t *pp, mblk_t *mp)
2554{
2555	/* put off until current transfer ends or delay is over */
2556	if ((pp->port_act & USBSER_ACT_TX) ||
2557	    (pp->port_act & USBSER_ACT_DELAY)) {
2558
2559		return (USB_FAILURE);
2560	}
2561	if (MBLKL(mp) <= 0) {
2562		freemsg(mp);
2563
2564		return (USB_SUCCESS);
2565	}
2566
2567	pp->port_act |= USBSER_ACT_TX;
2568	pp->port_wq_data_cnt -= msgdsize(mp);
2569
2570	mutex_exit(&pp->port_mutex);
2571	/* DSD is required to accept data block in any case */
2572	(void) USBSER_DS_TX(pp, mp);
2573	mutex_enter(&pp->port_mutex);
2574
2575	return (USB_SUCCESS);
2576}
2577
2578
2579/*
2580 * process an M_IOCTL message
2581 */
2582static int
2583usbser_ioctl(usbser_port_t *pp, mblk_t *mp)
2584{
2585	tty_common_t	*tp = &pp->port_ttycommon;
2586	queue_t		*q = tp->t_writeq;
2587	struct iocblk	*iocp;
2588	int		cmd;
2589	mblk_t		*datamp;
2590	int		error = 0, rval;
2591	int		val;
2592
2593	ASSERT(mutex_owned(&pp->port_mutex));
2594	ASSERT(DB_TYPE(mp) == M_IOCTL);
2595
2596	iocp = (struct iocblk *)mp->b_rptr;
2597	cmd = iocp->ioc_cmd;
2598
2599	USB_DPRINTF_L4(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
2600	    "mp=%p %s (0x%x)", (void *)mp, usbser_ioctl2str(cmd), cmd);
2601
2602	if (tp->t_iocpending != NULL) {
2603		/*
2604		 * We were holding an ioctl response pending the
2605		 * availability of an mblk to hold data to be passed up;
2606		 * another ioctl came through, which means that ioctl
2607		 * must have timed out or been aborted.
2608		 */
2609		freemsg(tp->t_iocpending);
2610		tp->t_iocpending = NULL;
2611	}
2612
2613	switch (cmd) {
2614	case TIOCMGET:
2615	case TIOCMBIC:
2616	case TIOCMBIS:
2617	case TIOCMSET:
2618	case CONSOPENPOLLEDIO:
2619	case CONSCLOSEPOLLEDIO:
2620	case CONSSETABORTENABLE:
2621	case CONSGETABORTENABLE:
2622		/*
2623		 * For the above ioctls do not call ttycommon_ioctl() because
2624		 * this function frees up the message block (mp->b_cont) that
2625		 * contains the address of the user variable where we need to
2626		 * pass back the bit array.
2627		 */
2628		error = -1;
2629		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2630		mutex_exit(&pp->port_mutex);
2631		break;
2632
2633	case TCSBRK:
2634		/* serialize breaks */
2635		if (pp->port_act & USBSER_ACT_BREAK)
2636			return (USB_FAILURE);
2637		/*FALLTHRU*/
2638	default:
2639		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2640		mutex_exit(&pp->port_mutex);
2641		(void) ttycommon_ioctl(tp, q, mp, &error);
2642		break;
2643	}
2644
2645	if (error == 0) {
2646		/*
2647		 * ttycommon_ioctl() did most of the work
2648		 * we just use the data it set up
2649		 */
2650		switch (cmd) {
2651		case TCSETSF:
2652		case TCSETSW:
2653		case TCSETA:
2654		case TCSETAW:
2655		case TCSETAF:
2656			(void) USBSER_DS_FIFO_DRAIN(pp, DS_TX);
2657			/*FALLTHRU*/
2658
2659		case TCSETS:
2660			mutex_enter(&pp->port_mutex);
2661			error = usbser_port_program(pp);
2662			mutex_exit(&pp->port_mutex);
2663			break;
2664		}
2665		goto end;
2666
2667	} else if (error > 0) {
2668		USB_DPRINTF_L3(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
2669		    "ttycommon_ioctl returned %d", error);
2670		goto end;
2671	}
2672
2673	/*
2674	 * error < 0: ttycommon_ioctl() didn't do anything, we process it here
2675	 */
2676	error = 0;
2677	switch (cmd) {
2678	case TCSBRK:
2679		if ((error = miocpullup(mp, sizeof (int))) != 0)
2680			break;
2681
2682		/* drain output */
2683		(void) USBSER_DS_FIFO_DRAIN(pp, USBSER_TX_FIFO_DRAIN_TIMEOUT);
2684
2685		/*
2686		 * if required, set break
2687		 */
2688		if (*(int *)mp->b_cont->b_rptr == 0) {
2689			if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS) {
2690				error = EIO;
2691				break;
2692			}
2693
2694			mutex_enter(&pp->port_mutex);
2695			pp->port_act |= USBSER_ACT_BREAK;
2696			pp->port_delay_id = timeout(usbser_restart, pp,
2697			    drv_usectohz(250000));
2698			mutex_exit(&pp->port_mutex);
2699		}
2700		mioc2ack(mp, NULL, 0, 0);
2701		break;
2702
2703	case TIOCSBRK:	/* set break */
2704		if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS)
2705			error = EIO;
2706		else
2707			mioc2ack(mp, NULL, 0, 0);
2708		break;
2709
2710	case TIOCCBRK:	/* clear break */
2711		if (USBSER_DS_BREAK_CTL(pp, DS_OFF) != USB_SUCCESS)
2712			error = EIO;
2713		else
2714			mioc2ack(mp, NULL, 0, 0);
2715		break;
2716
2717	case TIOCMSET:	/* set all modem bits */
2718	case TIOCMBIS:	/* bis modem bits */
2719	case TIOCMBIC:	/* bic modem bits */
2720		if (iocp->ioc_count == TRANSPARENT) {
2721			mcopyin(mp, NULL, sizeof (int), NULL);
2722			break;
2723		}
2724		if ((error = miocpullup(mp, sizeof (int))) != 0)
2725			break;
2726
2727		val = *(int *)mp->b_cont->b_rptr;
2728		if (cmd == TIOCMSET) {
2729			rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
2730		} else if (cmd == TIOCMBIS) {
2731			rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
2732		} else if (cmd == TIOCMBIC) {
2733			rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
2734		}
2735		if (rval == USB_SUCCESS)
2736			mioc2ack(mp, NULL, 0, 0);
2737		else
2738			error = EIO;
2739		break;
2740
2741	case TIOCSILOOP:
2742		if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
2743			if (USBSER_DS_LOOPBACK(pp, DS_ON) == USB_SUCCESS)
2744				mioc2ack(mp, NULL, 0, 0);
2745			else
2746				error = EIO;
2747		} else {
2748			error = EINVAL;
2749		}
2750		break;
2751
2752	case TIOCCILOOP:
2753		if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
2754			if (USBSER_DS_LOOPBACK(pp, DS_OFF) == USB_SUCCESS)
2755				mioc2ack(mp, NULL, 0, 0);
2756			else
2757				error = EIO;
2758		} else {
2759			error = EINVAL;
2760		}
2761		break;
2762
2763	case TIOCMGET:	/* get all modem bits */
2764		if ((datamp = allocb(sizeof (int), BPRI_MED)) == NULL) {
2765			error = EAGAIN;
2766			break;
2767		}
2768		rval = USBSER_DS_GET_MODEM_CTL(pp, -1, (int *)datamp->b_rptr);
2769		if (rval != USB_SUCCESS) {
2770			error = EIO;
2771			break;
2772		}
2773		if (iocp->ioc_count == TRANSPARENT)
2774			mcopyout(mp, NULL, sizeof (int), NULL, datamp);
2775		else
2776			mioc2ack(mp, datamp, sizeof (int), 0);
2777		break;
2778
2779	case CONSOPENPOLLEDIO:
2780		error = usbser_polledio_init(pp);
2781		if (error != 0)
2782			break;
2783
2784		error = miocpullup(mp, sizeof (struct cons_polledio *));
2785		if (error != 0)
2786			break;
2787
2788		*(struct cons_polledio **)mp->b_cont->b_rptr = &usbser_polledio;
2789
2790		mp->b_datap->db_type = M_IOCACK;
2791		break;
2792
2793	case CONSCLOSEPOLLEDIO:
2794		usbser_polledio_fini(pp);
2795		mp->b_datap->db_type = M_IOCACK;
2796		iocp->ioc_error = 0;
2797		iocp->ioc_rval = 0;
2798		break;
2799
2800	case CONSSETABORTENABLE:
2801		error = secpolicy_console(iocp->ioc_cr);
2802		if (error != 0)
2803			break;
2804
2805		if (iocp->ioc_count != TRANSPARENT) {
2806			error = EINVAL;
2807			break;
2808		}
2809
2810		/*
2811		 * To do: implement console abort support
2812		 * This involves adding a console flag to usbser
2813		 * state structure. If flag is set, parse input stream
2814		 * for abort sequence (see asy for example).
2815		 *
2816		 * For now, run mdb -K to get kmdb prompt.
2817		 */
2818		if (*(intptr_t *)mp->b_cont->b_rptr)
2819			usbser_console_abort = 1;
2820		else
2821			usbser_console_abort = 0;
2822
2823		mp->b_datap->db_type = M_IOCACK;
2824		iocp->ioc_error = 0;
2825		iocp->ioc_rval = 0;
2826		break;
2827
2828	case CONSGETABORTENABLE:
2829		/*CONSTANTCONDITION*/
2830		ASSERT(sizeof (boolean_t) <= sizeof (boolean_t *));
2831		/*
2832		 * Store the return value right in the payload
2833		 * we were passed.  Crude.
2834		 */
2835		mcopyout(mp, NULL, sizeof (boolean_t), NULL, NULL);
2836		*(boolean_t *)mp->b_cont->b_rptr = (usbser_console_abort != 0);
2837		break;
2838
2839	default:
2840		error = EINVAL;
2841		break;
2842	}
2843end:
2844	if (error != 0)
2845		miocnak(q, mp, 0, error);
2846	else
2847		qreply(q, mp);
2848
2849	mutex_enter(&pp->port_mutex);
2850	usbser_release_port_act(pp, USBSER_ACT_CTL);
2851
2852	return (USB_SUCCESS);
2853}
2854
2855
2856/*
2857 * process M_IOCDATA message
2858 */
2859static void
2860usbser_iocdata(usbser_port_t *pp, mblk_t *mp)
2861{
2862	tty_common_t	*tp = &pp->port_ttycommon;
2863	queue_t		*q = tp->t_writeq;
2864	struct copyresp	*csp;
2865	int		cmd;
2866	int		val;
2867	int		rval;
2868
2869	ASSERT(mutex_owned(&pp->port_mutex));
2870
2871	csp = (struct copyresp *)mp->b_rptr;
2872	cmd = csp->cp_cmd;
2873
2874	if (csp->cp_rval != 0) {
2875		freemsg(mp);
2876		return;
2877	}
2878
2879	switch (cmd) {
2880	case TIOCMSET:	/* set all modem bits */
2881	case TIOCMBIS:	/* bis modem bits */
2882	case TIOCMBIC:	/* bic modem bits */
2883		if ((mp->b_cont == NULL) ||
2884		    (MBLKL(mp->b_cont) < sizeof (int))) {
2885			miocnak(q, mp, 0, EINVAL);
2886			break;
2887		}
2888		val = *(int *)mp->b_cont->b_rptr;
2889
2890		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2891		mutex_exit(&pp->port_mutex);
2892
2893		if (cmd == TIOCMSET) {
2894			rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
2895		} else if (cmd == TIOCMBIS) {
2896			rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
2897		} else if (cmd == TIOCMBIC) {
2898			rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
2899		}
2900
2901		if (mp->b_cont) {
2902			freemsg(mp->b_cont);
2903			mp->b_cont = NULL;
2904		}
2905
2906		if (rval == USB_SUCCESS)
2907			miocack(q, mp, 0, 0);
2908		else
2909			miocnak(q, mp, 0, EIO);
2910
2911		mutex_enter(&pp->port_mutex);
2912		usbser_release_port_act(pp, USBSER_ACT_CTL);
2913		break;
2914
2915	case TIOCMGET:	/* get all modem bits */
2916		mutex_exit(&pp->port_mutex);
2917		miocack(q, mp, 0, 0);
2918		mutex_enter(&pp->port_mutex);
2919		break;
2920
2921	default:
2922		mutex_exit(&pp->port_mutex);
2923		miocnak(q, mp, 0, EINVAL);
2924		mutex_enter(&pp->port_mutex);
2925		break;
2926	}
2927}
2928
2929
2930/*
2931 * handle M_START[I]/M_STOP[I] messages
2932 */
2933static void
2934usbser_stop(usbser_port_t *pp, mblk_t *mp)
2935{
2936	usbser_st_mstop++;
2937	if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
2938		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2939		pp->port_flags |= USBSER_FL_TX_STOPPED;
2940
2941		mutex_exit(&pp->port_mutex);
2942		USBSER_DS_STOP(pp, DS_TX);
2943		mutex_enter(&pp->port_mutex);
2944
2945		usbser_release_port_act(pp, USBSER_ACT_TX);
2946		usbser_release_port_act(pp, USBSER_ACT_CTL);
2947	}
2948	freemsg(mp);
2949}
2950
2951
2952static void
2953usbser_start(usbser_port_t *pp, mblk_t *mp)
2954{
2955	usbser_st_mstart++;
2956	if (pp->port_flags & USBSER_FL_TX_STOPPED) {
2957		usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2958		pp->port_flags &= ~USBSER_FL_TX_STOPPED;
2959
2960		mutex_exit(&pp->port_mutex);
2961		USBSER_DS_START(pp, DS_TX);
2962		mutex_enter(&pp->port_mutex);
2963		usbser_release_port_act(pp, USBSER_ACT_CTL);
2964	}
2965	freemsg(mp);
2966}
2967
2968
2969static void
2970usbser_stopi(usbser_port_t *pp, mblk_t *mp)
2971{
2972	usbser_st_mstopi++;
2973	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2974	pp->port_flowc = pp->port_ttycommon.t_stopc;
2975	usbser_inbound_flow_ctl(pp);
2976	usbser_release_port_act(pp, USBSER_ACT_CTL);
2977	freemsg(mp);
2978}
2979
2980static void
2981usbser_starti(usbser_port_t *pp, mblk_t *mp)
2982{
2983	usbser_st_mstarti++;
2984	usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2985	pp->port_flowc = pp->port_ttycommon.t_startc;
2986	usbser_inbound_flow_ctl(pp);
2987	usbser_release_port_act(pp, USBSER_ACT_CTL);
2988	freemsg(mp);
2989}
2990
2991/*
2992 * process M_FLUSH message
2993 */
2994static void
2995usbser_flush(usbser_port_t *pp, mblk_t *mp)
2996{
2997	queue_t	*q = pp->port_ttycommon.t_writeq;
2998
2999	if (*mp->b_rptr & FLUSHW) {
3000		mutex_exit(&pp->port_mutex);
3001		(void) USBSER_DS_FIFO_FLUSH(pp, DS_TX);	/* flush FIFO buffers */
3002		flushq(q, FLUSHDATA);			/* flush write queue */
3003		mutex_enter(&pp->port_mutex);
3004
3005		usbser_release_port_act(pp, USBSER_ACT_TX);
3006
3007		*mp->b_rptr &= ~FLUSHW;
3008	}
3009	if (*mp->b_rptr & FLUSHR) {
3010		/*
3011		 * flush FIFO buffers
3012		 */
3013		mutex_exit(&pp->port_mutex);
3014		(void) USBSER_DS_FIFO_FLUSH(pp, DS_RX);
3015		flushq(RD(q), FLUSHDATA);
3016		qreply(q, mp);
3017		mutex_enter(&pp->port_mutex);
3018	} else {
3019		freemsg(mp);
3020	}
3021}
3022
3023/*
3024 * process M_BREAK message
3025 */
3026static void
3027usbser_break(usbser_port_t *pp, mblk_t *mp)
3028{
3029	int	rval;
3030
3031	/*
3032	 * set the break and arrange for usbser_restart() to be called in 1/4 s
3033	 */
3034	mutex_exit(&pp->port_mutex);
3035	rval = USBSER_DS_BREAK_CTL(pp, DS_ON);
3036	mutex_enter(&pp->port_mutex);
3037
3038	if (rval == USB_SUCCESS) {
3039		pp->port_act |= USBSER_ACT_BREAK;
3040		pp->port_delay_id = timeout(usbser_restart, pp,
3041		    drv_usectohz(250000));
3042	}
3043	freemsg(mp);
3044}
3045
3046
3047/*
3048 * process M_DELAY message
3049 */
3050static void
3051usbser_delay(usbser_port_t *pp, mblk_t *mp)
3052{
3053	/*
3054	 * arrange for usbser_restart() to be called when the delay expires
3055	 */
3056	pp->port_act |= USBSER_ACT_DELAY;
3057	pp->port_delay_id = timeout(usbser_restart, pp,
3058	    (clock_t)(*(uchar_t *)mp->b_rptr + 6));
3059	freemsg(mp);
3060}
3061
3062
3063/*
3064 * restart output on a line after a delay or break timer expired
3065 */
3066static void
3067usbser_restart(void *arg)
3068{
3069	usbser_port_t	*pp = (usbser_port_t *)arg;
3070
3071	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_restart");
3072
3073	mutex_enter(&pp->port_mutex);
3074	/* if cancelled, return immediately */
3075	if (pp->port_delay_id == 0) {
3076		mutex_exit(&pp->port_mutex);
3077
3078		return;
3079	}
3080	pp->port_delay_id = 0;
3081
3082	/* clear break if necessary */
3083	if (pp->port_act & USBSER_ACT_BREAK) {
3084		mutex_exit(&pp->port_mutex);
3085		(void) USBSER_DS_BREAK_CTL(pp, DS_OFF);
3086		mutex_enter(&pp->port_mutex);
3087	}
3088
3089	usbser_release_port_act(pp, USBSER_ACT_BREAK | USBSER_ACT_DELAY);
3090
3091	/* wake wq thread to resume message processing */
3092	usbser_thr_wake(&pp->port_wq_thread);
3093	mutex_exit(&pp->port_mutex);
3094}
3095
3096
3097/*
3098 * program port hardware with the chosen parameters
3099 * most of the operation is based on the values of 'c_iflag' and 'c_cflag'
3100 */
3101static int
3102usbser_port_program(usbser_port_t *pp)
3103{
3104	tty_common_t		*tp = &pp->port_ttycommon;
3105	int			baudrate;
3106	int			c_flag;
3107	ds_port_param_entry_t	pe[6];
3108	ds_port_params_t	params;
3109	int			flow_ctl, ctl_val;
3110	int			err = 0;
3111
3112	baudrate = tp->t_cflag & CBAUD;
3113	if (tp->t_cflag & CBAUDEXT) {
3114		baudrate += 16;
3115	}
3116
3117	/*
3118	 * set input speed same as output, as split speed not supported
3119	 */
3120	if (tp->t_cflag & (CIBAUD|CIBAUDEXT)) {
3121		tp->t_cflag &= ~(CIBAUD);
3122		if (baudrate > CBAUD) {
3123			tp->t_cflag |= CIBAUDEXT;
3124			tp->t_cflag |=
3125			    (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD);
3126		} else {
3127			tp->t_cflag &= ~CIBAUDEXT;
3128			tp->t_cflag |= ((baudrate << IBSHIFT) & CIBAUD);
3129		}
3130	}
3131
3132	c_flag = tp->t_cflag;
3133
3134	/*
3135	 * flow control
3136	 */
3137	flow_ctl = tp->t_iflag & (IXON | IXANY | IXOFF);
3138	if (c_flag & CRTSCTS) {
3139		flow_ctl |= CTSXON;
3140	}
3141	if (c_flag & CRTSXOFF) {
3142		flow_ctl |= RTSXOFF;
3143	}
3144
3145	/*
3146	 * fill in port parameters we need to set:
3147	 *
3148	 * baud rate
3149	 */
3150	pe[0].param = DS_PARAM_BAUD;
3151	pe[0].val.ui = baudrate;
3152
3153	/* stop bits */
3154	pe[1].param = DS_PARAM_STOPB;
3155	pe[1].val.ui = c_flag & CSTOPB;
3156
3157	/* parity */
3158	pe[2].param = DS_PARAM_PARITY;
3159	pe[2].val.ui = c_flag & (PARENB | PARODD);
3160
3161	/* char size */
3162	pe[3].param = DS_PARAM_CHARSZ;
3163	pe[3].val.ui = c_flag & CSIZE;
3164
3165	/* start & stop chars */
3166	pe[4].param = DS_PARAM_XON_XOFF;
3167	pe[4].val.uc[0] = tp->t_startc;
3168	pe[4].val.uc[1] = tp->t_stopc;
3169
3170	/* flow control */
3171	pe[5].param = DS_PARAM_FLOW_CTL;
3172	pe[5].val.ui = flow_ctl;
3173
3174	params.tp_entries = &pe[0];
3175	params.tp_cnt = 6;
3176
3177	/* control signals */
3178	ctl_val = TIOCM_DTR | TIOCM_RTS;
3179	if (baudrate == 0) {
3180		ctl_val &= ~TIOCM_DTR;	/* zero baudrate means drop DTR */
3181	}
3182	if (pp->port_flags & USBSER_FL_RX_STOPPED) {
3183		ctl_val &= ~TIOCM_RTS;
3184	}
3185
3186	/* submit */
3187	mutex_exit(&pp->port_mutex);
3188	err = USBSER_DS_SET_PORT_PARAMS(pp, &params);
3189	if (err != USB_SUCCESS) {
3190		mutex_enter(&pp->port_mutex);
3191
3192		return (EINVAL);
3193	}
3194
3195	err = USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR | TIOCM_RTS, ctl_val);
3196	mutex_enter(&pp->port_mutex);
3197
3198	return ((err == USB_SUCCESS) ? 0 : EIO);
3199}
3200
3201
3202/*
3203 * check if any inbound flow control action needed
3204 */
3205static void
3206usbser_inbound_flow_ctl(usbser_port_t *pp)
3207{
3208	tcflag_t	need_hw;
3209	int		rts;
3210	char		c = pp->port_flowc;
3211	mblk_t		*mp = NULL;
3212
3213	USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
3214	    "usbser_inbound_flow_ctl: c=%x cflag=%x port_flags=%x",
3215	    c, pp->port_ttycommon.t_cflag, pp->port_flags);
3216
3217	if (c == '\0') {
3218
3219		return;
3220	}
3221	pp->port_flowc = '\0';
3222
3223	/*
3224	 * if inbound hardware flow control enabled, we need to frob RTS
3225	 */
3226	need_hw = (pp->port_ttycommon.t_cflag & CRTSXOFF);
3227	if (c == pp->port_ttycommon.t_startc) {
3228		rts = TIOCM_RTS;
3229		pp->port_flags &= ~USBSER_FL_RX_STOPPED;
3230	} else {
3231		rts = 0;
3232		pp->port_flags |= USBSER_FL_RX_STOPPED;
3233	}
3234
3235	/*
3236	 * if character flow control active, transmit a start or stop char,
3237	 */
3238	if (pp->port_ttycommon.t_iflag & IXOFF) {
3239		if ((mp = allocb(1, BPRI_LO)) == NULL) {
3240			USB_DPRINTF_L2(DPRINT_WQ, pp->port_lh,
3241			    "usbser_inbound_flow_ctl: allocb failed");
3242		} else {
3243			*mp->b_wptr++ = c;
3244			pp->port_flags |= USBSER_ACT_TX;
3245		}
3246	}
3247
3248	mutex_exit(&pp->port_mutex);
3249	if (need_hw) {
3250		(void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_RTS, rts);
3251	}
3252	if (mp) {
3253		(void) USBSER_DS_TX(pp, mp);
3254	}
3255	mutex_enter(&pp->port_mutex);
3256}
3257
3258
3259/*
3260 * misc
3261 * ----
3262 *
3263 *
3264 * returns != 0 if device is online, 0 otherwise
3265 */
3266static int
3267usbser_dev_is_online(usbser_state_t *usp)
3268{
3269	int	rval;
3270
3271	mutex_enter(&usp->us_mutex);
3272	rval = (usp->us_dev_state == USB_DEV_ONLINE);
3273	mutex_exit(&usp->us_mutex);
3274
3275	return (rval);
3276}
3277
3278/*
3279 * serialize port activities defined by 'act' mask
3280 */
3281static void
3282usbser_serialize_port_act(usbser_port_t *pp, int act)
3283{
3284	while (pp->port_act & act)
3285		cv_wait(&pp->port_act_cv, &pp->port_mutex);
3286	pp->port_act |= act;
3287}
3288
3289
3290/*
3291 * indicate that port activity is finished
3292 */
3293static void
3294usbser_release_port_act(usbser_port_t *pp, int act)
3295{
3296	pp->port_act &= ~act;
3297	cv_broadcast(&pp->port_act_cv);
3298}
3299
3300
3301/*
3302 * message type to string and back conversion.
3303 *
3304 * pardon breaks on the same line, but as long as cstyle doesn't
3305 * complain, I'd like to keep this form for trivial cases like this.
3306 * associative arrays in the kernel, anyone?
3307 */
3308static char *
3309usbser_msgtype2str(int type)
3310{
3311	char	*str;
3312
3313	switch (type) {
3314	case M_STOP:	str = "M_STOP";		break;
3315	case M_START:	str = "M_START";	break;
3316	case M_STOPI:	str = "M_STOPI";	break;
3317	case M_STARTI:	str = "M_STARTI";	break;
3318	case M_DATA:	str = "M_DATA";		break;
3319	case M_DELAY:	str = "M_DELAY";	break;
3320	case M_BREAK:	str = "M_BREAK";	break;
3321	case M_IOCTL:	str = "M_IOCTL";	break;
3322	case M_IOCDATA:	str = "M_IOCDATA";	break;
3323	case M_FLUSH:	str = "M_FLUSH";	break;
3324	case M_CTL:	str = "M_CTL";		break;
3325	case M_READ:	str = "M_READ";		break;
3326	default:	str = "unknown";	break;
3327	}
3328
3329	return (str);
3330}
3331
3332
3333static char *
3334usbser_ioctl2str(int ioctl)
3335{
3336	char	*str;
3337
3338	switch (ioctl) {
3339	case TCGETA:	str = "TCGETA";		break;
3340	case TCSETA:	str = "TCSETA";		break;
3341	case TCSETAF:	str = "TCSETAF";	break;
3342	case TCSETAW:	str = "TCSETAW";	break;
3343	case TCSBRK:	str = "TCSBRK";		break;
3344	case TCXONC:	str = "TCXONC";		break;
3345	case TCFLSH:	str = "TCFLSH";		break;
3346	case TCGETS:	str = "TCGETS";		break;
3347	case TCSETS:	str = "TCSETS";		break;
3348	case TCSETSF:	str = "TCSETSF";	break;
3349	case TCSETSW:	str = "TCSETSW";	break;
3350	case TIOCSBRK:	str = "TIOCSBRK";	break;
3351	case TIOCCBRK:	str = "TIOCCBRK";	break;
3352	case TIOCMSET:	str = "TIOCMSET";	break;
3353	case TIOCMBIS:	str = "TIOCMBIS";	break;
3354	case TIOCMBIC:	str = "TIOCMBIC";	break;
3355	case TIOCMGET:	str = "TIOCMGET";	break;
3356	case TIOCSILOOP: str = "TIOCSILOOP";	break;
3357	case TIOCCILOOP: str = "TIOCCILOOP";	break;
3358	case TCGETX:	str = "TCGETX";		break;
3359	case TCSETX:	str = "TCGETX";		break;
3360	case TCSETXW:	str = "TCGETX";		break;
3361	case TCSETXF:	str = "TCGETX";		break;
3362	default:	str = "unknown";	break;
3363	}
3364
3365	return (str);
3366}
3367
3368/*
3369 * Polled IO support
3370 */
3371
3372/* called once	by consconfig() when polledio is opened */
3373static int
3374usbser_polledio_init(usbser_port_t *pp)
3375{
3376	int err;
3377	usb_pipe_handle_t hdl;
3378	ds_ops_t *ds_ops = pp->port_ds_ops;
3379
3380	/* only one serial line console supported */
3381	if (console_input != NULL)
3382		return (USB_FAILURE);
3383
3384	/* check if underlying driver supports polled io */
3385	if (ds_ops->ds_version < DS_OPS_VERSION_V1 ||
3386	    ds_ops->ds_out_pipe == NULL || ds_ops->ds_in_pipe == NULL)
3387		return (USB_FAILURE);
3388
3389	/* init polled input pipe */
3390	hdl = ds_ops->ds_in_pipe(pp->port_ds_hdl, pp->port_num);
3391	err = usb_console_input_init(pp->port_usp->us_dip, hdl,
3392	    &console_input_buf, &console_input);
3393	if (err)
3394		return (USB_FAILURE);
3395
3396	/* init polled output pipe */
3397	hdl = ds_ops->ds_out_pipe(pp->port_ds_hdl, pp->port_num);
3398	err = usb_console_output_init(pp->port_usp->us_dip, hdl,
3399	    &console_output);
3400	if (err) {
3401		(void) usb_console_input_fini(console_input);
3402		console_input = NULL;
3403		return (USB_FAILURE);
3404	}
3405
3406	return (USB_SUCCESS);
3407}
3408
3409/* called once	by consconfig() when polledio is closed */
3410/*ARGSUSED*/
3411static void usbser_polledio_fini(usbser_port_t *pp)
3412{
3413	/* Since we can't move the console, there is nothing to do. */
3414}
3415
3416/*ARGSUSED*/
3417static void
3418usbser_polledio_enter(cons_polledio_arg_t arg)
3419{
3420	(void) usb_console_input_enter(console_input);
3421	(void) usb_console_output_enter(console_output);
3422}
3423
3424/*ARGSUSED*/
3425static void
3426usbser_polledio_exit(cons_polledio_arg_t arg)
3427{
3428	(void) usb_console_output_exit(console_output);
3429	(void) usb_console_input_exit(console_input);
3430}
3431
3432/*ARGSUSED*/
3433static void
3434usbser_putchar(cons_polledio_arg_t arg, uchar_t c)
3435{
3436	static uchar_t cr[2] = {'\r', '\n'};
3437	uint_t nout;
3438
3439	if (c == '\n')
3440		(void) usb_console_write(console_output, cr, 2, &nout);
3441	else
3442		(void) usb_console_write(console_output, &c, 1, &nout);
3443}
3444
3445/*ARGSUSED*/
3446static int
3447usbser_getchar(cons_polledio_arg_t arg)
3448{
3449	while (!usbser_ischar(arg))
3450		;
3451
3452	return (*console_input_start++);
3453}
3454
3455/*ARGSUSED*/
3456static boolean_t
3457usbser_ischar(cons_polledio_arg_t arg)
3458{
3459	uint_t num_bytes;
3460
3461	if (console_input_start < console_input_end)
3462		return (B_TRUE);
3463
3464	if (usb_console_read(console_input, &num_bytes) != USB_SUCCESS)
3465		return (B_FALSE);
3466
3467	console_input_start = console_input_buf;
3468	console_input_end = console_input_buf + num_bytes;
3469
3470	return (num_bytes != 0);
3471}
3472