1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*
28 *
29 * USB generic serial driver (GSD)
30 *
31 */
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/stream.h>
35 #include <sys/stropts.h>
36 #include <sys/errno.h>
37 #include <sys/cred.h>
38 #include <sys/conf.h>
39 #include <sys/stat.h>
40 #include <sys/modctl.h>
41 #include <sys/ddi.h>
42 #include <sys/sunddi.h>
43 #include <sys/sunndi.h>
44 #include <sys/termio.h>
45 #include <sys/termiox.h>
46 #include <sys/stropts.h>
47 #include <sys/stream.h>
48 #include <sys/strsubr.h>
49 #include <sys/strsun.h>
50 #include <sys/strtty.h>
51 #include <sys/policy.h>
52 #include <sys/consdev.h>
53
54 #include <sys/usb/usba.h>
55 #include <sys/usb/clients/usbser/usbser_var.h>
56 #include <sys/usb/clients/usbser/usbser_dsdi.h>
57 #include <sys/usb/clients/usbser/usbser_rseq.h>
58 #include <sys/usb/usba/genconsole.h>
59
60 /* autoconfiguration subroutines */
61 static int usbser_rseq_do_cb(rseq_t *, int, uintptr_t);
62 static int usbser_free_soft_state(usbser_state_t *);
63 static int usbser_init_soft_state(usbser_state_t *);
64 static int usbser_fini_soft_state(usbser_state_t *);
65 static int usbser_attach_dev(usbser_state_t *);
66 static void usbser_detach_dev(usbser_state_t *);
67 static int usbser_attach_ports(usbser_state_t *);
68 static int usbser_create_port_minor_nodes(usbser_state_t *, int);
69 static void usbser_detach_ports(usbser_state_t *);
70 static int usbser_create_taskq(usbser_state_t *);
71 static void usbser_destroy_taskq(usbser_state_t *);
72 static void usbser_set_dev_state_init(usbser_state_t *);
73
74 /* hotplugging and power management */
75 static int usbser_disconnect_cb(dev_info_t *);
76 static int usbser_reconnect_cb(dev_info_t *);
77 static void usbser_disconnect_ports(usbser_state_t *);
78 static int usbser_cpr_suspend(dev_info_t *);
79 static int usbser_suspend_ports(usbser_state_t *);
80 static void usbser_cpr_resume(dev_info_t *);
81 static int usbser_restore_device_state(usbser_state_t *);
82 static void usbser_restore_ports_state(usbser_state_t *);
83
84 /* STREAMS subroutines */
85 static int usbser_open_setup(queue_t *, usbser_port_t *, int, int,
86 cred_t *);
87 static int usbser_open_init(usbser_port_t *, int);
88 static void usbser_check_port_props(usbser_port_t *);
89 static void usbser_open_fini(usbser_port_t *);
90 static int usbser_open_line_setup(usbser_port_t *, int, int);
91 static int usbser_open_carrier_check(usbser_port_t *, int, int);
92 static void usbser_open_queues_init(usbser_port_t *, queue_t *);
93 static void usbser_open_queues_fini(usbser_port_t *);
94 static void usbser_close_drain(usbser_port_t *);
95 static void usbser_close_cancel_break(usbser_port_t *);
96 static void usbser_close_hangup(usbser_port_t *);
97 static void usbser_close_cleanup(usbser_port_t *);
98
99 /* threads */
100 static void usbser_thr_dispatch(usbser_thread_t *);
101 static void usbser_thr_cancel(usbser_thread_t *);
102 static void usbser_thr_wake(usbser_thread_t *);
103 static void usbser_wq_thread(void *);
104 static void usbser_rq_thread(void *);
105
106 /* DSD callbacks */
107 static void usbser_tx_cb(caddr_t);
108 static void usbser_rx_cb(caddr_t);
109 static void usbser_rx_massage_data(usbser_port_t *, mblk_t *);
110 static void usbser_rx_massage_mbreak(usbser_port_t *, mblk_t *);
111 static void usbser_rx_cb_put(usbser_port_t *, queue_t *, queue_t *,
112 mblk_t *);
113 static void usbser_status_cb(caddr_t);
114 static void usbser_status_proc_cb(usbser_port_t *);
115
116 /* serial support */
117 static void usbser_wmsg(usbser_port_t *);
118 static int usbser_data(usbser_port_t *, mblk_t *);
119 static int usbser_ioctl(usbser_port_t *, mblk_t *);
120 static void usbser_iocdata(usbser_port_t *, mblk_t *);
121 static void usbser_stop(usbser_port_t *, mblk_t *);
122 static void usbser_start(usbser_port_t *, mblk_t *);
123 static void usbser_stopi(usbser_port_t *, mblk_t *);
124 static void usbser_starti(usbser_port_t *, mblk_t *);
125 static void usbser_flush(usbser_port_t *, mblk_t *);
126 static void usbser_break(usbser_port_t *, mblk_t *);
127 static void usbser_delay(usbser_port_t *, mblk_t *);
128 static void usbser_restart(void *);
129 static int usbser_port_program(usbser_port_t *);
130 static void usbser_inbound_flow_ctl(usbser_port_t *);
131
132 /* misc */
133 static int usbser_dev_is_online(usbser_state_t *);
134 static void usbser_serialize_port_act(usbser_port_t *, int);
135 static void usbser_release_port_act(usbser_port_t *, int);
136 static char *usbser_msgtype2str(int);
137 static char *usbser_ioctl2str(int);
138
139
140 /* USBA events */
141 usb_event_t usbser_usb_events = {
142 usbser_disconnect_cb, /* disconnect */
143 usbser_reconnect_cb, /* reconnect */
144 NULL, /* pre-suspend */
145 NULL, /* pre-resume */
146 };
147
148 /* debug support */
149 uint_t usbser_errlevel = USB_LOG_L4;
150 uint_t usbser_errmask = DPRINT_MASK_ALL;
151 uint_t usbser_instance_debug = (uint_t)-1;
152
153 /* usb serial console */
154 static struct usbser_state *usbser_list;
155 static kmutex_t usbser_lock;
156 static int usbser_console_abort;
157 static usb_console_info_t console_input, console_output;
158 static uchar_t *console_input_buf;
159 static uchar_t *console_input_start, *console_input_end;
160
161 _NOTE(SCHEME_PROTECTS_DATA("unshared", usbser_console_abort))
162 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input))
163 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_output))
164 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_start))
165 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_end))
166
167 static void usbser_putchar(cons_polledio_arg_t, uchar_t);
168 static int usbser_getchar(cons_polledio_arg_t);
169 static boolean_t usbser_ischar(cons_polledio_arg_t);
170 static void usbser_polledio_enter(cons_polledio_arg_t);
171 static void usbser_polledio_exit(cons_polledio_arg_t);
172 static int usbser_polledio_init(usbser_port_t *);
173 static void usbser_polledio_fini(usbser_port_t *);
174
175 static struct cons_polledio usbser_polledio = {
176 CONSPOLLEDIO_V1,
177 NULL, /* to be set later */
178 usbser_putchar,
179 usbser_getchar,
180 usbser_ischar,
181 usbser_polledio_enter,
182 usbser_polledio_exit
183 };
184
185 /* various statistics. TODO: replace with kstats */
186 static int usbser_st_tx_data_loss = 0;
187 static int usbser_st_rx_data_loss = 0;
188 static int usbser_st_put_stopi = 0;
189 static int usbser_st_mstop = 0;
190 static int usbser_st_mstart = 0;
191 static int usbser_st_mstopi = 0;
192 static int usbser_st_mstarti = 0;
193 static int usbser_st_rsrv = 0;
194 _NOTE(SCHEME_PROTECTS_DATA("monotonic stats", usbser_st_{
195 tx_data_loss rx_data_loss put_stopi mstop mstart mstopi mstarti rsrv}))
196 _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_bulk_req_t))
197 _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_intr_req_t))
198
199 /* taskq parameter */
200 extern pri_t minclsyspri;
201
202 /*
203 * tell warlock not to worry about STREAMS structures
204 */
205 _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk datab msgb queue copyreq))
206
207 /*
208 * modload support
209 */
210 extern struct mod_ops mod_miscops;
211
212 static struct modlmisc modlmisc = {
213 &mod_miscops, /* Type of module */
214 "USB generic serial module"
215 };
216
217 static struct modlinkage modlinkage = {
218 MODREV_1, (void *)&modlmisc, NULL
219 };
220
221
222 #define RSEQ(f1, f2) RSEQE(f1, usbser_rseq_do_cb, f2, NULL)
223
224
225 /*
226 * loadable module entry points
227 * ----------------------------
228 */
229
230 int
_init(void)231 _init(void)
232 {
233 int err;
234
235 mutex_init(&usbser_lock, NULL, MUTEX_DRIVER, (void *)NULL);
236 if (err = mod_install(&modlinkage))
237 mutex_destroy(&usbser_lock);
238
239 return (err);
240 }
241
242
243 int
_fini(void)244 _fini(void)
245 {
246 int err;
247
248 if (err = mod_remove(&modlinkage))
249
250 return (err);
251
252 mutex_destroy(&usbser_lock);
253
254 return (0);
255 }
256
257
258 int
_info(struct modinfo * modinfop)259 _info(struct modinfo *modinfop)
260 {
261 return (mod_info(&modlinkage, modinfop));
262 }
263
264
265 /*
266 * soft state size
267 */
268 int
usbser_soft_state_size()269 usbser_soft_state_size()
270 {
271 return (sizeof (usbser_state_t));
272 }
273
274
275 /*
276 * autoconfiguration entry points
277 * ------------------------------
278 */
279
280 /*ARGSUSED*/
281 int
usbser_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result,void * statep)282 usbser_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
283 void **result, void *statep)
284 {
285 int instance;
286 int ret = DDI_FAILURE;
287 usbser_state_t *usbserp;
288
289 instance = USBSER_MINOR2INST(getminor((dev_t)arg));
290
291 switch (infocmd) {
292 case DDI_INFO_DEVT2DEVINFO:
293 *result = NULL;
294 usbserp = ddi_get_soft_state(statep, instance);
295 if (usbserp != NULL) {
296 *result = usbserp->us_dip;
297 if (*result != NULL) {
298 ret = DDI_SUCCESS;
299 }
300 }
301
302 break;
303 case DDI_INFO_DEVT2INSTANCE:
304 *result = (void *)(uintptr_t)instance;
305 ret = DDI_SUCCESS;
306
307 break;
308 default:
309 break;
310 }
311
312 return (ret);
313 }
314
315 /*
316 * device attach
317 */
318 static rseq_t rseq_att[] = {
319 RSEQ(NULL, usbser_free_soft_state),
320 RSEQ(usbser_init_soft_state, usbser_fini_soft_state),
321 RSEQ(usbser_attach_dev, usbser_detach_dev),
322 RSEQ(usbser_attach_ports, usbser_detach_ports),
323 RSEQ(usbser_create_taskq, usbser_destroy_taskq),
324 RSEQ(NULL, usbser_set_dev_state_init)
325 };
326
327 static void
usbser_insert(struct usbser_state * usp)328 usbser_insert(struct usbser_state *usp)
329 {
330 struct usbser_state *tmp;
331
332 mutex_enter(&usbser_lock);
333 tmp = usbser_list;
334 if (tmp == NULL)
335 usbser_list = usp;
336 else {
337 while (tmp->us_next)
338 tmp = tmp->us_next;
339 tmp->us_next = usp;
340 }
341 mutex_exit(&usbser_lock);
342 }
343
344 static void
usbser_remove(struct usbser_state * usp)345 usbser_remove(struct usbser_state *usp)
346 {
347 struct usbser_state *tmp, *prev = NULL;
348
349 mutex_enter(&usbser_lock);
350 tmp = usbser_list;
351 while (tmp != usp) {
352 prev = tmp;
353 tmp = tmp->us_next;
354 }
355 ASSERT(tmp == usp); /* must exist, else attach/detach wrong */
356 if (prev)
357 prev->us_next = usp->us_next;
358 else
359 usbser_list = usp->us_next;
360 usp->us_next = NULL;
361 mutex_exit(&usbser_lock);
362 }
363
364 /*
365 * Return the first serial device, with dip held. This is called
366 * from the console subsystem to place console on usb serial device.
367 */
368 dev_info_t *
usbser_first_device(void)369 usbser_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
383 int
usbser_attach(dev_info_t * dip,ddi_attach_cmd_t cmd,void * statep,ds_ops_t * ds_ops)384 usbser_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 */
435 int
usbser_detach(dev_info_t * dip,ddi_detach_cmd_t cmd,void * statep)436 usbser_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*/
471 int
usbser_open(queue_t * rq,dev_t * dev,int flag,int sflag,cred_t * cr,void * statep)472 usbser_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*/
532 int
usbser_close(queue_t * rq,int flag,cred_t * cr)533 usbser_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 */
580 int
usbser_rsrv(queue_t * q)581 usbser_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 */
610 int
usbser_wput(queue_t * q,mblk_t * mp)611 usbser_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 */
643 int
usbser_wsrv(queue_t * q)644 usbser_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 */
665 int
usbser_power(dev_info_t * dip,int comp,int level)666 usbser_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 */
703 static int
usbser_rseq_do_cb(rseq_t * rseq,int num,uintptr_t arg)704 usbser_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 */
725 static int
usbser_free_soft_state(usbser_state_t * usp)726 usbser_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 */
736 static int
usbser_init_soft_state(usbser_state_t * usp)737 usbser_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 */
755 static int
usbser_fini_soft_state(usbser_state_t * usp)756 usbser_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 */
768 static int
usbser_attach_dev(usbser_state_t * usp)769 usbser_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 */
801 static void
usbser_detach_dev(usbser_state_t * usp)802 usbser_detach_dev(usbser_state_t *usp)
803 {
804 USBSER_DS_DETACH(usp);
805 }
806
807
808 /*
809 * attach each individual port
810 */
811 static int
usbser_attach_ports(usbser_state_t * usp)812 usbser_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 */
889 static int
usbser_create_port_minor_nodes(usbser_state_t * usp,int port_num)890 usbser_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 */
927 static void
usbser_detach_ports(usbser_state_t * usp)928 usbser_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 */
973 static int
usbser_create_taskq(usbser_state_t * usp)974 usbser_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
985 static void
usbser_destroy_taskq(usbser_state_t * usp)986 usbser_destroy_taskq(usbser_state_t *usp)
987 {
988 ddi_taskq_destroy(usp->us_taskq);
989 }
990
991
992 static void
usbser_set_dev_state_init(usbser_state_t * usp)993 usbser_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*/
1007 static int
usbser_disconnect_cb(dev_info_t * dip)1008 usbser_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*/
1053 static int
usbser_reconnect_cb(dev_info_t * dip)1054 usbser_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 */
1075 static void
usbser_disconnect_ports(usbser_state_t * usp)1076 usbser_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 */
1157 static int
usbser_cpr_suspend(dev_info_t * dip)1158 usbser_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
1194 static int
usbser_suspend_ports(usbser_state_t * usp)1195 usbser_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 */
1221 static void
usbser_cpr_resume(dev_info_t * dip)1222 usbser_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 */
1239 static int
usbser_restore_device_state(usbser_state_t * usp)1240 usbser_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 */
1284 static void
usbser_restore_ports_state(usbser_state_t * usp)1285 usbser_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 */
1362 static int
usbser_open_setup(queue_t * rq,usbser_port_t * pp,int minor,int flag,cred_t * cr)1363 usbser_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 */
1372 loop:
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 */
1470 static int
usbser_open_init(usbser_port_t * pp,int minor)1471 usbser_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 */
1541 static void
usbser_check_port_props(usbser_port_t * pp)1542 usbser_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 */
1586 static void
usbser_open_fini(usbser_port_t * pp)1587 usbser_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 */
1622 static int
usbser_open_line_setup(usbser_port_t * pp,int minor,int flag)1623 usbser_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 */
1653 static int
usbser_open_carrier_check(usbser_port_t * pp,int minor,int flag)1654 usbser_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 */
1717 static void
usbser_open_queues_init(usbser_port_t * pp,queue_t * rq)1718 usbser_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 */
1731 static void
usbser_open_queues_fini(usbser_port_t * pp)1732 usbser_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 */
1757 static void
usbser_close_drain(usbser_port_t * pp)1758 usbser_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 */
1806 static void
usbser_close_cancel_break(usbser_port_t * pp)1807 usbser_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 */
1828 static void
usbser_close_hangup(usbser_port_t * pp)1829 usbser_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 */
1845 static void
usbser_close_cleanup(usbser_port_t * pp)1846 usbser_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 */
1862 static void
usbser_thr_dispatch(usbser_thread_t * thr)1863 usbser_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 */
1883 static void
usbser_thr_cancel(usbser_thread_t * thr)1884 usbser_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 */
1904 static void
usbser_thr_wake(usbser_thread_t * thr)1905 usbser_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 */
1919 static void
usbser_wq_thread(void * arg)1920 usbser_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 */
1966 static void
usbser_rq_thread(void * arg)1967 usbser_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 */
2030 static void
usbser_tx_cb(caddr_t arg)2031 usbser_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 */
2066 static void
usbser_rx_cb(caddr_t arg)2067 usbser_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 */
2188 static void
usbser_rx_massage_data(usbser_port_t * pp,mblk_t * mp)2189 usbser_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 */
2251 static void
usbser_rx_massage_mbreak(usbser_port_t * pp,mblk_t * mp)2252 usbser_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 */
2281 static void
usbser_rx_cb_put(usbser_port_t * pp,queue_t * rq,queue_t * wq,mblk_t * mp)2282 usbser_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 */
2312 static void
usbser_status_cb(caddr_t arg)2313 usbser_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 */
2340 static void
usbser_status_proc_cb(usbser_port_t * pp)2341 usbser_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 */
2463 static void
usbser_wmsg(usbser_port_t * pp)2464 usbser_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 */
2552 static int
usbser_data(usbser_port_t * pp,mblk_t * mp)2553 usbser_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 */
2582 static int
usbser_ioctl(usbser_port_t * pp,mblk_t * mp)2583 usbser_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 }
2843 end:
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 */
2859 static void
usbser_iocdata(usbser_port_t * pp,mblk_t * mp)2860 usbser_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 */
2933 static void
usbser_stop(usbser_port_t * pp,mblk_t * mp)2934 usbser_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
2952 static void
usbser_start(usbser_port_t * pp,mblk_t * mp)2953 usbser_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
2969 static void
usbser_stopi(usbser_port_t * pp,mblk_t * mp)2970 usbser_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
2980 static void
usbser_starti(usbser_port_t * pp,mblk_t * mp)2981 usbser_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 */
2994 static void
usbser_flush(usbser_port_t * pp,mblk_t * mp)2995 usbser_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 */
3026 static void
usbser_break(usbser_port_t * pp,mblk_t * mp)3027 usbser_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 */
3050 static void
usbser_delay(usbser_port_t * pp,mblk_t * mp)3051 usbser_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 */
3066 static void
usbser_restart(void * arg)3067 usbser_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 */
3101 static int
usbser_port_program(usbser_port_t * pp)3102 usbser_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, ¶ms);
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 */
3205 static void
usbser_inbound_flow_ctl(usbser_port_t * pp)3206 usbser_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 */
3266 static int
usbser_dev_is_online(usbser_state_t * usp)3267 usbser_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 */
3281 static void
usbser_serialize_port_act(usbser_port_t * pp,int act)3282 usbser_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 */
3293 static void
usbser_release_port_act(usbser_port_t * pp,int act)3294 usbser_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 */
3308 static char *
usbser_msgtype2str(int type)3309 usbser_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
3333 static char *
usbser_ioctl2str(int ioctl)3334 usbser_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 */
3373 static int
usbser_polledio_init(usbser_port_t * pp)3374 usbser_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*/
usbser_polledio_fini(usbser_port_t * pp)3411 static 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*/
3417 static void
usbser_polledio_enter(cons_polledio_arg_t arg)3418 usbser_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*/
3425 static void
usbser_polledio_exit(cons_polledio_arg_t arg)3426 usbser_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*/
3433 static void
usbser_putchar(cons_polledio_arg_t arg,uchar_t c)3434 usbser_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*/
3446 static int
usbser_getchar(cons_polledio_arg_t arg)3447 usbser_getchar(cons_polledio_arg_t arg)
3448 {
3449 while (!usbser_ischar(arg))
3450 ;
3451
3452 return (*console_input_start++);
3453 }
3454
3455 /*ARGSUSED*/
3456 static boolean_t
usbser_ischar(cons_polledio_arg_t arg)3457 usbser_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