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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 * USB generic serial driver (GSD)
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>
40 #include <sys/modctl.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>
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>
60 /* autoconfiguration subroutines */
61 static int usbser_rseq_do_cb(rseq_t
*, int, uintptr_t);
62 static int usbser_free_soft_state(usbser_state_t
*);
63 static int usbser_init_soft_state(usbser_state_t
*);
64 static int usbser_fini_soft_state(usbser_state_t
*);
65 static int usbser_attach_dev(usbser_state_t
*);
66 static void usbser_detach_dev(usbser_state_t
*);
67 static int usbser_attach_ports(usbser_state_t
*);
68 static int usbser_create_port_minor_nodes(usbser_state_t
*, int);
69 static void usbser_detach_ports(usbser_state_t
*);
70 static int usbser_create_taskq(usbser_state_t
*);
71 static void usbser_destroy_taskq(usbser_state_t
*);
72 static void usbser_set_dev_state_init(usbser_state_t
*);
74 /* hotplugging and power management */
75 static int usbser_disconnect_cb(dev_info_t
*);
76 static int usbser_reconnect_cb(dev_info_t
*);
77 static void usbser_disconnect_ports(usbser_state_t
*);
78 static int usbser_cpr_suspend(dev_info_t
*);
79 static int usbser_suspend_ports(usbser_state_t
*);
80 static void usbser_cpr_resume(dev_info_t
*);
81 static int usbser_restore_device_state(usbser_state_t
*);
82 static void usbser_restore_ports_state(usbser_state_t
*);
84 /* STREAMS subroutines */
85 static int usbser_open_setup(queue_t
*, usbser_port_t
*, int, int,
87 static int usbser_open_init(usbser_port_t
*, int);
88 static void usbser_check_port_props(usbser_port_t
*);
89 static void usbser_open_fini(usbser_port_t
*);
90 static int usbser_open_line_setup(usbser_port_t
*, int, int);
91 static int usbser_open_carrier_check(usbser_port_t
*, int, int);
92 static void usbser_open_queues_init(usbser_port_t
*, queue_t
*);
93 static void usbser_open_queues_fini(usbser_port_t
*);
94 static void usbser_close_drain(usbser_port_t
*);
95 static void usbser_close_cancel_break(usbser_port_t
*);
96 static void usbser_close_hangup(usbser_port_t
*);
97 static void usbser_close_cleanup(usbser_port_t
*);
100 static void usbser_thr_dispatch(usbser_thread_t
*);
101 static void usbser_thr_cancel(usbser_thread_t
*);
102 static void usbser_thr_wake(usbser_thread_t
*);
103 static void usbser_wq_thread(void *);
104 static void usbser_rq_thread(void *);
107 static void usbser_tx_cb(caddr_t
);
108 static void usbser_rx_cb(caddr_t
);
109 static void usbser_rx_massage_data(usbser_port_t
*, mblk_t
*);
110 static void usbser_rx_massage_mbreak(usbser_port_t
*, mblk_t
*);
111 static void usbser_rx_cb_put(usbser_port_t
*, queue_t
*, queue_t
*,
113 static void usbser_status_cb(caddr_t
);
114 static void usbser_status_proc_cb(usbser_port_t
*);
117 static void usbser_wmsg(usbser_port_t
*);
118 static int usbser_data(usbser_port_t
*, mblk_t
*);
119 static int usbser_ioctl(usbser_port_t
*, mblk_t
*);
120 static void usbser_iocdata(usbser_port_t
*, mblk_t
*);
121 static void usbser_stop(usbser_port_t
*, mblk_t
*);
122 static void usbser_start(usbser_port_t
*, mblk_t
*);
123 static void usbser_stopi(usbser_port_t
*, mblk_t
*);
124 static void usbser_starti(usbser_port_t
*, mblk_t
*);
125 static void usbser_flush(usbser_port_t
*, mblk_t
*);
126 static void usbser_break(usbser_port_t
*, mblk_t
*);
127 static void usbser_delay(usbser_port_t
*, mblk_t
*);
128 static void usbser_restart(void *);
129 static int usbser_port_program(usbser_port_t
*);
130 static void usbser_inbound_flow_ctl(usbser_port_t
*);
133 static int usbser_dev_is_online(usbser_state_t
*);
134 static void usbser_serialize_port_act(usbser_port_t
*, int);
135 static void usbser_release_port_act(usbser_port_t
*, int);
137 static char *usbser_msgtype2str(int);
138 static char *usbser_ioctl2str(int);
142 usb_event_t usbser_usb_events
= {
143 usbser_disconnect_cb
, /* disconnect */
144 usbser_reconnect_cb
, /* reconnect */
145 NULL
, /* pre-suspend */
146 NULL
, /* pre-resume */
150 uint_t usbser_errlevel
= USB_LOG_L4
;
151 uint_t usbser_errmask
= DPRINT_MASK_ALL
;
152 uint_t usbser_instance_debug
= (uint_t
)-1;
154 /* usb serial console */
155 static struct usbser_state
*usbser_list
;
156 static kmutex_t usbser_lock
;
157 static int usbser_console_abort
;
158 static usb_console_info_t console_input
, console_output
;
159 static uchar_t
*console_input_buf
;
160 static uchar_t
*console_input_start
, *console_input_end
;
162 _NOTE(SCHEME_PROTECTS_DATA("unshared", usbser_console_abort
))
163 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input
))
164 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_output
))
165 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_start
))
166 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_end
))
168 static void usbser_putchar(cons_polledio_arg_t
, uchar_t
);
169 static int usbser_getchar(cons_polledio_arg_t
);
170 static boolean_t
usbser_ischar(cons_polledio_arg_t
);
171 static void usbser_polledio_enter(cons_polledio_arg_t
);
172 static void usbser_polledio_exit(cons_polledio_arg_t
);
173 static int usbser_polledio_init(usbser_port_t
*);
174 static void usbser_polledio_fini(usbser_port_t
*);
176 static struct cons_polledio usbser_polledio
= {
178 NULL
, /* to be set later */
182 usbser_polledio_enter
,
186 /* various statistics. TODO: replace with kstats */
187 static int usbser_st_tx_data_loss
= 0;
188 static int usbser_st_rx_data_loss
= 0;
189 static int usbser_st_put_stopi
= 0;
190 static int usbser_st_mstop
= 0;
191 static int usbser_st_mstart
= 0;
192 static int usbser_st_mstopi
= 0;
193 static int usbser_st_mstarti
= 0;
194 static int usbser_st_rsrv
= 0;
195 _NOTE(SCHEME_PROTECTS_DATA("monotonic stats", usbser_st_
{
196 tx_data_loss rx_data_loss put_stopi mstop mstart mstopi mstarti rsrv
}))
197 _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_bulk_req_t
))
198 _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_intr_req_t
))
200 /* taskq parameter */
201 extern pri_t minclsyspri
;
206 extern struct mod_ops mod_miscops
;
208 static struct modlmisc modlmisc
= {
209 &mod_miscops
, /* Type of module */
210 "USB generic serial module"
213 static struct modlinkage modlinkage
= {
214 MODREV_1
, (void *)&modlmisc
, NULL
218 #define RSEQ(f1, f2) RSEQE(f1, usbser_rseq_do_cb, f2, NULL)
222 * loadable module entry points
223 * ----------------------------
231 mutex_init(&usbser_lock
, NULL
, MUTEX_DRIVER
, NULL
);
233 if ((err
= mod_install(&modlinkage
)) != 0)
234 mutex_destroy(&usbser_lock
);
245 if ((err
= mod_remove(&modlinkage
)) != 0)
248 mutex_destroy(&usbser_lock
);
255 _info(struct modinfo
*modinfop
)
257 return (mod_info(&modlinkage
, modinfop
));
265 usbser_soft_state_size()
267 return (sizeof (usbser_state_t
));
272 * autoconfiguration entry points
273 * ------------------------------
278 usbser_getinfo(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
279 void **result
, void *statep
)
282 int ret
= DDI_FAILURE
;
283 usbser_state_t
*usbserp
;
285 instance
= USBSER_MINOR2INST(getminor((dev_t
)arg
));
288 case DDI_INFO_DEVT2DEVINFO
:
290 usbserp
= ddi_get_soft_state(statep
, instance
);
291 if (usbserp
!= NULL
) {
292 *result
= usbserp
->us_dip
;
293 if (*result
!= NULL
) {
299 case DDI_INFO_DEVT2INSTANCE
:
300 *result
= (void *)(uintptr_t)instance
;
314 static rseq_t rseq_att
[] = {
315 RSEQ(NULL
, usbser_free_soft_state
),
316 RSEQ(usbser_init_soft_state
, usbser_fini_soft_state
),
317 RSEQ(usbser_attach_dev
, usbser_detach_dev
),
318 RSEQ(usbser_attach_ports
, usbser_detach_ports
),
319 RSEQ(usbser_create_taskq
, usbser_destroy_taskq
),
320 RSEQ(NULL
, usbser_set_dev_state_init
)
324 usbser_insert(struct usbser_state
*usp
)
326 struct usbser_state
*tmp
;
328 mutex_enter(&usbser_lock
);
337 mutex_exit(&usbser_lock
);
341 usbser_remove(struct usbser_state
*usp
)
343 struct usbser_state
*tmp
, *prev
= NULL
;
345 mutex_enter(&usbser_lock
);
351 ASSERT(tmp
== usp
); /* must exist, else attach/detach wrong */
353 prev
->us_next
= usp
->us_next
;
355 usbser_list
= usp
->us_next
;
357 mutex_exit(&usbser_lock
);
361 * Return the first serial device, with dip held. This is called
362 * from the console subsystem to place console on usb serial device.
365 usbser_first_device(void)
367 dev_info_t
*dip
= NULL
;
369 mutex_enter(&usbser_lock
);
371 dip
= usbser_list
->us_dip
;
374 mutex_exit(&usbser_lock
);
380 usbser_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
,
381 void *statep
, ds_ops_t
*ds_ops
)
386 instance
= ddi_get_instance(dip
);
393 usbser_cpr_resume(dip
);
395 return (DDI_SUCCESS
);
398 return (DDI_FAILURE
);
401 /* allocate and get soft state */
402 if (ddi_soft_state_zalloc(statep
, instance
) != DDI_SUCCESS
) {
404 return (DDI_FAILURE
);
406 if ((usp
= ddi_get_soft_state(statep
, instance
)) == NULL
) {
407 ddi_soft_state_free(statep
, instance
);
409 return (DDI_FAILURE
);
412 usp
->us_statep
= statep
;
414 usp
->us_instance
= instance
;
415 usp
->us_ds_ops
= ds_ops
;
417 if (rseq_do(rseq_att
, NELEM(rseq_att
), (uintptr_t)usp
, 0) == RSEQ_OK
) {
421 return (DDI_SUCCESS
);
424 return (DDI_FAILURE
);
432 usbser_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
, void *statep
)
434 int instance
= ddi_get_instance(dip
);
438 usp
= ddi_get_soft_state(statep
, instance
);
442 USB_DPRINTF_L4(DPRINT_DETACH
, usp
->us_lh
, "usbser_detach");
444 (void) rseq_undo(rseq_att
, NELEM(rseq_att
), (uintptr_t)usp
, 0);
445 USB_DPRINTF_L4(DPRINT_DETACH
, NULL
,
446 "usbser_detach.%d: end", instance
);
448 return (DDI_SUCCESS
);
450 rval
= usbser_cpr_suspend(dip
);
452 return ((rval
== USB_SUCCESS
)? DDI_SUCCESS
: DDI_FAILURE
);
455 return (DDI_FAILURE
);
460 * STREAMS entry points
461 * --------------------
468 usbser_open(queue_t
*rq
, dev_t
*dev
, int flag
, int sflag
, cred_t
*cr
,
473 int minor
= getminor(*dev
);
478 instance
= USBSER_MINOR2INST(minor
);
484 usp
= ddi_get_soft_state(statep
, instance
);
490 /* don't allow to open disconnected device */
491 mutex_enter(&usp
->us_mutex
);
492 if (usp
->us_dev_state
== USB_DEV_DISCONNECTED
) {
493 mutex_exit(&usp
->us_mutex
);
497 mutex_exit(&usp
->us_mutex
);
499 /* get port soft state */
500 port_num
= USBSER_MINOR2PORT(minor
);
501 if (port_num
>= usp
->us_port_cnt
) {
505 pp
= &usp
->us_ports
[port_num
];
507 /* set up everything for open */
508 rval
= usbser_open_setup(rq
, pp
, minor
, flag
, cr
);
510 USB_DPRINTF_L4(DPRINT_OPEN
, pp
->port_lh
, "usbser_open: rval=%d", rval
);
519 * some things driver should do when the last app closes the line:
522 * cancel break/delay;
523 * hangup line (if necessary);
525 * cleanup soft state;
529 usbser_close(queue_t
*rq
, int flag
, cred_t
*cr
)
531 usbser_port_t
*pp
= (usbser_port_t
*)rq
->q_ptr
;
539 online
= usbser_dev_is_online(pp
->port_usp
);
542 * in the closing state new activities will not be initiated
544 mutex_enter(&pp
->port_mutex
);
545 pp
->port_state
= USBSER_PORT_CLOSING
;
549 usbser_close_drain(pp
);
552 /* stop break/delay */
553 usbser_close_cancel_break(pp
);
557 usbser_close_hangup(pp
);
561 * close DSD, cleanup state and transition to 'closed' state
563 usbser_close_cleanup(pp
);
564 mutex_exit(&pp
->port_mutex
);
566 USB_DPRINTF_L4(DPRINT_CLOSE
, pp
->port_lh
, "usbser_close: end");
573 * read side service routine: send as much as possible messages upstream
574 * and if there is still place on the queue, enable receive (if not already)
577 usbser_rsrv(queue_t
*q
)
579 usbser_port_t
*pp
= (usbser_port_t
*)q
->q_ptr
;
583 USB_DPRINTF_L4(DPRINT_RQ
, pp
->port_lh
, "usbser_rsrv");
585 while (canputnext(q
) && (mp
= getq(q
))) {
590 mutex_enter(&pp
->port_mutex
);
591 ASSERT(pp
->port_state
!= USBSER_PORT_CLOSED
);
593 if (USBSER_PORT_ACCESS_OK(pp
)) {
594 usbser_thr_wake(&pp
->port_rq_thread
);
596 mutex_exit(&pp
->port_mutex
);
604 * wput: put message on the queue and wake wq thread
607 usbser_wput(queue_t
*q
, mblk_t
*mp
)
609 usbser_port_t
*pp
= (usbser_port_t
*)q
->q_ptr
;
611 USB_DPRINTF_L4(DPRINT_WQ
, pp
->port_lh
, "usbser_wput");
613 mutex_enter(&pp
->port_mutex
);
614 ASSERT(pp
->port_state
!= USBSER_PORT_CLOSED
);
616 /* ignore new messages if port is already closing */
617 if (pp
->port_state
== USBSER_PORT_CLOSING
) {
619 } else if (putq(q
, mp
)) {
621 * this counter represents amount of tx data on the wq.
622 * each time the data is passed to DSD for transmission,
623 * the counter is decremented accordingly
625 pp
->port_wq_data_cnt
+= msgdsize(mp
);
627 usbser_st_tx_data_loss
++;
629 mutex_exit(&pp
->port_mutex
);
636 * we need wsrv() routine to take advantage of STREAMS flow control:
637 * without it the framework will consider we are always able to process msgs
640 usbser_wsrv(queue_t
*q
)
642 usbser_port_t
*pp
= (usbser_port_t
*)q
->q_ptr
;
644 USB_DPRINTF_L4(DPRINT_WQ
, pp
->port_lh
, "usbser_wsrv");
646 mutex_enter(&pp
->port_mutex
);
647 ASSERT(pp
->port_state
!= USBSER_PORT_CLOSED
);
649 if (USBSER_PORT_ACCESS_OK(pp
)) {
650 usbser_thr_wake(&pp
->port_wq_thread
);
652 mutex_exit(&pp
->port_mutex
);
662 usbser_power(dev_info_t
*dip
, int comp
, int level
)
669 statep
= ddi_get_driver_private(dip
);
670 usp
= ddi_get_soft_state(statep
, ddi_get_instance(dip
));
672 USB_DPRINTF_L3(DPRINT_EVENTS
, usp
->us_lh
,
673 "usbser_power: dip=0x%p, comp=%d, level=%d",
674 (void *)dip
, comp
, level
);
676 mutex_enter(&usp
->us_mutex
);
677 new_state
= usp
->us_dev_state
;
678 mutex_exit(&usp
->us_mutex
);
680 /* let DSD do the job */
681 rval
= USBSER_DS_USB_POWER(usp
, comp
, level
, &new_state
);
683 /* stay in sync with DSD */
684 mutex_enter(&usp
->us_mutex
);
685 usp
->us_dev_state
= new_state
;
686 mutex_exit(&usp
->us_mutex
);
688 return ((rval
== USB_SUCCESS
) ? DDI_SUCCESS
: DDI_FAILURE
);
694 * configuration entry point subroutines
695 * -------------------------------------
700 usbser_rseq_do_cb(rseq_t
*rseq
, int num
, uintptr_t arg
)
702 usbser_state_t
*usp
= (usbser_state_t
*)arg
;
703 int rval
= rseq
[num
].r_do
.s_rval
;
704 char *name
= rseq
[num
].r_do
.s_name
;
706 if (rval
!= DDI_SUCCESS
) {
707 USB_DPRINTF_L2(DPRINT_ATTACH
, usp
->us_lh
,
708 "do %s failed (%d)", name
, rval
);
722 usbser_free_soft_state(usbser_state_t
*usp
)
724 ddi_soft_state_free(usp
->us_statep
, usp
->us_instance
);
726 return (USB_SUCCESS
);
730 * init instance soft state
733 usbser_init_soft_state(usbser_state_t
*usp
)
735 usp
->us_lh
= usb_alloc_log_hdl(usp
->us_dip
, "usbs[*].",
736 &usbser_errlevel
, &usbser_errmask
, &usbser_instance_debug
,
738 mutex_init(&usp
->us_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
740 /* save state pointer for use in event callbacks */
741 ddi_set_driver_private(usp
->us_dip
, usp
->us_statep
);
743 usp
->us_dev_state
= USBSER_DEV_INIT
;
745 return (DDI_SUCCESS
);
749 * fini instance soft state
752 usbser_fini_soft_state(usbser_state_t
*usp
)
754 usb_free_log_hdl(usp
->us_lh
);
755 mutex_destroy(&usp
->us_mutex
);
756 ddi_set_driver_private(usp
->us_dip
, NULL
);
758 return (DDI_SUCCESS
);
762 * attach entire device
765 usbser_attach_dev(usbser_state_t
*usp
)
770 usp
->us_dev_state
= USB_DEV_ONLINE
;
772 ai
.ai_dip
= usp
->us_dip
;
773 ai
.ai_usb_events
= &usbser_usb_events
;
774 ai
.ai_hdl
= &usp
->us_ds_hdl
;
775 ai
.ai_port_cnt
= &usp
->us_port_cnt
;
777 rval
= USBSER_DS_ATTACH(usp
, &ai
);
779 if ((rval
!= USB_SUCCESS
) || (usp
->us_ds_hdl
== NULL
) ||
780 (usp
->us_port_cnt
== 0)) {
781 USB_DPRINTF_L4(DPRINT_ATTACH
, usp
->us_lh
, "usbser_attach_dev: "
782 "failed %d %p %d", rval
, usp
->us_ds_hdl
, usp
->us_port_cnt
);
784 return (DDI_FAILURE
);
787 USB_DPRINTF_L4(DPRINT_ATTACH
, usp
->us_lh
,
788 "usbser_attach_dev: port_cnt = %d", usp
->us_port_cnt
);
790 return (DDI_SUCCESS
);
795 * detach entire device
798 usbser_detach_dev(usbser_state_t
*usp
)
800 USBSER_DS_DETACH(usp
);
805 * attach each individual port
808 usbser_attach_ports(usbser_state_t
*usp
)
815 * allocate port array
817 usp
->us_ports
= kmem_zalloc(usp
->us_port_cnt
*
818 sizeof (usbser_port_t
), KM_SLEEP
);
820 /* callback handlers */
821 ds_cb
.cb_tx
= usbser_tx_cb
;
822 ds_cb
.cb_rx
= usbser_rx_cb
;
823 ds_cb
.cb_status
= usbser_status_cb
;
826 * initialize each port
828 for (i
= 0; i
< usp
->us_port_cnt
; i
++) {
829 pp
= &usp
->us_ports
[i
];
836 pp
->port_ds_ops
= usp
->us_ds_ops
;
837 pp
->port_ds_hdl
= usp
->us_ds_hdl
;
839 /* allocate log handle */
840 (void) sprintf(pp
->port_lh_name
, "usbs[%d].", i
);
841 pp
->port_lh
= usb_alloc_log_hdl(usp
->us_dip
,
842 pp
->port_lh_name
, &usbser_errlevel
, &usbser_errmask
,
843 &usbser_instance_debug
, 0);
845 mutex_init(&pp
->port_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
846 cv_init(&pp
->port_state_cv
, NULL
, CV_DEFAULT
, NULL
);
847 cv_init(&pp
->port_act_cv
, NULL
, CV_DEFAULT
, NULL
);
848 cv_init(&pp
->port_car_cv
, NULL
, CV_DEFAULT
, NULL
);
853 pp
->port_wq_thread
.thr_port
= pp
;
854 pp
->port_wq_thread
.thr_func
= usbser_wq_thread
;
855 pp
->port_wq_thread
.thr_arg
= (void *)&pp
->port_wq_thread
;
856 cv_init(&pp
->port_wq_thread
.thr_cv
, NULL
, CV_DEFAULT
, NULL
);
858 pp
->port_rq_thread
.thr_port
= pp
;
859 pp
->port_rq_thread
.thr_func
= usbser_rq_thread
;
860 pp
->port_rq_thread
.thr_arg
= (void *)&pp
->port_rq_thread
;
861 cv_init(&pp
->port_rq_thread
.thr_cv
, NULL
, CV_DEFAULT
, NULL
);
866 ds_cb
.cb_arg
= (caddr_t
)pp
;
867 USBSER_DS_REGISTER_CB(usp
, i
, &ds_cb
);
869 pp
->port_state
= USBSER_PORT_CLOSED
;
871 if (usbser_create_port_minor_nodes(usp
, i
) != USB_SUCCESS
) {
872 usbser_detach_ports(usp
);
874 return (DDI_FAILURE
);
878 return (DDI_SUCCESS
);
883 * create a pair of minor nodes for the port
886 usbser_create_port_minor_nodes(usbser_state_t
*usp
, int port_num
)
888 int instance
= usp
->us_instance
;
895 (void) sprintf(name
, "%d", port_num
);
896 minor
= USBSER_MAKEMINOR(instance
, port_num
, 0);
898 if (ddi_create_minor_node(usp
->us_dip
, name
,
899 S_IFCHR
, minor
, DDI_NT_SERIAL
, 0) != DDI_SUCCESS
) {
901 return (USB_FAILURE
);
907 (void) sprintf(name
, "%d,cu", port_num
);
908 minor
= USBSER_MAKEMINOR(instance
, port_num
, OUTLINE
);
910 if (ddi_create_minor_node(usp
->us_dip
, name
,
911 S_IFCHR
, minor
, DDI_NT_SERIAL_DO
, 0) != DDI_SUCCESS
) {
913 return (USB_FAILURE
);
916 return (USB_SUCCESS
);
921 * detach each port individually
924 usbser_detach_ports(usbser_state_t
*usp
)
931 * remove all minor nodes
933 ddi_remove_minor_node(usp
->us_dip
, NULL
);
935 for (i
= 0; i
< usp
->us_port_cnt
; i
++) {
936 pp
= &usp
->us_ports
[i
];
938 if (pp
->port_state
!= USBSER_PORT_CLOSED
) {
939 ASSERT(pp
->port_state
== USBSER_PORT_NOT_INIT
);
944 USBSER_DS_UNREGISTER_CB(usp
, i
);
946 mutex_destroy(&pp
->port_mutex
);
947 cv_destroy(&pp
->port_state_cv
);
948 cv_destroy(&pp
->port_act_cv
);
949 cv_destroy(&pp
->port_car_cv
);
951 cv_destroy(&pp
->port_wq_thread
.thr_cv
);
952 cv_destroy(&pp
->port_rq_thread
.thr_cv
);
954 usb_free_log_hdl(pp
->port_lh
);
960 sz
= usp
->us_port_cnt
* sizeof (usbser_port_t
);
961 kmem_free(usp
->us_ports
, sz
);
962 usp
->us_ports
= NULL
;
967 * create a taskq with two threads per port (read and write sides)
970 usbser_create_taskq(usbser_state_t
*usp
)
972 int nthr
= usp
->us_port_cnt
* 2;
974 usp
->us_taskq
= ddi_taskq_create(usp
->us_dip
, "usbser_taskq",
975 nthr
, TASKQ_DEFAULTPRI
, 0);
977 return ((usp
->us_taskq
== NULL
) ? DDI_FAILURE
: DDI_SUCCESS
);
982 usbser_destroy_taskq(usbser_state_t
*usp
)
984 ddi_taskq_destroy(usp
->us_taskq
);
989 usbser_set_dev_state_init(usbser_state_t
*usp
)
991 mutex_enter(&usp
->us_mutex
);
992 usp
->us_dev_state
= USBSER_DEV_INIT
;
993 mutex_exit(&usp
->us_mutex
);
997 * hotplugging and power management
998 * ---------------------------------
1000 * disconnect event callback
1004 usbser_disconnect_cb(dev_info_t
*dip
)
1007 usbser_state_t
*usp
;
1009 statep
= ddi_get_driver_private(dip
);
1010 usp
= ddi_get_soft_state(statep
, ddi_get_instance(dip
));
1012 USB_DPRINTF_L3(DPRINT_EVENTS
, usp
->us_lh
,
1013 "usbser_disconnect_cb: dip=%p", (void *)dip
);
1015 mutex_enter(&usp
->us_mutex
);
1016 switch (usp
->us_dev_state
) {
1017 case USB_DEV_ONLINE
:
1018 case USB_DEV_PWRED_DOWN
:
1019 /* prevent further activity */
1020 usp
->us_dev_state
= USB_DEV_DISCONNECTED
;
1021 mutex_exit(&usp
->us_mutex
);
1023 /* see if any of the ports are open and do necessary handling */
1024 usbser_disconnect_ports(usp
);
1026 /* call DSD to do any necessary work */
1027 if (USBSER_DS_DISCONNECT(usp
) != USB_DEV_DISCONNECTED
) {
1028 USB_DPRINTF_L2(DPRINT_EVENTS
, usp
->us_lh
,
1029 "usbser_disconnect_cb: ds_disconnect failed");
1033 case USB_DEV_SUSPENDED
:
1034 /* we remain suspended */
1036 mutex_exit(&usp
->us_mutex
);
1041 return (USB_SUCCESS
);
1046 * reconnect event callback
1050 usbser_reconnect_cb(dev_info_t
*dip
)
1053 usbser_state_t
*usp
;
1055 statep
= ddi_get_driver_private(dip
);
1056 usp
= ddi_get_soft_state(statep
, ddi_get_instance(dip
));
1058 USB_DPRINTF_L3(DPRINT_EVENTS
, usp
->us_lh
,
1059 "usbser_reconnect_cb: dip=%p", (void *)dip
);
1061 (void) usbser_restore_device_state(usp
);
1063 return (USB_SUCCESS
);
1068 * if any of the ports is open during disconnect,
1069 * send M_HANGUP message upstream and log a warning
1072 usbser_disconnect_ports(usbser_state_t
*usp
)
1078 timeout_id_t delay_id
= 0;
1081 if (usp
->us_ports
== NULL
) {
1085 for (i
= 0; i
< usp
->us_port_cnt
; i
++) {
1086 pp
= &usp
->us_ports
[i
];
1088 mutex_enter(&pp
->port_mutex
);
1089 if (pp
->port_state
== USBSER_PORT_OPEN
||
1090 USBSER_IS_OPENING(pp
) ||
1091 pp
->port_state
== USBSER_PORT_CLOSING
) {
1095 if (pp
->port_state
== USBSER_PORT_OPEN
) {
1096 rq
= pp
->port_ttycommon
.t_readq
;
1099 * hangup the stream; will send actual
1100 * M_HANGUP message after releasing mutex
1102 pp
->port_flags
|= USBSER_FL_HUNGUP
;
1106 * cancel all activities
1108 usbser_release_port_act(pp
, USBSER_ACT_ALL
);
1110 delay_id
= pp
->port_delay_id
;
1111 pp
->port_delay_id
= 0;
1113 /* mark disconnected */
1114 pp
->port_state
= USBSER_PORT_DISCONNECTED
;
1115 cv_broadcast(&pp
->port_state_cv
);
1117 mutex_exit(&pp
->port_mutex
);
1120 (void) putnextctl(rq
, M_HANGUP
);
1125 * we couldn't untimeout while holding the mutex - do it now
1128 (void) untimeout(delay_id
);
1134 * complain about disconnecting device while open
1137 USB_DPRINTF_L0(DPRINT_EVENTS
, usp
->us_lh
, "device was "
1138 "disconnected while open. Data may have been lost");
1146 * We use a trivial CPR strategy - fail if any of the device's ports are open.
1147 * The problem with more sophisticated strategies is that each open port uses
1148 * two threads that sit in the loop until the port is closed, while CPR has to
1149 * stop all kernel threads to succeed. Stopping port threads is a rather
1150 * intrusive and delicate procedure; I leave it as an RFE for now.
1154 usbser_cpr_suspend(dev_info_t
*dip
)
1157 usbser_state_t
*usp
;
1161 statep
= ddi_get_driver_private(dip
);
1162 usp
= ddi_get_soft_state(statep
, ddi_get_instance(dip
));
1164 USB_DPRINTF_L4(DPRINT_EVENTS
, usp
->us_lh
, "usbser_cpr_suspend");
1166 /* suspend each port first */
1167 if (usbser_suspend_ports(usp
) != USB_SUCCESS
) {
1168 USB_DPRINTF_L3(DPRINT_EVENTS
, usp
->us_lh
,
1169 "usbser_cpr_suspend: GSD failure");
1171 return (USB_FAILURE
);
1174 new_state
= USBSER_DS_SUSPEND(usp
); /* let DSD do its part */
1176 mutex_enter(&usp
->us_mutex
);
1177 if (new_state
== USB_DEV_SUSPENDED
) {
1180 ASSERT(new_state
== USB_DEV_ONLINE
);
1183 usp
->us_dev_state
= new_state
;
1184 mutex_exit(&usp
->us_mutex
);
1191 usbser_suspend_ports(usbser_state_t
*usp
)
1196 for (i
= 0; i
< usp
->us_port_cnt
; i
++) {
1197 pp
= &usp
->us_ports
[i
];
1199 mutex_enter(&pp
->port_mutex
);
1200 if (pp
->port_state
!= USBSER_PORT_CLOSED
) {
1201 mutex_exit(&pp
->port_mutex
);
1203 return (USB_FAILURE
);
1205 mutex_exit(&pp
->port_mutex
);
1208 return (USB_SUCCESS
);
1215 * DSD will return USB_DEV_ONLINE in case of success
1218 usbser_cpr_resume(dev_info_t
*dip
)
1221 usbser_state_t
*usp
;
1223 statep
= ddi_get_driver_private(dip
);
1224 usp
= ddi_get_soft_state(statep
, ddi_get_instance(dip
));
1226 USB_DPRINTF_L3(DPRINT_EVENTS
, usp
->us_lh
, "usbser_cpr_resume");
1228 (void) usbser_restore_device_state(usp
);
1233 * restore device state after CPR resume or reconnect
1236 usbser_restore_device_state(usbser_state_t
*usp
)
1238 int new_state
, current_state
;
1240 /* needed as power up state of dev is "unknown" to system */
1241 (void) pm_busy_component(usp
->us_dip
, 0);
1242 (void) pm_raise_power(usp
->us_dip
, 0, USB_DEV_OS_FULL_PWR
);
1244 mutex_enter(&usp
->us_mutex
);
1245 current_state
= usp
->us_dev_state
;
1246 mutex_exit(&usp
->us_mutex
);
1248 ASSERT((current_state
== USB_DEV_DISCONNECTED
) ||
1249 (current_state
== USB_DEV_SUSPENDED
));
1252 * call DSD to perform device-specific work
1254 if (current_state
== USB_DEV_DISCONNECTED
) {
1255 new_state
= USBSER_DS_RECONNECT(usp
);
1257 new_state
= USBSER_DS_RESUME(usp
);
1260 mutex_enter(&usp
->us_mutex
);
1261 usp
->us_dev_state
= new_state
;
1262 mutex_exit(&usp
->us_mutex
);
1264 if (new_state
== USB_DEV_ONLINE
) {
1266 * restore ports state
1268 usbser_restore_ports_state(usp
);
1271 (void) pm_idle_component(usp
->us_dip
, 0);
1273 return (USB_SUCCESS
);
1278 * restore ports state after device reconnect/resume
1281 usbser_restore_ports_state(usbser_state_t
*usp
)
1287 for (i
= 0; i
< usp
->us_port_cnt
; i
++) {
1288 pp
= &usp
->us_ports
[i
];
1290 mutex_enter(&pp
->port_mutex
);
1292 * only care about ports that are open
1294 if ((pp
->port_state
!= USBSER_PORT_SUSPENDED
) &&
1295 (pp
->port_state
!= USBSER_PORT_DISCONNECTED
)) {
1296 mutex_exit(&pp
->port_mutex
);
1301 pp
->port_state
= USBSER_PORT_OPEN
;
1304 * if the stream was hung up during disconnect, restore it
1306 if (pp
->port_flags
& USBSER_FL_HUNGUP
) {
1307 pp
->port_flags
&= ~USBSER_FL_HUNGUP
;
1308 rq
= pp
->port_ttycommon
.t_readq
;
1310 mutex_exit(&pp
->port_mutex
);
1311 (void) putnextctl(rq
, M_UNHANGUP
);
1312 mutex_enter(&pp
->port_mutex
);
1316 * restore serial parameters
1318 (void) usbser_port_program(pp
);
1321 * wake anything that might be sleeping
1323 cv_broadcast(&pp
->port_state_cv
);
1324 cv_broadcast(&pp
->port_act_cv
);
1325 usbser_thr_wake(&pp
->port_wq_thread
);
1326 usbser_thr_wake(&pp
->port_rq_thread
);
1327 mutex_exit(&pp
->port_mutex
);
1333 * STREAMS subroutines
1334 * -------------------
1337 * port open state machine
1339 * here's a list of things that the driver has to do while open;
1340 * because device can be opened any number of times,
1341 * initial open has additional responsibilities:
1343 * if (initial_open) {
1344 * initialize soft state; \
1345 * DSD open; - see usbser_open_init()
1346 * dispatch threads; /
1349 * wait for carrier (if necessary);
1351 * we should also take into consideration that two threads can try to open
1352 * the same physical port simultaneously (/dev/term/N and /dev/cua/N).
1356 * >0 - fail with this error code;
1359 usbser_open_setup(queue_t
*rq
, usbser_port_t
*pp
, int minor
, int flag
,
1362 int rval
= USBSER_CONTINUE
;
1364 mutex_enter(&pp
->port_mutex
);
1366 * refer to port state diagram in the header file
1369 switch (pp
->port_state
) {
1370 case USBSER_PORT_CLOSED
:
1374 rval
= usbser_open_init(pp
, minor
);
1377 case USBSER_PORT_OPENING_TTY
:
1379 * dial-out thread can overtake the port
1380 * if tty open thread is sleeping waiting for carrier
1382 if ((minor
& OUTLINE
) && (pp
->port_flags
& USBSER_FL_WOPEN
)) {
1383 pp
->port_state
= USBSER_PORT_OPENING_OUT
;
1385 USB_DPRINTF_L3(DPRINT_OPEN
, pp
->port_lh
,
1386 "usbser_open_state: overtake");
1390 case USBSER_PORT_OPENING_OUT
:
1392 * if no other open in progress, setup the line
1394 if (USBSER_NO_OTHER_OPEN(pp
, minor
)) {
1395 rval
= usbser_open_line_setup(pp
, minor
, flag
);
1401 case USBSER_PORT_CLOSING
:
1403 * wait until close active phase ends
1405 if (cv_wait_sig(&pp
->port_state_cv
, &pp
->port_mutex
) == 0) {
1410 case USBSER_PORT_OPEN
:
1411 if ((pp
->port_ttycommon
.t_flags
& TS_XCLUDE
) &&
1412 secpolicy_excl_open(cr
) != 0) {
1417 } else if (USBSER_OPEN_IN_OTHER_MODE(pp
, minor
)) {
1419 * tty and dial-out modes are mutually exclusive
1424 * port is being re-open in the same mode
1426 rval
= usbser_open_line_setup(pp
, minor
, flag
);
1436 if (rval
== USBSER_CONTINUE
) {
1442 * initial open requires additional handling
1444 if (USBSER_IS_OPENING(pp
)) {
1445 if (rval
== USBSER_COMPLETE
) {
1446 if (pp
->port_state
== USBSER_PORT_OPENING_OUT
) {
1447 pp
->port_flags
|= USBSER_FL_OUT
;
1449 pp
->port_state
= USBSER_PORT_OPEN
;
1450 cv_broadcast(&pp
->port_state_cv
);
1452 usbser_open_queues_init(pp
, rq
);
1454 usbser_open_fini(pp
);
1457 mutex_exit(&pp
->port_mutex
);
1464 * initialize the port when opened for the first time
1467 usbser_open_init(usbser_port_t
*pp
, int minor
)
1469 usbser_state_t
*usp
= pp
->port_usp
;
1470 tty_common_t
*tp
= &pp
->port_ttycommon
;
1473 ASSERT(pp
->port_state
== USBSER_PORT_CLOSED
);
1479 pp
->port_flags
&= USBSER_FL_PRESERVE
;
1480 pp
->port_flowc
= '\0';
1481 pp
->port_wq_data_cnt
= 0;
1483 if (minor
& OUTLINE
) {
1484 pp
->port_state
= USBSER_PORT_OPENING_OUT
;
1486 pp
->port_state
= USBSER_PORT_OPENING_TTY
;
1490 * init termios settings
1493 tp
->t_iocpending
= NULL
;
1494 tp
->t_size
.ws_row
= tp
->t_size
.ws_col
= 0;
1495 tp
->t_size
.ws_xpixel
= tp
->t_size
.ws_ypixel
= 0;
1496 tp
->t_startc
= CSTART
;
1497 tp
->t_stopc
= CSTOP
;
1499 usbser_check_port_props(pp
);
1502 * dispatch wq and rq threads:
1503 * although queues are not enabled at this point,
1504 * we will need wq to run status processing callback
1506 usbser_thr_dispatch(&pp
->port_wq_thread
);
1507 usbser_thr_dispatch(&pp
->port_rq_thread
);
1512 mutex_exit(&pp
->port_mutex
);
1513 rval
= USBSER_DS_OPEN_PORT(usp
, pp
->port_num
);
1514 mutex_enter(&pp
->port_mutex
);
1516 if (rval
!= USB_SUCCESS
) {
1520 pp
->port_flags
|= USBSER_FL_DSD_OPEN
;
1523 * program port with default parameters
1525 if ((rval
= usbser_port_program(pp
)) != 0) {
1530 return (USBSER_CONTINUE
);
1535 * create a pair of minor nodes for the port
1538 usbser_check_port_props(usbser_port_t
*pp
)
1540 dev_info_t
*dip
= pp
->port_usp
->us_dip
;
1541 tty_common_t
*tp
= &pp
->port_ttycommon
;
1542 struct termios
*termiosp
;
1547 * take default modes from "ttymodes" property if it exists
1549 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY
, ddi_root_node(), 0,
1550 "ttymodes", (uchar_t
**)&termiosp
, &len
) == DDI_PROP_SUCCESS
) {
1552 if (len
== sizeof (struct termios
)) {
1553 tp
->t_cflag
= termiosp
->c_cflag
;
1555 if (termiosp
->c_iflag
& (IXON
| IXANY
)) {
1557 termiosp
->c_iflag
& (IXON
| IXANY
);
1558 tp
->t_startc
= termiosp
->c_cc
[VSTART
];
1559 tp
->t_stopc
= termiosp
->c_cc
[VSTOP
];
1562 ddi_prop_free(termiosp
);
1566 * look for "ignore-cd" or "port-N-ignore-cd" property
1568 (void) sprintf(name
, "port-%d-ignore-cd", pp
->port_num
);
1569 if (ddi_prop_get_int(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
1571 ddi_prop_get_int(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
, name
, 0)) {
1572 pp
->port_flags
|= USBSER_FL_IGNORE_CD
;
1574 pp
->port_flags
&= ~USBSER_FL_IGNORE_CD
;
1580 * undo what was done in usbser_open_init()
1583 usbser_open_fini(usbser_port_t
*pp
)
1585 uint_t port_num
= pp
->port_num
;
1586 usbser_state_t
*usp
= pp
->port_usp
;
1589 * close DSD if it is open
1591 if (pp
->port_flags
& USBSER_FL_DSD_OPEN
) {
1592 mutex_exit(&pp
->port_mutex
);
1593 if (USBSER_DS_CLOSE_PORT(usp
, port_num
) != USB_SUCCESS
) {
1594 USB_DPRINTF_L2(DPRINT_CLOSE
, pp
->port_lh
,
1595 "usbser_open_fini: CLOSE_PORT fail");
1597 mutex_enter(&pp
->port_mutex
);
1603 usbser_thr_cancel(&pp
->port_wq_thread
);
1604 usbser_thr_cancel(&pp
->port_rq_thread
);
1607 * unpdate soft state
1609 pp
->port_state
= USBSER_PORT_CLOSED
;
1610 cv_broadcast(&pp
->port_state_cv
);
1611 cv_broadcast(&pp
->port_car_cv
);
1619 usbser_open_line_setup(usbser_port_t
*pp
, int minor
, int flag
)
1623 mutex_exit(&pp
->port_mutex
);
1625 * prevent opening a disconnected device
1627 if (!usbser_dev_is_online(pp
->port_usp
)) {
1628 mutex_enter(&pp
->port_mutex
);
1633 /* raise DTR on every open */
1634 (void) USBSER_DS_SET_MODEM_CTL(pp
, TIOCM_DTR
, TIOCM_DTR
);
1636 mutex_enter(&pp
->port_mutex
);
1640 rval
= usbser_open_carrier_check(pp
, minor
, flag
);
1647 * check carrier and wait if needed
1650 usbser_open_carrier_check(usbser_port_t
*pp
, int minor
, int flag
)
1652 tty_common_t
*tp
= &pp
->port_ttycommon
;
1656 if (pp
->port_flags
& USBSER_FL_IGNORE_CD
) {
1657 tp
->t_flags
|= TS_SOFTCAR
;
1663 if (tp
->t_flags
& TS_SOFTCAR
) {
1664 pp
->port_flags
|= USBSER_FL_CARR_ON
;
1665 } else if (USBSER_DS_GET_MODEM_CTL(pp
, TIOCM_CD
, &val
) != USB_SUCCESS
) {
1668 } else if (val
& TIOCM_CD
) {
1669 pp
->port_flags
|= USBSER_FL_CARR_ON
;
1671 pp
->port_flags
&= ~USBSER_FL_CARR_ON
;
1675 * don't block if 1) not allowed to, 2) this is a local device,
1676 * 3) opening in dial-out mode, or 4) carrier is already on
1678 if ((flag
& (FNDELAY
| FNONBLOCK
)) || (tp
->t_cflag
& CLOCAL
) ||
1679 (minor
& OUTLINE
) || (pp
->port_flags
& USBSER_FL_CARR_ON
)) {
1681 return (USBSER_COMPLETE
);
1685 * block until carrier up (only in tty mode)
1687 USB_DPRINTF_L4(DPRINT_OPEN
, pp
->port_lh
,
1688 "usbser_open_carrier_check: waiting for carrier...");
1690 pp
->port_flags
|= USBSER_FL_WOPEN
;
1692 rval
= cv_wait_sig(&pp
->port_car_cv
, &pp
->port_mutex
);
1694 pp
->port_flags
&= ~USBSER_FL_WOPEN
;
1698 * interrupted with a signal
1705 return (USBSER_CONTINUE
);
1711 * during open, setup queues and message processing
1714 usbser_open_queues_init(usbser_port_t
*pp
, queue_t
*rq
)
1716 pp
->port_ttycommon
.t_readq
= rq
;
1717 pp
->port_ttycommon
.t_writeq
= WR(rq
);
1718 rq
->q_ptr
= WR(rq
)->q_ptr
= (caddr_t
)pp
;
1725 * clean up queues and message processing
1728 usbser_open_queues_fini(usbser_port_t
*pp
)
1730 queue_t
*rq
= pp
->port_ttycommon
.t_readq
;
1732 mutex_exit(&pp
->port_mutex
);
1739 * free unused messages
1741 flushq(rq
, FLUSHALL
);
1742 flushq(WR(rq
), FLUSHALL
);
1744 rq
->q_ptr
= WR(rq
)->q_ptr
= NULL
;
1745 ttycommon_close(&pp
->port_ttycommon
);
1746 mutex_enter(&pp
->port_mutex
);
1751 * during close, wait until pending data is gone or the signal is sent
1754 usbser_close_drain(usbser_port_t
*pp
)
1758 int rval
= USB_SUCCESS
;
1761 * port_wq_data_cnt indicates amount of data on the write queue,
1762 * which becomes zero when all data is submitted to DSD. But usbser
1763 * stays busy until it gets tx callback from DSD, signalling that
1764 * data has been sent over USB. To be continued in the next comment...
1766 until
= ddi_get_lbolt() +
1767 drv_usectohz(USBSER_WQ_DRAIN_TIMEOUT
* 1000000);
1769 while ((pp
->port_wq_data_cnt
> 0) && USBSER_PORT_IS_BUSY(pp
)) {
1770 if ((rval
= cv_timedwait_sig(&pp
->port_act_cv
, &pp
->port_mutex
,
1777 /* don't drain if timed out or received a signal */
1778 need_drain
= (pp
->port_wq_data_cnt
== 0) || !USBSER_PORT_IS_BUSY(pp
) ||
1779 (rval
!= USB_SUCCESS
);
1781 mutex_exit(&pp
->port_mutex
);
1783 * Once the data reaches USB serial box, it may still be stored in its
1784 * internal output buffer (FIFO). We call DSD drain to ensure that all
1785 * the data is transmitted transmitted over the serial line.
1788 rval
= USBSER_DS_FIFO_DRAIN(pp
, USBSER_TX_FIFO_DRAIN_TIMEOUT
);
1789 if (rval
!= USB_SUCCESS
) {
1790 (void) USBSER_DS_FIFO_FLUSH(pp
, DS_TX
);
1793 (void) USBSER_DS_FIFO_FLUSH(pp
, DS_TX
);
1795 mutex_enter(&pp
->port_mutex
);
1800 * during close, cancel break/delay
1803 usbser_close_cancel_break(usbser_port_t
*pp
)
1805 timeout_id_t delay_id
;
1807 if (pp
->port_act
& USBSER_ACT_BREAK
) {
1808 delay_id
= pp
->port_delay_id
;
1809 pp
->port_delay_id
= 0;
1811 mutex_exit(&pp
->port_mutex
);
1812 (void) untimeout(delay_id
);
1813 (void) USBSER_DS_BREAK_CTL(pp
, DS_OFF
);
1814 mutex_enter(&pp
->port_mutex
);
1816 pp
->port_act
&= ~USBSER_ACT_BREAK
;
1822 * during close, drop RTS/DTR if necessary
1825 usbser_close_hangup(usbser_port_t
*pp
)
1828 * drop DTR and RTS if HUPCL is set
1830 if (pp
->port_ttycommon
.t_cflag
& HUPCL
) {
1831 mutex_exit(&pp
->port_mutex
);
1832 (void) USBSER_DS_SET_MODEM_CTL(pp
, TIOCM_RTS
| TIOCM_DTR
, 0);
1833 mutex_enter(&pp
->port_mutex
);
1839 * state cleanup during close
1842 usbser_close_cleanup(usbser_port_t
*pp
)
1844 usbser_open_queues_fini(pp
);
1846 usbser_open_fini(pp
);
1859 usbser_thr_dispatch(usbser_thread_t
*thr
)
1861 usbser_port_t
*pp
= thr
->thr_port
;
1862 usbser_state_t
*usp
= pp
->port_usp
;
1865 ASSERT(mutex_owned(&pp
->port_mutex
));
1866 ASSERT((thr
->thr_flags
& USBSER_THR_RUNNING
) == 0);
1868 thr
->thr_flags
= USBSER_THR_RUNNING
;
1870 rval
= ddi_taskq_dispatch(usp
->us_taskq
, thr
->thr_func
, thr
->thr_arg
,
1872 ASSERT(rval
== DDI_SUCCESS
);
1880 usbser_thr_cancel(usbser_thread_t
*thr
)
1882 usbser_port_t
*pp
= thr
->thr_port
;
1884 ASSERT(mutex_owned(&pp
->port_mutex
));
1886 thr
->thr_flags
&= ~USBSER_THR_RUNNING
;
1887 cv_signal(&thr
->thr_cv
);
1889 /* wait until the thread actually exits */
1891 cv_wait(&thr
->thr_cv
, &pp
->port_mutex
);
1893 } while ((thr
->thr_flags
& USBSER_THR_EXITED
) == 0);
1901 usbser_thr_wake(usbser_thread_t
*thr
)
1903 ASSERT(mutex_owned(&thr
->thr_port
->port_mutex
));
1905 thr
->thr_flags
|= USBSER_THR_WAKE
;
1906 cv_signal(&thr
->thr_cv
);
1911 * thread handling write queue requests
1914 usbser_wq_thread(void *arg
)
1916 usbser_thread_t
*thr
= (usbser_thread_t
*)arg
;
1917 usbser_port_t
*pp
= thr
->thr_port
;
1919 USB_DPRINTF_L4(DPRINT_WQ
, pp
->port_lh
, "usbser_wq_thread: enter");
1921 mutex_enter(&pp
->port_mutex
);
1922 while (thr
->thr_flags
& USBSER_THR_RUNNING
) {
1924 * when woken, see what we should do
1926 if (thr
->thr_flags
& USBSER_THR_WAKE
) {
1927 thr
->thr_flags
&= ~USBSER_THR_WAKE
;
1930 * status callback pending?
1932 if (pp
->port_flags
& USBSER_FL_STATUS_CB
) {
1933 usbser_status_proc_cb(pp
);
1939 * sleep until woken up to do some work, e.g:
1940 * - new message arrives;
1941 * - data transmit completes;
1942 * - status callback pending;
1943 * - wq thread is cancelled;
1945 cv_wait(&thr
->thr_cv
, &pp
->port_mutex
);
1946 USB_DPRINTF_L4(DPRINT_WQ
, pp
->port_lh
,
1947 "usbser_wq_thread: wakeup");
1950 thr
->thr_flags
|= USBSER_THR_EXITED
;
1951 cv_signal(&thr
->thr_cv
);
1952 USB_DPRINTF_L4(DPRINT_WQ
, pp
->port_lh
, "usbser_wq_thread: exit");
1953 mutex_exit(&pp
->port_mutex
);
1958 * thread handling read queue requests
1961 usbser_rq_thread(void *arg
)
1963 usbser_thread_t
*thr
= (usbser_thread_t
*)arg
;
1964 usbser_port_t
*pp
= thr
->thr_port
;
1966 USB_DPRINTF_L4(DPRINT_WQ
, pp
->port_lh
, "usbser_rq_thread: enter");
1968 mutex_enter(&pp
->port_mutex
);
1969 while (thr
->thr_flags
& USBSER_THR_RUNNING
) {
1971 * read service routine will wake us when
1972 * more space is available on the read queue
1974 if (thr
->thr_flags
& USBSER_THR_WAKE
) {
1975 thr
->thr_flags
&= ~USBSER_THR_WAKE
;
1978 * don't process messages until queue is enabled
1980 if (!pp
->port_ttycommon
.t_readq
) {
1986 * check whether we need to resume receive
1988 if (pp
->port_flags
& USBSER_FL_RX_STOPPED
) {
1989 pp
->port_flowc
= pp
->port_ttycommon
.t_startc
;
1990 usbser_inbound_flow_ctl(pp
);
1994 * grab more data if available
1996 mutex_exit(&pp
->port_mutex
);
1997 usbser_rx_cb((caddr_t
)pp
);
1998 mutex_enter(&pp
->port_mutex
);
2000 cv_wait(&thr
->thr_cv
, &pp
->port_mutex
);
2001 USB_DPRINTF_L4(DPRINT_WQ
, pp
->port_lh
,
2002 "usbser_rq_thread: wakeup");
2005 thr
->thr_flags
|= USBSER_THR_EXITED
;
2006 cv_signal(&thr
->thr_cv
);
2007 USB_DPRINTF_L4(DPRINT_RQ
, pp
->port_lh
, "usbser_rq_thread: exit");
2008 mutex_exit(&pp
->port_mutex
);
2016 * Note: to avoid deadlocks with DSD, these callbacks
2017 * should not call DSD functions that can block.
2022 * invoked by DSD when the last byte of data is transmitted over USB
2025 usbser_tx_cb(caddr_t arg
)
2027 usbser_port_t
*pp
= (usbser_port_t
*)arg
;
2030 online
= usbser_dev_is_online(pp
->port_usp
);
2032 mutex_enter(&pp
->port_mutex
);
2033 USB_DPRINTF_L4(DPRINT_TX_CB
, pp
->port_lh
,
2034 "usbser_tx_cb: act=%x curthread=%p", pp
->port_act
,
2037 usbser_release_port_act(pp
, USBSER_ACT_TX
);
2040 * as long as port access is ok and the port is not busy on
2041 * TX, break, ctrl or delay, the wq_thread should be waken
2042 * to do further process for next message
2044 if (online
&& USBSER_PORT_ACCESS_OK(pp
) &&
2045 !USBSER_PORT_IS_BUSY_NON_RX(pp
)) {
2047 * wake wq thread for further data/ioctl processing
2049 usbser_thr_wake(&pp
->port_wq_thread
);
2051 mutex_exit(&pp
->port_mutex
);
2058 * invoked by DSD when there is more data for us to pick
2061 usbser_rx_cb(caddr_t arg
)
2063 usbser_port_t
*pp
= (usbser_port_t
*)arg
;
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 */
2069 USB_DPRINTF_L4(DPRINT_RX_CB
, pp
->port_lh
, "usbser_rx_cb");
2071 if (!usbser_dev_is_online(pp
->port_usp
)) {
2076 /* get data from DSD */
2077 if ((mp
= USBSER_DS_RX(pp
)) == NULL
) {
2082 mutex_enter(&pp
->port_mutex
);
2083 if ((!USBSER_PORT_ACCESS_OK(pp
)) ||
2084 ((pp
->port_ttycommon
.t_cflag
& CREAD
) == 0)) {
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");
2093 usbser_serialize_port_act(pp
, USBSER_ACT_RX
);
2095 rq
= pp
->port_ttycommon
.t_readq
;
2096 wq
= pp
->port_ttycommon
.t_writeq
;
2097 mutex_exit(&pp
->port_mutex
);
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.
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.
2109 data
= data_tail
= NULL
;
2112 * skip data until we meet M_BREAK or end of list
2114 if (DB_TYPE(mp
) == M_DATA
) {
2124 /* detach data list from mp */
2126 data_tail
->b_cont
= NULL
;
2128 /* detach emp from the list */
2133 /* DSD shouldn't send anything but M_DATA or M_BREAK */
2134 if ((DB_TYPE(emp
) != M_BREAK
) || (MBLKL(emp
) != 2)) {
2136 USB_DPRINTF_L2(DPRINT_RX_CB
, pp
->port_lh
,
2137 "usbser_rx_cb: bad message");
2143 * first tweak and send M_DATA's
2146 usbser_rx_massage_data(pp
, data
);
2147 usbser_rx_cb_put(pp
, rq
, wq
, data
);
2148 data
= data_tail
= NULL
;
2152 * now tweak and send M_BREAK
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
);
2160 /* send the rest of the data, if any */
2162 usbser_rx_massage_data(pp
, data
);
2163 usbser_rx_cb_put(pp
, rq
, wq
, data
);
2166 mutex_enter(&pp
->port_mutex
);
2167 usbser_release_port_act(pp
, USBSER_ACT_RX
);
2168 mutex_exit(&pp
->port_mutex
);
2172 * the joys of termio -- this is to accomodate Unix98 assertion:
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'.
2178 * Posix Ref: Assertion 7.1.2.2-16(C)
2180 * this requires the driver to scan every incoming valid character
2183 usbser_rx_massage_data(usbser_port_t
*pp
, mblk_t
*mp
)
2185 tty_common_t
*tp
= &pp
->port_ttycommon
;
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
);
2199 mutex_exit(&pp
->port_mutex
);
2202 for (p
= mp
->b_rptr
; p
< mp
->b_wptr
; ) {
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,
2213 * insert another 0377 after this one. all data after
2214 * the original 0377 have to be copied to the new mblk
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");
2224 /* fill in the new mblk */
2225 *newmp
->b_wptr
++ = 0377;
2227 bcopy(p
, newmp
->b_wptr
, tailsz
);
2228 newmp
->b_wptr
+= tailsz
;
2230 /* shrink the original mblk */
2233 newmp
->b_cont
= mp
->b_cont
;
2235 p
= newmp
->b_rptr
+ 1;
2243 * more joys of termio
2246 usbser_rx_massage_mbreak(usbser_port_t
*pp
, mblk_t
*mp
)
2248 tty_common_t
*tp
= &pp
->port_ttycommon
;
2252 c
= *(mp
->b_rptr
+ 1);
2254 if ((err
& (DS_FRAMING_ERR
| DS_BREAK_ERR
)) && (c
== 0)) {
2257 } else if (!(tp
->t_iflag
& INPCK
) && (err
& (DS_PARITY_ERR
))) {
2258 /* Posix Ref: Assertion 7.1.2.2-20(C) */
2260 DB_TYPE(mp
) = M_DATA
;
2262 /* for ldterm to handle */
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);
2273 * in rx callback, try to send an mblk upstream
2276 usbser_rx_cb_put(usbser_port_t
*pp
, queue_t
*rq
, queue_t
*wq
, mblk_t
*mp
)
2278 if (canputnext(rq
)) {
2280 } else if (canput(rq
) && putq(rq
, mp
)) {
2282 * full queue indicates the need for inbound flow control
2284 (void) putctl(wq
, M_STOPI
);
2285 usbser_st_put_stopi
++;
2287 USB_DPRINTF_L3(DPRINT_RX_CB
, pp
->port_lh
,
2288 "usbser_rx_cb: cannot putnext, flow ctl");
2291 usbser_st_rx_data_loss
++;
2292 (void) putctl(wq
, M_STOPI
);
2293 usbser_st_put_stopi
++;
2295 USB_DPRINTF_L1(DPRINT_RX_CB
, pp
->port_lh
,
2302 * modem status change callback
2304 * each time external status lines are changed, DSD calls this routine
2307 usbser_status_cb(caddr_t arg
)
2309 usbser_port_t
*pp
= (usbser_port_t
*)arg
;
2311 USB_DPRINTF_L4(DPRINT_STATUS_CB
, pp
->port_lh
, "usbser_status_cb");
2313 if (!usbser_dev_is_online(pp
->port_usp
)) {
2319 * actual processing will be done in usbser_status_proc_cb()
2320 * running in wq thread
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
);
2327 mutex_exit(&pp
->port_mutex
);
2332 * modem status change
2335 usbser_status_proc_cb(usbser_port_t
*pp
)
2337 tty_common_t
*tp
= &pp
->port_ttycommon
;
2341 int rq_msg
= 0, wq_msg
= 0;
2343 USB_DPRINTF_L4(DPRINT_STATUS_CB
, pp
->port_lh
, "usbser_status_proc_cb");
2345 pp
->port_flags
&= ~USBSER_FL_STATUS_CB
;
2347 mutex_exit(&pp
->port_mutex
);
2348 if (!usbser_dev_is_online(pp
->port_usp
)) {
2349 mutex_enter(&pp
->port_mutex
);
2354 /* get modem status */
2355 if (USBSER_DS_GET_MODEM_CTL(pp
, -1, &status
) != USB_SUCCESS
) {
2356 mutex_enter(&pp
->port_mutex
);
2361 mutex_enter(&pp
->port_mutex
);
2362 usbser_serialize_port_act(pp
, USBSER_ACT_CTL
);
2364 rq
= pp
->port_ttycommon
.t_readq
;
2365 wq
= pp
->port_ttycommon
.t_writeq
;
2368 * outbound flow control
2370 if (tp
->t_cflag
& CRTSCTS
) {
2371 if (!(status
& TIOCM_CTS
)) {
2373 * CTS dropped, stop xmit
2375 if (!(pp
->port_flags
& USBSER_FL_TX_STOPPED
)) {
2378 } else if (pp
->port_flags
& USBSER_FL_TX_STOPPED
) {
2380 * CTS raised, resume xmit
2389 if ((status
& TIOCM_CD
) || (tp
->t_flags
& TS_SOFTCAR
)) {
2393 if ((pp
->port_flags
& USBSER_FL_CARR_ON
) == 0) {
2394 pp
->port_flags
|= USBSER_FL_CARR_ON
;
2396 rq_msg
= M_UNHANGUP
;
2400 if (pp
->port_flags
& USBSER_FL_WOPEN
) {
2401 cv_broadcast(&pp
->port_car_cv
);
2404 USB_DPRINTF_L4(DPRINT_STATUS_CB
, pp
->port_lh
,
2405 "usbser_status_cb: carr on");
2407 } else if (pp
->port_flags
& USBSER_FL_CARR_ON
) {
2408 pp
->port_flags
&= ~USBSER_FL_CARR_ON
;
2410 * carrier went away: if not local line, drop DTR
2412 if (!(tp
->t_cflag
& CLOCAL
)) {
2416 if ((pp
->port_flags
& USBSER_FL_TX_STOPPED
) && (wq_msg
== 0)) {
2420 USB_DPRINTF_L4(DPRINT_STATUS_CB
, pp
->port_lh
,
2421 "usbser_status_cb: carr off");
2423 mutex_exit(&pp
->port_mutex
);
2425 USB_DPRINTF_L4(DPRINT_STATUS_CB
, pp
->port_lh
,
2426 "usbser_status_cb: rq_msg=%d wq_msg=%d", rq_msg
, wq_msg
);
2429 * commit postponed actions now
2430 * do so only if port is fully open (queues are enabled)
2434 (void) putnextctl(rq
, rq_msg
);
2437 (void) USBSER_DS_SET_MODEM_CTL(pp
, TIOCM_DTR
, 0);
2440 (void) putctl(wq
, wq_msg
);
2444 mutex_enter(&pp
->port_mutex
);
2445 usbser_release_port_act(pp
, USBSER_ACT_CTL
);
2454 * this routine is run by wq thread every time it's woken,
2455 * i.e. when the queue contains messages to process
2458 usbser_wmsg(usbser_port_t
*pp
)
2460 queue_t
*q
= pp
->port_ttycommon
.t_writeq
;
2464 ASSERT(mutex_owned(&pp
->port_mutex
));
2467 USB_DPRINTF_L3(DPRINT_WQ
, pp
->port_lh
, "usbser_wmsg: q=NULL");
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);
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
);
2481 * high-priority messages
2484 usbser_stop(pp
, mp
);
2488 usbser_start(pp
, mp
);
2492 usbser_stopi(pp
, mp
);
2496 usbser_starti(pp
, mp
);
2500 usbser_iocdata(pp
, mp
);
2504 usbser_flush(pp
, mp
);
2508 * normal-priority messages
2511 usbser_break(pp
, mp
);
2515 usbser_delay(pp
, mp
);
2519 if (usbser_data(pp
, mp
) != USB_SUCCESS
) {
2520 (void) putbq(q
, mp
);
2527 if (usbser_ioctl(pp
, mp
) != USB_SUCCESS
) {
2528 (void) putbq(q
, mp
);
2544 * process M_DATA message
2547 usbser_data(usbser_port_t
*pp
, mblk_t
*mp
)
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
)) {
2553 return (USB_FAILURE
);
2555 if (MBLKL(mp
) <= 0) {
2558 return (USB_SUCCESS
);
2561 pp
->port_act
|= USBSER_ACT_TX
;
2562 pp
->port_wq_data_cnt
-= msgdsize(mp
);
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
);
2569 return (USB_SUCCESS
);
2574 * process an M_IOCTL message
2577 usbser_ioctl(usbser_port_t
*pp
, mblk_t
*mp
)
2579 tty_common_t
*tp
= &pp
->port_ttycommon
;
2580 queue_t
*q
= tp
->t_writeq
;
2581 struct iocblk
*iocp
;
2584 int error
= 0, rval
= USB_SUCCESS
;
2587 ASSERT(mutex_owned(&pp
->port_mutex
));
2588 ASSERT(DB_TYPE(mp
) == M_IOCTL
);
2590 iocp
= (struct iocblk
*)mp
->b_rptr
;
2591 cmd
= iocp
->ioc_cmd
;
2593 USB_DPRINTF_L4(DPRINT_IOCTL
, pp
->port_lh
, "usbser_ioctl: "
2594 "mp=%p %s (0x%x)", (void *)mp
, usbser_ioctl2str(cmd
), cmd
);
2596 if (tp
->t_iocpending
!= NULL
) {
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.
2603 freemsg(tp
->t_iocpending
);
2604 tp
->t_iocpending
= NULL
;
2612 case CONSOPENPOLLEDIO
:
2613 case CONSCLOSEPOLLEDIO
:
2614 case CONSSETABORTENABLE
:
2615 case CONSGETABORTENABLE
:
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.
2623 usbser_serialize_port_act(pp
, USBSER_ACT_CTL
);
2624 mutex_exit(&pp
->port_mutex
);
2628 /* serialize breaks */
2629 if (pp
->port_act
& USBSER_ACT_BREAK
)
2630 return (USB_FAILURE
);
2633 usbser_serialize_port_act(pp
, USBSER_ACT_CTL
);
2634 mutex_exit(&pp
->port_mutex
);
2635 (void) ttycommon_ioctl(tp
, q
, mp
, &error
);
2641 * ttycommon_ioctl() did most of the work
2642 * we just use the data it set up
2650 (void) USBSER_DS_FIFO_DRAIN(pp
, DS_TX
);
2654 mutex_enter(&pp
->port_mutex
);
2655 error
= usbser_port_program(pp
);
2656 mutex_exit(&pp
->port_mutex
);
2661 } else if (error
> 0) {
2662 USB_DPRINTF_L3(DPRINT_IOCTL
, pp
->port_lh
, "usbser_ioctl: "
2663 "ttycommon_ioctl returned %d", error
);
2668 * error < 0: ttycommon_ioctl() didn't do anything, we process it here
2673 if ((error
= miocpullup(mp
, sizeof (int))) != 0)
2677 (void) USBSER_DS_FIFO_DRAIN(pp
, USBSER_TX_FIFO_DRAIN_TIMEOUT
);
2680 * if required, set break
2682 if (*(int *)mp
->b_cont
->b_rptr
== 0) {
2683 if (USBSER_DS_BREAK_CTL(pp
, DS_ON
) != USB_SUCCESS
) {
2688 mutex_enter(&pp
->port_mutex
);
2689 pp
->port_act
|= USBSER_ACT_BREAK
;
2690 pp
->port_delay_id
= timeout(usbser_restart
, pp
,
2691 drv_usectohz(250000));
2692 mutex_exit(&pp
->port_mutex
);
2694 mioc2ack(mp
, NULL
, 0, 0);
2697 case TIOCSBRK
: /* set break */
2698 if (USBSER_DS_BREAK_CTL(pp
, DS_ON
) != USB_SUCCESS
)
2701 mioc2ack(mp
, NULL
, 0, 0);
2704 case TIOCCBRK
: /* clear break */
2705 if (USBSER_DS_BREAK_CTL(pp
, DS_OFF
) != USB_SUCCESS
)
2708 mioc2ack(mp
, NULL
, 0, 0);
2711 case TIOCMSET
: /* set all modem bits */
2712 case TIOCMBIS
: /* bis modem bits */
2713 case TIOCMBIC
: /* bic modem bits */
2714 if (iocp
->ioc_count
== TRANSPARENT
) {
2715 mcopyin(mp
, NULL
, sizeof (int), NULL
);
2718 if ((error
= miocpullup(mp
, sizeof (int))) != 0)
2721 val
= *(int *)mp
->b_cont
->b_rptr
;
2722 if (cmd
== TIOCMSET
) {
2723 rval
= USBSER_DS_SET_MODEM_CTL(pp
, -1, val
);
2724 } else if (cmd
== TIOCMBIS
) {
2725 rval
= USBSER_DS_SET_MODEM_CTL(pp
, val
, -1);
2726 } else if (cmd
== TIOCMBIC
) {
2727 rval
= USBSER_DS_SET_MODEM_CTL(pp
, val
, 0);
2729 if (rval
== USB_SUCCESS
)
2730 mioc2ack(mp
, NULL
, 0, 0);
2736 if (USBSER_DS_LOOPBACK_SUPPORTED(pp
)) {
2737 if (USBSER_DS_LOOPBACK(pp
, DS_ON
) == USB_SUCCESS
)
2738 mioc2ack(mp
, NULL
, 0, 0);
2747 if (USBSER_DS_LOOPBACK_SUPPORTED(pp
)) {
2748 if (USBSER_DS_LOOPBACK(pp
, DS_OFF
) == USB_SUCCESS
)
2749 mioc2ack(mp
, NULL
, 0, 0);
2757 case TIOCMGET
: /* get all modem bits */
2758 if ((datamp
= allocb(sizeof (int), BPRI_MED
)) == NULL
) {
2762 rval
= USBSER_DS_GET_MODEM_CTL(pp
, -1, (int *)datamp
->b_rptr
);
2763 if (rval
!= USB_SUCCESS
) {
2767 if (iocp
->ioc_count
== TRANSPARENT
)
2768 mcopyout(mp
, NULL
, sizeof (int), NULL
, datamp
);
2770 mioc2ack(mp
, datamp
, sizeof (int), 0);
2773 case CONSOPENPOLLEDIO
:
2774 error
= usbser_polledio_init(pp
);
2778 error
= miocpullup(mp
, sizeof (struct cons_polledio
*));
2782 *(struct cons_polledio
**)mp
->b_cont
->b_rptr
= &usbser_polledio
;
2784 mp
->b_datap
->db_type
= M_IOCACK
;
2787 case CONSCLOSEPOLLEDIO
:
2788 usbser_polledio_fini(pp
);
2789 mp
->b_datap
->db_type
= M_IOCACK
;
2790 iocp
->ioc_error
= 0;
2794 case CONSSETABORTENABLE
:
2795 error
= secpolicy_console(iocp
->ioc_cr
);
2799 if (iocp
->ioc_count
!= TRANSPARENT
) {
2805 * To do: implement console abort support
2806 * This involves adding a console flag to usbser
2807 * state structure. If flag is set, parse input stream
2808 * for abort sequence (see asy for example).
2810 * For now, run mdb -K to get kmdb prompt.
2812 if (*(intptr_t *)mp
->b_cont
->b_rptr
)
2813 usbser_console_abort
= 1;
2815 usbser_console_abort
= 0;
2817 mp
->b_datap
->db_type
= M_IOCACK
;
2818 iocp
->ioc_error
= 0;
2822 case CONSGETABORTENABLE
:
2823 /*CONSTANTCONDITION*/
2824 ASSERT(sizeof (boolean_t
) <= sizeof (boolean_t
*));
2826 * Store the return value right in the payload
2827 * we were passed. Crude.
2829 mcopyout(mp
, NULL
, sizeof (boolean_t
), NULL
, NULL
);
2830 *(boolean_t
*)mp
->b_cont
->b_rptr
= (usbser_console_abort
!= 0);
2839 miocnak(q
, mp
, 0, error
);
2843 mutex_enter(&pp
->port_mutex
);
2844 usbser_release_port_act(pp
, USBSER_ACT_CTL
);
2846 return (USB_SUCCESS
);
2851 * process M_IOCDATA message
2854 usbser_iocdata(usbser_port_t
*pp
, mblk_t
*mp
)
2856 tty_common_t
*tp
= &pp
->port_ttycommon
;
2857 queue_t
*q
= tp
->t_writeq
;
2858 struct copyresp
*csp
;
2861 int rval
= USB_FAILURE
;
2863 ASSERT(mutex_owned(&pp
->port_mutex
));
2865 csp
= (struct copyresp
*)mp
->b_rptr
;
2868 if (csp
->cp_rval
!= 0) {
2874 case TIOCMSET
: /* set all modem bits */
2875 case TIOCMBIS
: /* bis modem bits */
2876 case TIOCMBIC
: /* bic modem bits */
2877 if ((mp
->b_cont
== NULL
) ||
2878 (MBLKL(mp
->b_cont
) < sizeof (int))) {
2879 miocnak(q
, mp
, 0, EINVAL
);
2882 val
= *(int *)mp
->b_cont
->b_rptr
;
2884 usbser_serialize_port_act(pp
, USBSER_ACT_CTL
);
2885 mutex_exit(&pp
->port_mutex
);
2887 if (cmd
== TIOCMSET
) {
2888 rval
= USBSER_DS_SET_MODEM_CTL(pp
, -1, val
);
2889 } else if (cmd
== TIOCMBIS
) {
2890 rval
= USBSER_DS_SET_MODEM_CTL(pp
, val
, -1);
2891 } else if (cmd
== TIOCMBIC
) {
2892 rval
= USBSER_DS_SET_MODEM_CTL(pp
, val
, 0);
2896 freemsg(mp
->b_cont
);
2900 if (rval
== USB_SUCCESS
)
2901 miocack(q
, mp
, 0, 0);
2903 miocnak(q
, mp
, 0, EIO
);
2905 mutex_enter(&pp
->port_mutex
);
2906 usbser_release_port_act(pp
, USBSER_ACT_CTL
);
2909 case TIOCMGET
: /* get all modem bits */
2910 mutex_exit(&pp
->port_mutex
);
2911 miocack(q
, mp
, 0, 0);
2912 mutex_enter(&pp
->port_mutex
);
2916 mutex_exit(&pp
->port_mutex
);
2917 miocnak(q
, mp
, 0, EINVAL
);
2918 mutex_enter(&pp
->port_mutex
);
2925 * handle M_START[I]/M_STOP[I] messages
2928 usbser_stop(usbser_port_t
*pp
, mblk_t
*mp
)
2931 if (!(pp
->port_flags
& USBSER_FL_TX_STOPPED
)) {
2932 usbser_serialize_port_act(pp
, USBSER_ACT_CTL
);
2933 pp
->port_flags
|= USBSER_FL_TX_STOPPED
;
2935 mutex_exit(&pp
->port_mutex
);
2936 USBSER_DS_STOP(pp
, DS_TX
);
2937 mutex_enter(&pp
->port_mutex
);
2939 usbser_release_port_act(pp
, USBSER_ACT_TX
);
2940 usbser_release_port_act(pp
, USBSER_ACT_CTL
);
2947 usbser_start(usbser_port_t
*pp
, mblk_t
*mp
)
2950 if (pp
->port_flags
& USBSER_FL_TX_STOPPED
) {
2951 usbser_serialize_port_act(pp
, USBSER_ACT_CTL
);
2952 pp
->port_flags
&= ~USBSER_FL_TX_STOPPED
;
2954 mutex_exit(&pp
->port_mutex
);
2955 USBSER_DS_START(pp
, DS_TX
);
2956 mutex_enter(&pp
->port_mutex
);
2957 usbser_release_port_act(pp
, USBSER_ACT_CTL
);
2964 usbser_stopi(usbser_port_t
*pp
, mblk_t
*mp
)
2967 usbser_serialize_port_act(pp
, USBSER_ACT_CTL
);
2968 pp
->port_flowc
= pp
->port_ttycommon
.t_stopc
;
2969 usbser_inbound_flow_ctl(pp
);
2970 usbser_release_port_act(pp
, USBSER_ACT_CTL
);
2975 usbser_starti(usbser_port_t
*pp
, mblk_t
*mp
)
2977 usbser_st_mstarti
++;
2978 usbser_serialize_port_act(pp
, USBSER_ACT_CTL
);
2979 pp
->port_flowc
= pp
->port_ttycommon
.t_startc
;
2980 usbser_inbound_flow_ctl(pp
);
2981 usbser_release_port_act(pp
, USBSER_ACT_CTL
);
2986 * process M_FLUSH message
2989 usbser_flush(usbser_port_t
*pp
, mblk_t
*mp
)
2991 queue_t
*q
= pp
->port_ttycommon
.t_writeq
;
2993 if (*mp
->b_rptr
& FLUSHW
) {
2994 mutex_exit(&pp
->port_mutex
);
2995 (void) USBSER_DS_FIFO_FLUSH(pp
, DS_TX
); /* flush FIFO buffers */
2996 flushq(q
, FLUSHDATA
); /* flush write queue */
2997 mutex_enter(&pp
->port_mutex
);
2999 usbser_release_port_act(pp
, USBSER_ACT_TX
);
3001 *mp
->b_rptr
&= ~FLUSHW
;
3003 if (*mp
->b_rptr
& FLUSHR
) {
3005 * flush FIFO buffers
3007 mutex_exit(&pp
->port_mutex
);
3008 (void) USBSER_DS_FIFO_FLUSH(pp
, DS_RX
);
3009 flushq(RD(q
), FLUSHDATA
);
3011 mutex_enter(&pp
->port_mutex
);
3018 * process M_BREAK message
3021 usbser_break(usbser_port_t
*pp
, mblk_t
*mp
)
3026 * set the break and arrange for usbser_restart() to be called in 1/4 s
3028 mutex_exit(&pp
->port_mutex
);
3029 rval
= USBSER_DS_BREAK_CTL(pp
, DS_ON
);
3030 mutex_enter(&pp
->port_mutex
);
3032 if (rval
== USB_SUCCESS
) {
3033 pp
->port_act
|= USBSER_ACT_BREAK
;
3034 pp
->port_delay_id
= timeout(usbser_restart
, pp
,
3035 drv_usectohz(250000));
3042 * process M_DELAY message
3045 usbser_delay(usbser_port_t
*pp
, mblk_t
*mp
)
3048 * arrange for usbser_restart() to be called when the delay expires
3050 pp
->port_act
|= USBSER_ACT_DELAY
;
3051 pp
->port_delay_id
= timeout(usbser_restart
, pp
,
3052 (clock_t)(*(uchar_t
*)mp
->b_rptr
+ 6));
3058 * restart output on a line after a delay or break timer expired
3061 usbser_restart(void *arg
)
3063 usbser_port_t
*pp
= (usbser_port_t
*)arg
;
3065 USB_DPRINTF_L4(DPRINT_WQ
, pp
->port_lh
, "usbser_restart");
3067 mutex_enter(&pp
->port_mutex
);
3068 /* if cancelled, return immediately */
3069 if (pp
->port_delay_id
== 0) {
3070 mutex_exit(&pp
->port_mutex
);
3074 pp
->port_delay_id
= 0;
3076 /* clear break if necessary */
3077 if (pp
->port_act
& USBSER_ACT_BREAK
) {
3078 mutex_exit(&pp
->port_mutex
);
3079 (void) USBSER_DS_BREAK_CTL(pp
, DS_OFF
);
3080 mutex_enter(&pp
->port_mutex
);
3083 usbser_release_port_act(pp
, USBSER_ACT_BREAK
| USBSER_ACT_DELAY
);
3085 /* wake wq thread to resume message processing */
3086 usbser_thr_wake(&pp
->port_wq_thread
);
3087 mutex_exit(&pp
->port_mutex
);
3092 * program port hardware with the chosen parameters
3093 * most of the operation is based on the values of 'c_iflag' and 'c_cflag'
3096 usbser_port_program(usbser_port_t
*pp
)
3098 tty_common_t
*tp
= &pp
->port_ttycommon
;
3101 ds_port_param_entry_t pe
[6];
3102 ds_port_params_t params
;
3103 int flow_ctl
, ctl_val
;
3106 baudrate
= tp
->t_cflag
& CBAUD
;
3107 if (tp
->t_cflag
& CBAUDEXT
) {
3112 * set input speed same as output, as split speed not supported
3114 if (tp
->t_cflag
& (CIBAUD
|CIBAUDEXT
)) {
3115 tp
->t_cflag
&= ~(CIBAUD
);
3116 if (baudrate
> CBAUD
) {
3117 tp
->t_cflag
|= CIBAUDEXT
;
3119 (((baudrate
- CBAUD
- 1) << IBSHIFT
) & CIBAUD
);
3121 tp
->t_cflag
&= ~CIBAUDEXT
;
3122 tp
->t_cflag
|= ((baudrate
<< IBSHIFT
) & CIBAUD
);
3126 c_flag
= tp
->t_cflag
;
3131 flow_ctl
= tp
->t_iflag
& (IXON
| IXANY
| IXOFF
);
3132 if (c_flag
& CRTSCTS
) {
3135 if (c_flag
& CRTSXOFF
) {
3136 flow_ctl
|= RTSXOFF
;
3140 * fill in port parameters we need to set:
3144 pe
[0].param
= DS_PARAM_BAUD
;
3145 pe
[0].val
.ui
= baudrate
;
3148 pe
[1].param
= DS_PARAM_STOPB
;
3149 pe
[1].val
.ui
= c_flag
& CSTOPB
;
3152 pe
[2].param
= DS_PARAM_PARITY
;
3153 pe
[2].val
.ui
= c_flag
& (PARENB
| PARODD
);
3156 pe
[3].param
= DS_PARAM_CHARSZ
;
3157 pe
[3].val
.ui
= c_flag
& CSIZE
;
3159 /* start & stop chars */
3160 pe
[4].param
= DS_PARAM_XON_XOFF
;
3161 pe
[4].val
.uc
[0] = tp
->t_startc
;
3162 pe
[4].val
.uc
[1] = tp
->t_stopc
;
3165 pe
[5].param
= DS_PARAM_FLOW_CTL
;
3166 pe
[5].val
.ui
= flow_ctl
;
3168 params
.tp_entries
= &pe
[0];
3171 /* control signals */
3172 ctl_val
= TIOCM_DTR
| TIOCM_RTS
;
3173 if (baudrate
== 0) {
3174 ctl_val
&= ~TIOCM_DTR
; /* zero baudrate means drop DTR */
3176 if (pp
->port_flags
& USBSER_FL_RX_STOPPED
) {
3177 ctl_val
&= ~TIOCM_RTS
;
3181 mutex_exit(&pp
->port_mutex
);
3182 err
= USBSER_DS_SET_PORT_PARAMS(pp
, ¶ms
);
3183 if (err
!= USB_SUCCESS
) {
3184 mutex_enter(&pp
->port_mutex
);
3189 err
= USBSER_DS_SET_MODEM_CTL(pp
, TIOCM_DTR
| TIOCM_RTS
, ctl_val
);
3190 mutex_enter(&pp
->port_mutex
);
3192 return ((err
== USB_SUCCESS
) ? 0 : EIO
);
3197 * check if any inbound flow control action needed
3200 usbser_inbound_flow_ctl(usbser_port_t
*pp
)
3204 char c
= pp
->port_flowc
;
3207 USB_DPRINTF_L4(DPRINT_WQ
, pp
->port_lh
,
3208 "usbser_inbound_flow_ctl: c=%x cflag=%x port_flags=%x",
3209 c
, pp
->port_ttycommon
.t_cflag
, pp
->port_flags
);
3215 pp
->port_flowc
= '\0';
3218 * if inbound hardware flow control enabled, we need to frob RTS
3220 need_hw
= (pp
->port_ttycommon
.t_cflag
& CRTSXOFF
);
3221 if (c
== pp
->port_ttycommon
.t_startc
) {
3223 pp
->port_flags
&= ~USBSER_FL_RX_STOPPED
;
3226 pp
->port_flags
|= USBSER_FL_RX_STOPPED
;
3230 * if character flow control active, transmit a start or stop char,
3232 if (pp
->port_ttycommon
.t_iflag
& IXOFF
) {
3233 if ((mp
= allocb(1, BPRI_LO
)) == NULL
) {
3234 USB_DPRINTF_L2(DPRINT_WQ
, pp
->port_lh
,
3235 "usbser_inbound_flow_ctl: allocb failed");
3238 pp
->port_flags
|= USBSER_ACT_TX
;
3242 mutex_exit(&pp
->port_mutex
);
3244 (void) USBSER_DS_SET_MODEM_CTL(pp
, TIOCM_RTS
, rts
);
3247 (void) USBSER_DS_TX(pp
, mp
);
3249 mutex_enter(&pp
->port_mutex
);
3258 * returns != 0 if device is online, 0 otherwise
3261 usbser_dev_is_online(usbser_state_t
*usp
)
3265 mutex_enter(&usp
->us_mutex
);
3266 rval
= (usp
->us_dev_state
== USB_DEV_ONLINE
);
3267 mutex_exit(&usp
->us_mutex
);
3273 * serialize port activities defined by 'act' mask
3276 usbser_serialize_port_act(usbser_port_t
*pp
, int act
)
3278 while (pp
->port_act
& act
)
3279 cv_wait(&pp
->port_act_cv
, &pp
->port_mutex
);
3280 pp
->port_act
|= act
;
3285 * indicate that port activity is finished
3288 usbser_release_port_act(usbser_port_t
*pp
, int act
)
3290 pp
->port_act
&= ~act
;
3291 cv_broadcast(&pp
->port_act_cv
);
3296 * message type to string and back conversion.
3298 * pardon breaks on the same line, but as long as cstyle doesn't
3299 * complain, I'd like to keep this form for trivial cases like this.
3300 * associative arrays in the kernel, anyone?
3303 usbser_msgtype2str(int type
) __unused
;
3306 usbser_msgtype2str(int type
)
3311 case M_STOP
: str
= "M_STOP"; break;
3312 case M_START
: str
= "M_START"; break;
3313 case M_STOPI
: str
= "M_STOPI"; break;
3314 case M_STARTI
: str
= "M_STARTI"; break;
3315 case M_DATA
: str
= "M_DATA"; break;
3316 case M_DELAY
: str
= "M_DELAY"; break;
3317 case M_BREAK
: str
= "M_BREAK"; break;
3318 case M_IOCTL
: str
= "M_IOCTL"; break;
3319 case M_IOCDATA
: str
= "M_IOCDATA"; break;
3320 case M_FLUSH
: str
= "M_FLUSH"; break;
3321 case M_CTL
: str
= "M_CTL"; break;
3322 case M_READ
: str
= "M_READ"; break;
3323 default: str
= "unknown"; break;
3330 usbser_ioctl2str(int ioctl
) __unused
;
3333 usbser_ioctl2str(int ioctl
)
3338 case TCGETA
: str
= "TCGETA"; break;
3339 case TCSETA
: str
= "TCSETA"; break;
3340 case TCSETAF
: str
= "TCSETAF"; break;
3341 case TCSETAW
: str
= "TCSETAW"; break;
3342 case TCSBRK
: str
= "TCSBRK"; break;
3343 case TCXONC
: str
= "TCXONC"; break;
3344 case TCFLSH
: str
= "TCFLSH"; break;
3345 case TCGETS
: str
= "TCGETS"; break;
3346 case TCSETS
: str
= "TCSETS"; break;
3347 case TCSETSF
: str
= "TCSETSF"; break;
3348 case TCSETSW
: str
= "TCSETSW"; break;
3349 case TIOCSBRK
: str
= "TIOCSBRK"; break;
3350 case TIOCCBRK
: str
= "TIOCCBRK"; break;
3351 case TIOCMSET
: str
= "TIOCMSET"; break;
3352 case TIOCMBIS
: str
= "TIOCMBIS"; break;
3353 case TIOCMBIC
: str
= "TIOCMBIC"; break;
3354 case TIOCMGET
: str
= "TIOCMGET"; break;
3355 case TIOCSILOOP
: str
= "TIOCSILOOP"; break;
3356 case TIOCCILOOP
: str
= "TIOCCILOOP"; break;
3357 case TCGETX
: str
= "TCGETX"; break;
3358 case TCSETX
: str
= "TCGETX"; break;
3359 case TCSETXW
: str
= "TCGETX"; break;
3360 case TCSETXF
: str
= "TCGETX"; break;
3361 default: str
= "unknown"; break;
3371 /* called once by consconfig() when polledio is opened */
3373 usbser_polledio_init(usbser_port_t
*pp
)
3376 usb_pipe_handle_t hdl
;
3377 ds_ops_t
*ds_ops
= pp
->port_ds_ops
;
3379 /* only one serial line console supported */
3380 if (console_input
!= NULL
)
3381 return (USB_FAILURE
);
3383 /* check if underlying driver supports polled io */
3384 if (ds_ops
->ds_version
< DS_OPS_VERSION_V1
||
3385 ds_ops
->ds_out_pipe
== NULL
|| ds_ops
->ds_in_pipe
== NULL
)
3386 return (USB_FAILURE
);
3388 /* init polled input pipe */
3389 hdl
= ds_ops
->ds_in_pipe(pp
->port_ds_hdl
, pp
->port_num
);
3390 err
= usb_console_input_init(pp
->port_usp
->us_dip
, hdl
,
3391 &console_input_buf
, &console_input
);
3393 return (USB_FAILURE
);
3395 /* init polled output pipe */
3396 hdl
= ds_ops
->ds_out_pipe(pp
->port_ds_hdl
, pp
->port_num
);
3397 err
= usb_console_output_init(pp
->port_usp
->us_dip
, hdl
,
3400 (void) usb_console_input_fini(console_input
);
3401 console_input
= NULL
;
3402 return (USB_FAILURE
);
3405 return (USB_SUCCESS
);
3408 /* called once by consconfig() when polledio is closed */
3410 static void usbser_polledio_fini(usbser_port_t
*pp
)
3412 /* Since we can't move the console, there is nothing to do. */
3417 usbser_polledio_enter(cons_polledio_arg_t arg
)
3419 (void) usb_console_input_enter(console_input
);
3420 (void) usb_console_output_enter(console_output
);
3425 usbser_polledio_exit(cons_polledio_arg_t arg
)
3427 (void) usb_console_output_exit(console_output
);
3428 (void) usb_console_input_exit(console_input
);
3433 usbser_putchar(cons_polledio_arg_t arg
, uchar_t c
)
3435 static uchar_t cr
[2] = {'\r', '\n'};
3439 (void) usb_console_write(console_output
, cr
, 2, &nout
);
3441 (void) usb_console_write(console_output
, &c
, 1, &nout
);
3446 usbser_getchar(cons_polledio_arg_t arg
)
3448 while (!usbser_ischar(arg
))
3451 return (*console_input_start
++);
3456 usbser_ischar(cons_polledio_arg_t arg
)
3460 if (console_input_start
< console_input_end
)
3463 if (usb_console_read(console_input
, &num_bytes
) != USB_SUCCESS
)
3466 console_input_start
= console_input_buf
;
3467 console_input_end
= console_input_buf
+ num_bytes
;
3469 return (num_bytes
!= 0);