1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*
28 *
29 * USB generic serial driver (GSD)
30 *
31 */
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/stream.h>
35 #include <sys/stropts.h>
36 #include <sys/errno.h>
37 #include <sys/cred.h>
38 #include <sys/conf.h>
39 #include <sys/stat.h>
40 #include <sys/modctl.h>
41 #include <sys/ddi.h>
42 #include <sys/sunddi.h>
43 #include <sys/sunndi.h>
44 #include <sys/termio.h>
45 #include <sys/termiox.h>
46 #include <sys/stropts.h>
47 #include <sys/stream.h>
48 #include <sys/strsubr.h>
49 #include <sys/strsun.h>
50 #include <sys/strtty.h>
51 #include <sys/policy.h>
52 #include <sys/consdev.h>
53
54 #include <sys/usb/usba.h>
55 #include <sys/usb/clients/usbser/usbser_var.h>
56 #include <sys/usb/clients/usbser/usbser_dsdi.h>
57 #include <sys/usb/clients/usbser/usbser_rseq.h>
58 #include <sys/usb/usba/genconsole.h>
59
60 /* autoconfiguration subroutines */
61 static int usbser_rseq_do_cb(rseq_t *, int, uintptr_t);
62 static int usbser_free_soft_state(usbser_state_t *);
63 static int usbser_init_soft_state(usbser_state_t *);
64 static int usbser_fini_soft_state(usbser_state_t *);
65 static int usbser_attach_dev(usbser_state_t *);
66 static void usbser_detach_dev(usbser_state_t *);
67 static int usbser_attach_ports(usbser_state_t *);
68 static int usbser_create_port_minor_nodes(usbser_state_t *, int);
69 static void usbser_detach_ports(usbser_state_t *);
70 static int usbser_create_taskq(usbser_state_t *);
71 static void usbser_destroy_taskq(usbser_state_t *);
72 static void usbser_set_dev_state_init(usbser_state_t *);
73
74 /* hotplugging and power management */
75 static int usbser_disconnect_cb(dev_info_t *);
76 static int usbser_reconnect_cb(dev_info_t *);
77 static void usbser_disconnect_ports(usbser_state_t *);
78 static int usbser_cpr_suspend(dev_info_t *);
79 static int usbser_suspend_ports(usbser_state_t *);
80 static void usbser_cpr_resume(dev_info_t *);
81 static int usbser_restore_device_state(usbser_state_t *);
82 static void usbser_restore_ports_state(usbser_state_t *);
83
84 /* STREAMS subroutines */
85 static int usbser_open_setup(queue_t *, usbser_port_t *, int, int,
86 cred_t *);
87 static int usbser_open_init(usbser_port_t *, int);
88 static void usbser_check_port_props(usbser_port_t *);
89 static void usbser_open_fini(usbser_port_t *);
90 static int usbser_open_line_setup(usbser_port_t *, int, int);
91 static int usbser_open_carrier_check(usbser_port_t *, int, int);
92 static void usbser_open_queues_init(usbser_port_t *, queue_t *);
93 static void usbser_open_queues_fini(usbser_port_t *);
94 static void usbser_close_drain(usbser_port_t *);
95 static void usbser_close_cancel_break(usbser_port_t *);
96 static void usbser_close_hangup(usbser_port_t *);
97 static void usbser_close_cleanup(usbser_port_t *);
98
99 /* threads */
100 static void usbser_thr_dispatch(usbser_thread_t *);
101 static void usbser_thr_cancel(usbser_thread_t *);
102 static void usbser_thr_wake(usbser_thread_t *);
103 static void usbser_wq_thread(void *);
104 static void usbser_rq_thread(void *);
105
106 /* DSD callbacks */
107 static void usbser_tx_cb(caddr_t);
108 static void usbser_rx_cb(caddr_t);
109 static void usbser_rx_massage_data(usbser_port_t *, mblk_t *);
110 static void usbser_rx_massage_mbreak(usbser_port_t *, mblk_t *);
111 static void usbser_rx_cb_put(usbser_port_t *, queue_t *, queue_t *,
112 mblk_t *);
113 static void usbser_status_cb(caddr_t);
114 static void usbser_status_proc_cb(usbser_port_t *);
115
116 /* serial support */
117 static void usbser_wmsg(usbser_port_t *);
118 static int usbser_data(usbser_port_t *, mblk_t *);
119 static int usbser_ioctl(usbser_port_t *, mblk_t *);
120 static void usbser_iocdata(usbser_port_t *, mblk_t *);
121 static void usbser_stop(usbser_port_t *, mblk_t *);
122 static void usbser_start(usbser_port_t *, mblk_t *);
123 static void usbser_stopi(usbser_port_t *, mblk_t *);
124 static void usbser_starti(usbser_port_t *, mblk_t *);
125 static void usbser_flush(usbser_port_t *, mblk_t *);
126 static void usbser_break(usbser_port_t *, mblk_t *);
127 static void usbser_delay(usbser_port_t *, mblk_t *);
128 static void usbser_restart(void *);
129 static int usbser_port_program(usbser_port_t *);
130 static void usbser_inbound_flow_ctl(usbser_port_t *);
131
132 /* misc */
133 static int usbser_dev_is_online(usbser_state_t *);
134 static void usbser_serialize_port_act(usbser_port_t *, int);
135 static void usbser_release_port_act(usbser_port_t *, int);
136 #ifdef DEBUG
137 static char *usbser_msgtype2str(int);
138 static char *usbser_ioctl2str(int);
139 #endif
140
141 /* USBA events */
142 usb_event_t usbser_usb_events = {
143 usbser_disconnect_cb, /* disconnect */
144 usbser_reconnect_cb, /* reconnect */
145 NULL, /* pre-suspend */
146 NULL, /* pre-resume */
147 };
148
149 /* debug support */
150 uint_t usbser_errlevel = USB_LOG_L4;
151 uint_t usbser_errmask = DPRINT_MASK_ALL;
152 uint_t usbser_instance_debug = (uint_t)-1;
153
154 /* usb serial console */
155 static struct usbser_state *usbser_list;
156 static kmutex_t usbser_lock;
157 static int usbser_console_abort;
158 static usb_console_info_t console_input, console_output;
159 static uchar_t *console_input_buf;
160 static uchar_t *console_input_start, *console_input_end;
161
162 _NOTE(SCHEME_PROTECTS_DATA("unshared", usbser_console_abort))
163 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input))
164 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_output))
165 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_start))
166 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_end))
167
168 static void usbser_putchar(cons_polledio_arg_t, uchar_t);
169 static int usbser_getchar(cons_polledio_arg_t);
170 static boolean_t usbser_ischar(cons_polledio_arg_t);
171 static void usbser_polledio_enter(cons_polledio_arg_t);
172 static void usbser_polledio_exit(cons_polledio_arg_t);
173 static int usbser_polledio_init(usbser_port_t *);
174 static void usbser_polledio_fini(usbser_port_t *);
175
176 static struct cons_polledio usbser_polledio = {
177 CONSPOLLEDIO_V1,
178 NULL, /* to be set later */
179 usbser_putchar,
180 usbser_getchar,
181 usbser_ischar,
182 usbser_polledio_enter,
183 usbser_polledio_exit
184 };
185
186 /* various statistics. TODO: replace with kstats */
187 static int usbser_st_tx_data_loss = 0;
188 static int usbser_st_rx_data_loss = 0;
189 static int usbser_st_put_stopi = 0;
190 static int usbser_st_mstop = 0;
191 static int usbser_st_mstart = 0;
192 static int usbser_st_mstopi = 0;
193 static int usbser_st_mstarti = 0;
194 static int usbser_st_rsrv = 0;
195 _NOTE(SCHEME_PROTECTS_DATA("monotonic stats", usbser_st_{
196 tx_data_loss rx_data_loss put_stopi mstop mstart mstopi mstarti rsrv}))
197 _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_bulk_req_t))
198 _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_intr_req_t))
199
200 /* taskq parameter */
201 extern pri_t minclsyspri;
202
203 /*
204 * tell warlock not to worry about STREAMS structures
205 */
206 _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk datab msgb queue copyreq))
207
208 /*
209 * modload support
210 */
211 extern struct mod_ops mod_miscops;
212
213 static struct modlmisc modlmisc = {
214 &mod_miscops, /* Type of module */
215 "USB generic serial module"
216 };
217
218 static struct modlinkage modlinkage = {
219 MODREV_1, (void *)&modlmisc, NULL
220 };
221
222
223 #define RSEQ(f1, f2) RSEQE(f1, usbser_rseq_do_cb, f2, NULL)
224
225
226 /*
227 * loadable module entry points
228 * ----------------------------
229 */
230
231 int
_init(void)232 _init(void)
233 {
234 int err;
235
236 mutex_init(&usbser_lock, NULL, MUTEX_DRIVER, (void *)NULL);
237
238 if ((err = mod_install(&modlinkage)) != 0)
239 mutex_destroy(&usbser_lock);
240
241 return (err);
242 }
243
244
245 int
_fini(void)246 _fini(void)
247 {
248 int err;
249
250 if ((err = mod_remove(&modlinkage)) != 0)
251 return (err);
252
253 mutex_destroy(&usbser_lock);
254
255 return (0);
256 }
257
258
259 int
_info(struct modinfo * modinfop)260 _info(struct modinfo *modinfop)
261 {
262 return (mod_info(&modlinkage, modinfop));
263 }
264
265
266 /*
267 * soft state size
268 */
269 int
usbser_soft_state_size()270 usbser_soft_state_size()
271 {
272 return (sizeof (usbser_state_t));
273 }
274
275
276 /*
277 * autoconfiguration entry points
278 * ------------------------------
279 */
280
281 /*ARGSUSED*/
282 int
usbser_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result,void * statep)283 usbser_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
284 void **result, void *statep)
285 {
286 int instance;
287 int ret = DDI_FAILURE;
288 usbser_state_t *usbserp;
289
290 instance = USBSER_MINOR2INST(getminor((dev_t)arg));
291
292 switch (infocmd) {
293 case DDI_INFO_DEVT2DEVINFO:
294 *result = NULL;
295 usbserp = ddi_get_soft_state(statep, instance);
296 if (usbserp != NULL) {
297 *result = usbserp->us_dip;
298 if (*result != NULL) {
299 ret = DDI_SUCCESS;
300 }
301 }
302
303 break;
304 case DDI_INFO_DEVT2INSTANCE:
305 *result = (void *)(uintptr_t)instance;
306 ret = DDI_SUCCESS;
307
308 break;
309 default:
310 break;
311 }
312
313 return (ret);
314 }
315
316 /*
317 * device attach
318 */
319 static rseq_t rseq_att[] = {
320 RSEQ(NULL, usbser_free_soft_state),
321 RSEQ(usbser_init_soft_state, usbser_fini_soft_state),
322 RSEQ(usbser_attach_dev, usbser_detach_dev),
323 RSEQ(usbser_attach_ports, usbser_detach_ports),
324 RSEQ(usbser_create_taskq, usbser_destroy_taskq),
325 RSEQ(NULL, usbser_set_dev_state_init)
326 };
327
328 static void
usbser_insert(struct usbser_state * usp)329 usbser_insert(struct usbser_state *usp)
330 {
331 struct usbser_state *tmp;
332
333 mutex_enter(&usbser_lock);
334 tmp = usbser_list;
335 if (tmp == NULL)
336 usbser_list = usp;
337 else {
338 while (tmp->us_next)
339 tmp = tmp->us_next;
340 tmp->us_next = usp;
341 }
342 mutex_exit(&usbser_lock);
343 }
344
345 static void
usbser_remove(struct usbser_state * usp)346 usbser_remove(struct usbser_state *usp)
347 {
348 struct usbser_state *tmp, *prev = NULL;
349
350 mutex_enter(&usbser_lock);
351 tmp = usbser_list;
352 while (tmp != usp) {
353 prev = tmp;
354 tmp = tmp->us_next;
355 }
356 ASSERT(tmp == usp); /* must exist, else attach/detach wrong */
357 if (prev)
358 prev->us_next = usp->us_next;
359 else
360 usbser_list = usp->us_next;
361 usp->us_next = NULL;
362 mutex_exit(&usbser_lock);
363 }
364
365 /*
366 * Return the first serial device, with dip held. This is called
367 * from the console subsystem to place console on usb serial device.
368 */
369 dev_info_t *
usbser_first_device(void)370 usbser_first_device(void)
371 {
372 dev_info_t *dip = NULL;
373
374 mutex_enter(&usbser_lock);
375 if (usbser_list) {
376 dip = usbser_list->us_dip;
377 ndi_hold_devi(dip);
378 }
379 mutex_exit(&usbser_lock);
380
381 return (dip);
382 }
383
384 int
usbser_attach(dev_info_t * dip,ddi_attach_cmd_t cmd,void * statep,ds_ops_t * ds_ops)385 usbser_attach(dev_info_t *dip, ddi_attach_cmd_t cmd,
386 void *statep, ds_ops_t *ds_ops)
387 {
388 int instance;
389 usbser_state_t *usp;
390
391 instance = ddi_get_instance(dip);
392
393 switch (cmd) {
394 case DDI_ATTACH:
395
396 break;
397 case DDI_RESUME:
398 usbser_cpr_resume(dip);
399
400 return (DDI_SUCCESS);
401 default:
402
403 return (DDI_FAILURE);
404 }
405
406 /* allocate and get soft state */
407 if (ddi_soft_state_zalloc(statep, instance) != DDI_SUCCESS) {
408
409 return (DDI_FAILURE);
410 }
411 if ((usp = ddi_get_soft_state(statep, instance)) == NULL) {
412 ddi_soft_state_free(statep, instance);
413
414 return (DDI_FAILURE);
415 }
416
417 usp->us_statep = statep;
418 usp->us_dip = dip;
419 usp->us_instance = instance;
420 usp->us_ds_ops = ds_ops;
421
422 if (rseq_do(rseq_att, NELEM(rseq_att), (uintptr_t)usp, 0) == RSEQ_OK) {
423 ddi_report_dev(dip);
424 usbser_insert(usp);
425
426 return (DDI_SUCCESS);
427 } else {
428
429 return (DDI_FAILURE);
430 }
431 }
432
433 /*
434 * device detach
435 */
436 int
usbser_detach(dev_info_t * dip,ddi_detach_cmd_t cmd,void * statep)437 usbser_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, void *statep)
438 {
439 int instance = ddi_get_instance(dip);
440 usbser_state_t *usp;
441 int rval;
442
443 usp = ddi_get_soft_state(statep, instance);
444
445 switch (cmd) {
446 case DDI_DETACH:
447 USB_DPRINTF_L4(DPRINT_DETACH, usp->us_lh, "usbser_detach");
448 usbser_remove(usp);
449 (void) rseq_undo(rseq_att, NELEM(rseq_att), (uintptr_t)usp, 0);
450 USB_DPRINTF_L4(DPRINT_DETACH, NULL,
451 "usbser_detach.%d: end", instance);
452
453 return (DDI_SUCCESS);
454 case DDI_SUSPEND:
455 rval = usbser_cpr_suspend(dip);
456
457 return ((rval == USB_SUCCESS)? DDI_SUCCESS : DDI_FAILURE);
458 default:
459
460 return (DDI_FAILURE);
461 }
462 }
463
464 /*
465 * STREAMS entry points
466 * --------------------
467 *
468 *
469 * port open
470 */
471 /*ARGSUSED*/
472 int
usbser_open(queue_t * rq,dev_t * dev,int flag,int sflag,cred_t * cr,void * statep)473 usbser_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr,
474 void *statep)
475 {
476 usbser_state_t *usp;
477 usbser_port_t *pp;
478 int minor = getminor(*dev);
479 int instance;
480 uint_t port_num;
481 int rval;
482
483 instance = USBSER_MINOR2INST(minor);
484 if (instance < 0) {
485
486 return (ENXIO);
487 }
488
489 usp = ddi_get_soft_state(statep, instance);
490 if (usp == NULL) {
491
492 return (ENXIO);
493 }
494
495 /* don't allow to open disconnected device */
496 mutex_enter(&usp->us_mutex);
497 if (usp->us_dev_state == USB_DEV_DISCONNECTED) {
498 mutex_exit(&usp->us_mutex);
499
500 return (ENXIO);
501 }
502 mutex_exit(&usp->us_mutex);
503
504 /* get port soft state */
505 port_num = USBSER_MINOR2PORT(minor);
506 if (port_num >= usp->us_port_cnt) {
507
508 return (ENXIO);
509 }
510 pp = &usp->us_ports[port_num];
511
512 /* set up everything for open */
513 rval = usbser_open_setup(rq, pp, minor, flag, cr);
514
515 USB_DPRINTF_L4(DPRINT_OPEN, pp->port_lh, "usbser_open: rval=%d", rval);
516
517 return (rval);
518 }
519
520
521 /*
522 * port close
523 *
524 * some things driver should do when the last app closes the line:
525 *
526 * drain data;
527 * cancel break/delay;
528 * hangup line (if necessary);
529 * DSD close;
530 * cleanup soft state;
531 */
532 /*ARGSUSED*/
533 int
usbser_close(queue_t * rq,int flag,cred_t * cr)534 usbser_close(queue_t *rq, int flag, cred_t *cr)
535 {
536 usbser_port_t *pp = (usbser_port_t *)rq->q_ptr;
537 int online;
538
539 if (pp == NULL) {
540
541 return (ENXIO);
542 }
543
544 online = usbser_dev_is_online(pp->port_usp);
545
546 /*
547 * in the closing state new activities will not be initiated
548 */
549 mutex_enter(&pp->port_mutex);
550 pp->port_state = USBSER_PORT_CLOSING;
551
552 if (online) {
553 /* drain the data */
554 usbser_close_drain(pp);
555 }
556
557 /* stop break/delay */
558 usbser_close_cancel_break(pp);
559
560 if (online) {
561 /* hangup line */
562 usbser_close_hangup(pp);
563 }
564
565 /*
566 * close DSD, cleanup state and transition to 'closed' state
567 */
568 usbser_close_cleanup(pp);
569 mutex_exit(&pp->port_mutex);
570
571 USB_DPRINTF_L4(DPRINT_CLOSE, pp->port_lh, "usbser_close: end");
572
573 return (0);
574 }
575
576
577 /*
578 * read side service routine: send as much as possible messages upstream
579 * and if there is still place on the queue, enable receive (if not already)
580 */
581 int
usbser_rsrv(queue_t * q)582 usbser_rsrv(queue_t *q)
583 {
584 usbser_port_t *pp = (usbser_port_t *)q->q_ptr;
585 mblk_t *mp;
586
587 usbser_st_rsrv++;
588 USB_DPRINTF_L4(DPRINT_RQ, pp->port_lh, "usbser_rsrv");
589
590 while (canputnext(q) && (mp = getq(q))) {
591 putnext(q, mp);
592 }
593
594 if (canputnext(q)) {
595 mutex_enter(&pp->port_mutex);
596 ASSERT(pp->port_state != USBSER_PORT_CLOSED);
597
598 if (USBSER_PORT_ACCESS_OK(pp)) {
599 usbser_thr_wake(&pp->port_rq_thread);
600 }
601 mutex_exit(&pp->port_mutex);
602 }
603
604 return (0);
605 }
606
607
608 /*
609 * wput: put message on the queue and wake wq thread
610 */
611 int
usbser_wput(queue_t * q,mblk_t * mp)612 usbser_wput(queue_t *q, mblk_t *mp)
613 {
614 usbser_port_t *pp = (usbser_port_t *)q->q_ptr;
615
616 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wput");
617
618 mutex_enter(&pp->port_mutex);
619 ASSERT(pp->port_state != USBSER_PORT_CLOSED);
620
621 /* ignore new messages if port is already closing */
622 if (pp->port_state == USBSER_PORT_CLOSING) {
623 freemsg(mp);
624 } else if (putq(q, mp)) {
625 /*
626 * this counter represents amount of tx data on the wq.
627 * each time the data is passed to DSD for transmission,
628 * the counter is decremented accordingly
629 */
630 pp->port_wq_data_cnt += msgdsize(mp);
631 } else {
632 usbser_st_tx_data_loss++;
633 }
634 mutex_exit(&pp->port_mutex);
635
636 return (0);
637 }
638
639
640 /*
641 * we need wsrv() routine to take advantage of STREAMS flow control:
642 * without it the framework will consider we are always able to process msgs
643 */
644 int
usbser_wsrv(queue_t * q)645 usbser_wsrv(queue_t *q)
646 {
647 usbser_port_t *pp = (usbser_port_t *)q->q_ptr;
648
649 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wsrv");
650
651 mutex_enter(&pp->port_mutex);
652 ASSERT(pp->port_state != USBSER_PORT_CLOSED);
653
654 if (USBSER_PORT_ACCESS_OK(pp)) {
655 usbser_thr_wake(&pp->port_wq_thread);
656 }
657 mutex_exit(&pp->port_mutex);
658
659 return (0);
660 }
661
662
663 /*
664 * power entry point
665 */
666 int
usbser_power(dev_info_t * dip,int comp,int level)667 usbser_power(dev_info_t *dip, int comp, int level)
668 {
669 void *statep;
670 usbser_state_t *usp;
671 int new_state;
672 int rval;
673
674 statep = ddi_get_driver_private(dip);
675 usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
676
677 USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
678 "usbser_power: dip=0x%p, comp=%d, level=%d",
679 (void *)dip, comp, level);
680
681 mutex_enter(&usp->us_mutex);
682 new_state = usp->us_dev_state;
683 mutex_exit(&usp->us_mutex);
684
685 /* let DSD do the job */
686 rval = USBSER_DS_USB_POWER(usp, comp, level, &new_state);
687
688 /* stay in sync with DSD */
689 mutex_enter(&usp->us_mutex);
690 usp->us_dev_state = new_state;
691 mutex_exit(&usp->us_mutex);
692
693 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
694 }
695
696
697 /*
698 *
699 * configuration entry point subroutines
700 * -------------------------------------
701 *
702 * rseq callback
703 */
704 static int
usbser_rseq_do_cb(rseq_t * rseq,int num,uintptr_t arg)705 usbser_rseq_do_cb(rseq_t *rseq, int num, uintptr_t arg)
706 {
707 usbser_state_t *usp = (usbser_state_t *)arg;
708 int rval = rseq[num].r_do.s_rval;
709 char *name = rseq[num].r_do.s_name;
710
711 if (rval != DDI_SUCCESS) {
712 USB_DPRINTF_L2(DPRINT_ATTACH, usp->us_lh,
713 "do %s failed (%d)", name, rval);
714
715 return (RSEQ_UNDO);
716 } else {
717
718 return (RSEQ_OK);
719 }
720 }
721
722
723 /*
724 * free soft state
725 */
726 static int
usbser_free_soft_state(usbser_state_t * usp)727 usbser_free_soft_state(usbser_state_t *usp)
728 {
729 ddi_soft_state_free(usp->us_statep, usp->us_instance);
730
731 return (USB_SUCCESS);
732 }
733
734 /*
735 * init instance soft state
736 */
737 static int
usbser_init_soft_state(usbser_state_t * usp)738 usbser_init_soft_state(usbser_state_t *usp)
739 {
740 usp->us_lh = usb_alloc_log_hdl(usp->us_dip, "usbs[*].",
741 &usbser_errlevel, &usbser_errmask, &usbser_instance_debug,
742 0);
743 mutex_init(&usp->us_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
744
745 /* save state pointer for use in event callbacks */
746 ddi_set_driver_private(usp->us_dip, usp->us_statep);
747
748 usp->us_dev_state = USBSER_DEV_INIT;
749
750 return (DDI_SUCCESS);
751 }
752
753 /*
754 * fini instance soft state
755 */
756 static int
usbser_fini_soft_state(usbser_state_t * usp)757 usbser_fini_soft_state(usbser_state_t *usp)
758 {
759 usb_free_log_hdl(usp->us_lh);
760 mutex_destroy(&usp->us_mutex);
761 ddi_set_driver_private(usp->us_dip, NULL);
762
763 return (DDI_SUCCESS);
764 }
765
766 /*
767 * attach entire device
768 */
769 static int
usbser_attach_dev(usbser_state_t * usp)770 usbser_attach_dev(usbser_state_t *usp)
771 {
772 ds_attach_info_t ai;
773 int rval;
774
775 usp->us_dev_state = USB_DEV_ONLINE;
776
777 ai.ai_dip = usp->us_dip;
778 ai.ai_usb_events = &usbser_usb_events;
779 ai.ai_hdl = &usp->us_ds_hdl;
780 ai.ai_port_cnt = &usp->us_port_cnt;
781
782 rval = USBSER_DS_ATTACH(usp, &ai);
783
784 if ((rval != USB_SUCCESS) || (usp->us_ds_hdl == NULL) ||
785 (usp->us_port_cnt == 0)) {
786 USB_DPRINTF_L4(DPRINT_ATTACH, usp->us_lh, "usbser_attach_dev: "
787 "failed %d %p %d", rval, usp->us_ds_hdl, usp->us_port_cnt);
788
789 return (DDI_FAILURE);
790 }
791
792 USB_DPRINTF_L4(DPRINT_ATTACH, usp->us_lh,
793 "usbser_attach_dev: port_cnt = %d", usp->us_port_cnt);
794
795 return (DDI_SUCCESS);
796 }
797
798
799 /*
800 * detach entire device
801 */
802 static void
usbser_detach_dev(usbser_state_t * usp)803 usbser_detach_dev(usbser_state_t *usp)
804 {
805 USBSER_DS_DETACH(usp);
806 }
807
808
809 /*
810 * attach each individual port
811 */
812 static int
usbser_attach_ports(usbser_state_t * usp)813 usbser_attach_ports(usbser_state_t *usp)
814 {
815 int i;
816 usbser_port_t *pp;
817 ds_cb_t ds_cb;
818
819 /*
820 * allocate port array
821 */
822 usp->us_ports = kmem_zalloc(usp->us_port_cnt *
823 sizeof (usbser_port_t), KM_SLEEP);
824
825 /* callback handlers */
826 ds_cb.cb_tx = usbser_tx_cb;
827 ds_cb.cb_rx = usbser_rx_cb;
828 ds_cb.cb_status = usbser_status_cb;
829
830 /*
831 * initialize each port
832 */
833 for (i = 0; i < usp->us_port_cnt; i++) {
834 pp = &usp->us_ports[i];
835
836 /*
837 * initialize data
838 */
839 pp->port_num = i;
840 pp->port_usp = usp;
841 pp->port_ds_ops = usp->us_ds_ops;
842 pp->port_ds_hdl = usp->us_ds_hdl;
843
844 /* allocate log handle */
845 (void) sprintf(pp->port_lh_name, "usbs[%d].", i);
846 pp->port_lh = usb_alloc_log_hdl(usp->us_dip,
847 pp->port_lh_name, &usbser_errlevel, &usbser_errmask,
848 &usbser_instance_debug, 0);
849
850 mutex_init(&pp->port_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
851 cv_init(&pp->port_state_cv, NULL, CV_DEFAULT, NULL);
852 cv_init(&pp->port_act_cv, NULL, CV_DEFAULT, NULL);
853 cv_init(&pp->port_car_cv, NULL, CV_DEFAULT, NULL);
854
855 /*
856 * init threads
857 */
858 pp->port_wq_thread.thr_port = pp;
859 pp->port_wq_thread.thr_func = usbser_wq_thread;
860 pp->port_wq_thread.thr_arg = (void *)&pp->port_wq_thread;
861 cv_init(&pp->port_wq_thread.thr_cv, NULL, CV_DEFAULT, NULL);
862
863 pp->port_rq_thread.thr_port = pp;
864 pp->port_rq_thread.thr_func = usbser_rq_thread;
865 pp->port_rq_thread.thr_arg = (void *)&pp->port_rq_thread;
866 cv_init(&pp->port_rq_thread.thr_cv, NULL, CV_DEFAULT, NULL);
867
868 /*
869 * register callbacks
870 */
871 ds_cb.cb_arg = (caddr_t)pp;
872 USBSER_DS_REGISTER_CB(usp, i, &ds_cb);
873
874 pp->port_state = USBSER_PORT_CLOSED;
875
876 if (usbser_create_port_minor_nodes(usp, i) != USB_SUCCESS) {
877 usbser_detach_ports(usp);
878
879 return (DDI_FAILURE);
880 }
881 }
882
883 return (DDI_SUCCESS);
884 }
885
886
887 /*
888 * create a pair of minor nodes for the port
889 */
890 static int
usbser_create_port_minor_nodes(usbser_state_t * usp,int port_num)891 usbser_create_port_minor_nodes(usbser_state_t *usp, int port_num)
892 {
893 int instance = usp->us_instance;
894 minor_t minor;
895 char name[16];
896
897 /*
898 * tty node
899 */
900 (void) sprintf(name, "%d", port_num);
901 minor = USBSER_MAKEMINOR(instance, port_num, 0);
902
903 if (ddi_create_minor_node(usp->us_dip, name,
904 S_IFCHR, minor, DDI_NT_SERIAL, NULL) != DDI_SUCCESS) {
905
906 return (USB_FAILURE);
907 }
908
909 /*
910 * dial-out node
911 */
912 (void) sprintf(name, "%d,cu", port_num);
913 minor = USBSER_MAKEMINOR(instance, port_num, OUTLINE);
914
915 if (ddi_create_minor_node(usp->us_dip, name,
916 S_IFCHR, minor, DDI_NT_SERIAL_DO, NULL) != DDI_SUCCESS) {
917
918 return (USB_FAILURE);
919 }
920
921 return (USB_SUCCESS);
922 }
923
924
925 /*
926 * detach each port individually
927 */
928 static void
usbser_detach_ports(usbser_state_t * usp)929 usbser_detach_ports(usbser_state_t *usp)
930 {
931 int i;
932 int sz;
933 usbser_port_t *pp;
934
935 /*
936 * remove all minor nodes
937 */
938 ddi_remove_minor_node(usp->us_dip, NULL);
939
940 for (i = 0; i < usp->us_port_cnt; i++) {
941 pp = &usp->us_ports[i];
942
943 if (pp->port_state != USBSER_PORT_CLOSED) {
944 ASSERT(pp->port_state == USBSER_PORT_NOT_INIT);
945
946 continue;
947 }
948
949 USBSER_DS_UNREGISTER_CB(usp, i);
950
951 mutex_destroy(&pp->port_mutex);
952 cv_destroy(&pp->port_state_cv);
953 cv_destroy(&pp->port_act_cv);
954 cv_destroy(&pp->port_car_cv);
955
956 cv_destroy(&pp->port_wq_thread.thr_cv);
957 cv_destroy(&pp->port_rq_thread.thr_cv);
958
959 usb_free_log_hdl(pp->port_lh);
960 }
961
962 /*
963 * free memory
964 */
965 sz = usp->us_port_cnt * sizeof (usbser_port_t);
966 kmem_free(usp->us_ports, sz);
967 usp->us_ports = NULL;
968 }
969
970
971 /*
972 * create a taskq with two threads per port (read and write sides)
973 */
974 static int
usbser_create_taskq(usbser_state_t * usp)975 usbser_create_taskq(usbser_state_t *usp)
976 {
977 int nthr = usp->us_port_cnt * 2;
978
979 usp->us_taskq = ddi_taskq_create(usp->us_dip, "usbser_taskq",
980 nthr, TASKQ_DEFAULTPRI, 0);
981
982 return ((usp->us_taskq == NULL) ? DDI_FAILURE : DDI_SUCCESS);
983 }
984
985
986 static void
usbser_destroy_taskq(usbser_state_t * usp)987 usbser_destroy_taskq(usbser_state_t *usp)
988 {
989 ddi_taskq_destroy(usp->us_taskq);
990 }
991
992
993 static void
usbser_set_dev_state_init(usbser_state_t * usp)994 usbser_set_dev_state_init(usbser_state_t *usp)
995 {
996 mutex_enter(&usp->us_mutex);
997 usp->us_dev_state = USBSER_DEV_INIT;
998 mutex_exit(&usp->us_mutex);
999 }
1000
1001 /*
1002 * hotplugging and power management
1003 * ---------------------------------
1004 *
1005 * disconnect event callback
1006 */
1007 /*ARGSUSED*/
1008 static int
usbser_disconnect_cb(dev_info_t * dip)1009 usbser_disconnect_cb(dev_info_t *dip)
1010 {
1011 void *statep;
1012 usbser_state_t *usp;
1013
1014 statep = ddi_get_driver_private(dip);
1015 usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
1016
1017 USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
1018 "usbser_disconnect_cb: dip=%p", (void *)dip);
1019
1020 mutex_enter(&usp->us_mutex);
1021 switch (usp->us_dev_state) {
1022 case USB_DEV_ONLINE:
1023 case USB_DEV_PWRED_DOWN:
1024 /* prevent further activity */
1025 usp->us_dev_state = USB_DEV_DISCONNECTED;
1026 mutex_exit(&usp->us_mutex);
1027
1028 /* see if any of the ports are open and do necessary handling */
1029 usbser_disconnect_ports(usp);
1030
1031 /* call DSD to do any necessary work */
1032 if (USBSER_DS_DISCONNECT(usp) != USB_DEV_DISCONNECTED) {
1033 USB_DPRINTF_L2(DPRINT_EVENTS, usp->us_lh,
1034 "usbser_disconnect_cb: ds_disconnect failed");
1035 }
1036
1037 break;
1038 case USB_DEV_SUSPENDED:
1039 /* we remain suspended */
1040 default:
1041 mutex_exit(&usp->us_mutex);
1042
1043 break;
1044 }
1045
1046 return (USB_SUCCESS);
1047 }
1048
1049
1050 /*
1051 * reconnect event callback
1052 */
1053 /*ARGSUSED*/
1054 static int
usbser_reconnect_cb(dev_info_t * dip)1055 usbser_reconnect_cb(dev_info_t *dip)
1056 {
1057 void *statep;
1058 usbser_state_t *usp;
1059
1060 statep = ddi_get_driver_private(dip);
1061 usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
1062
1063 USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
1064 "usbser_reconnect_cb: dip=%p", (void *)dip);
1065
1066 (void) usbser_restore_device_state(usp);
1067
1068 return (USB_SUCCESS);
1069 }
1070
1071
1072 /*
1073 * if any of the ports is open during disconnect,
1074 * send M_HANGUP message upstream and log a warning
1075 */
1076 static void
usbser_disconnect_ports(usbser_state_t * usp)1077 usbser_disconnect_ports(usbser_state_t *usp)
1078 {
1079 usbser_port_t *pp;
1080 queue_t *rq;
1081 int complain = 0;
1082 int hangup = 0;
1083 timeout_id_t delay_id = 0;
1084 int i;
1085
1086 if (usp->us_ports == NULL) {
1087 return;
1088 }
1089
1090 for (i = 0; i < usp->us_port_cnt; i++) {
1091 pp = &usp->us_ports[i];
1092
1093 mutex_enter(&pp->port_mutex);
1094 if (pp->port_state == USBSER_PORT_OPEN ||
1095 USBSER_IS_OPENING(pp) ||
1096 pp->port_state == USBSER_PORT_CLOSING) {
1097 complain = 1;
1098 }
1099
1100 if (pp->port_state == USBSER_PORT_OPEN) {
1101 rq = pp->port_ttycommon.t_readq;
1102
1103 /*
1104 * hangup the stream; will send actual
1105 * M_HANGUP message after releasing mutex
1106 */
1107 pp->port_flags |= USBSER_FL_HUNGUP;
1108 hangup = 1;
1109
1110 /*
1111 * cancel all activities
1112 */
1113 usbser_release_port_act(pp, USBSER_ACT_ALL);
1114
1115 delay_id = pp->port_delay_id;
1116 pp->port_delay_id = 0;
1117
1118 /* mark disconnected */
1119 pp->port_state = USBSER_PORT_DISCONNECTED;
1120 cv_broadcast(&pp->port_state_cv);
1121 }
1122 mutex_exit(&pp->port_mutex);
1123
1124 if (hangup) {
1125 (void) putnextctl(rq, M_HANGUP);
1126 hangup = 0;
1127 }
1128
1129 /*
1130 * we couldn't untimeout while holding the mutex - do it now
1131 */
1132 if (delay_id) {
1133 (void) untimeout(delay_id);
1134 delay_id = 0;
1135 }
1136 }
1137
1138 /*
1139 * complain about disconnecting device while open
1140 */
1141 if (complain) {
1142 USB_DPRINTF_L0(DPRINT_EVENTS, usp->us_lh, "device was "
1143 "disconnected while open. Data may have been lost");
1144 }
1145 }
1146
1147
1148 /*
1149 * do CPR suspend
1150 *
1151 * We use a trivial CPR strategy - fail if any of the device's ports are open.
1152 * The problem with more sophisticated strategies is that each open port uses
1153 * two threads that sit in the loop until the port is closed, while CPR has to
1154 * stop all kernel threads to succeed. Stopping port threads is a rather
1155 * intrusive and delicate procedure; I leave it as an RFE for now.
1156 *
1157 */
1158 static int
usbser_cpr_suspend(dev_info_t * dip)1159 usbser_cpr_suspend(dev_info_t *dip)
1160 {
1161 void *statep;
1162 usbser_state_t *usp;
1163 int new_state;
1164 int rval;
1165
1166 statep = ddi_get_driver_private(dip);
1167 usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
1168
1169 USB_DPRINTF_L4(DPRINT_EVENTS, usp->us_lh, "usbser_cpr_suspend");
1170
1171 /* suspend each port first */
1172 if (usbser_suspend_ports(usp) != USB_SUCCESS) {
1173 USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
1174 "usbser_cpr_suspend: GSD failure");
1175
1176 return (USB_FAILURE);
1177 }
1178
1179 new_state = USBSER_DS_SUSPEND(usp); /* let DSD do its part */
1180
1181 mutex_enter(&usp->us_mutex);
1182 if (new_state == USB_DEV_SUSPENDED) {
1183 rval = USB_SUCCESS;
1184 } else {
1185 ASSERT(new_state == USB_DEV_ONLINE);
1186 rval = USB_FAILURE;
1187 }
1188 usp->us_dev_state = new_state;
1189 mutex_exit(&usp->us_mutex);
1190
1191 return (rval);
1192 }
1193
1194
1195 static int
usbser_suspend_ports(usbser_state_t * usp)1196 usbser_suspend_ports(usbser_state_t *usp)
1197 {
1198 usbser_port_t *pp;
1199 int i;
1200
1201 for (i = 0; i < usp->us_port_cnt; i++) {
1202 pp = &usp->us_ports[i];
1203
1204 mutex_enter(&pp->port_mutex);
1205 if (pp->port_state != USBSER_PORT_CLOSED) {
1206 mutex_exit(&pp->port_mutex);
1207
1208 return (USB_FAILURE);
1209 }
1210 mutex_exit(&pp->port_mutex);
1211 }
1212
1213 return (USB_SUCCESS);
1214 }
1215
1216
1217 /*
1218 * do CPR resume
1219 *
1220 * DSD will return USB_DEV_ONLINE in case of success
1221 */
1222 static void
usbser_cpr_resume(dev_info_t * dip)1223 usbser_cpr_resume(dev_info_t *dip)
1224 {
1225 void *statep;
1226 usbser_state_t *usp;
1227
1228 statep = ddi_get_driver_private(dip);
1229 usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
1230
1231 USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh, "usbser_cpr_resume");
1232
1233 (void) usbser_restore_device_state(usp);
1234 }
1235
1236
1237 /*
1238 * restore device state after CPR resume or reconnect
1239 */
1240 static int
usbser_restore_device_state(usbser_state_t * usp)1241 usbser_restore_device_state(usbser_state_t *usp)
1242 {
1243 int new_state, current_state;
1244
1245 /* needed as power up state of dev is "unknown" to system */
1246 (void) pm_busy_component(usp->us_dip, 0);
1247 (void) pm_raise_power(usp->us_dip, 0, USB_DEV_OS_FULL_PWR);
1248
1249 mutex_enter(&usp->us_mutex);
1250 current_state = usp->us_dev_state;
1251 mutex_exit(&usp->us_mutex);
1252
1253 ASSERT((current_state == USB_DEV_DISCONNECTED) ||
1254 (current_state == USB_DEV_SUSPENDED));
1255
1256 /*
1257 * call DSD to perform device-specific work
1258 */
1259 if (current_state == USB_DEV_DISCONNECTED) {
1260 new_state = USBSER_DS_RECONNECT(usp);
1261 } else {
1262 new_state = USBSER_DS_RESUME(usp);
1263 }
1264
1265 mutex_enter(&usp->us_mutex);
1266 usp->us_dev_state = new_state;
1267 mutex_exit(&usp->us_mutex);
1268
1269 if (new_state == USB_DEV_ONLINE) {
1270 /*
1271 * restore ports state
1272 */
1273 usbser_restore_ports_state(usp);
1274 }
1275
1276 (void) pm_idle_component(usp->us_dip, 0);
1277
1278 return (USB_SUCCESS);
1279 }
1280
1281
1282 /*
1283 * restore ports state after device reconnect/resume
1284 */
1285 static void
usbser_restore_ports_state(usbser_state_t * usp)1286 usbser_restore_ports_state(usbser_state_t *usp)
1287 {
1288 usbser_port_t *pp;
1289 queue_t *rq;
1290 int i;
1291
1292 for (i = 0; i < usp->us_port_cnt; i++) {
1293 pp = &usp->us_ports[i];
1294
1295 mutex_enter(&pp->port_mutex);
1296 /*
1297 * only care about ports that are open
1298 */
1299 if ((pp->port_state != USBSER_PORT_SUSPENDED) &&
1300 (pp->port_state != USBSER_PORT_DISCONNECTED)) {
1301 mutex_exit(&pp->port_mutex);
1302
1303 continue;
1304 }
1305
1306 pp->port_state = USBSER_PORT_OPEN;
1307
1308 /*
1309 * if the stream was hung up during disconnect, restore it
1310 */
1311 if (pp->port_flags & USBSER_FL_HUNGUP) {
1312 pp->port_flags &= ~USBSER_FL_HUNGUP;
1313 rq = pp->port_ttycommon.t_readq;
1314
1315 mutex_exit(&pp->port_mutex);
1316 (void) putnextctl(rq, M_UNHANGUP);
1317 mutex_enter(&pp->port_mutex);
1318 }
1319
1320 /*
1321 * restore serial parameters
1322 */
1323 (void) usbser_port_program(pp);
1324
1325 /*
1326 * wake anything that might be sleeping
1327 */
1328 cv_broadcast(&pp->port_state_cv);
1329 cv_broadcast(&pp->port_act_cv);
1330 usbser_thr_wake(&pp->port_wq_thread);
1331 usbser_thr_wake(&pp->port_rq_thread);
1332 mutex_exit(&pp->port_mutex);
1333 }
1334 }
1335
1336
1337 /*
1338 * STREAMS subroutines
1339 * -------------------
1340 *
1341 *
1342 * port open state machine
1343 *
1344 * here's a list of things that the driver has to do while open;
1345 * because device can be opened any number of times,
1346 * initial open has additional responsibilities:
1347 *
1348 * if (initial_open) {
1349 * initialize soft state; \
1350 * DSD open; - see usbser_open_init()
1351 * dispatch threads; /
1352 * }
1353 * raise DTR;
1354 * wait for carrier (if necessary);
1355 *
1356 * we should also take into consideration that two threads can try to open
1357 * the same physical port simultaneously (/dev/term/N and /dev/cua/N).
1358 *
1359 * return values:
1360 * 0 - success;
1361 * >0 - fail with this error code;
1362 */
1363 static int
usbser_open_setup(queue_t * rq,usbser_port_t * pp,int minor,int flag,cred_t * cr)1364 usbser_open_setup(queue_t *rq, usbser_port_t *pp, int minor, int flag,
1365 cred_t *cr)
1366 {
1367 int rval = USBSER_CONTINUE;
1368
1369 mutex_enter(&pp->port_mutex);
1370 /*
1371 * refer to port state diagram in the header file
1372 */
1373 loop:
1374 switch (pp->port_state) {
1375 case USBSER_PORT_CLOSED:
1376 /*
1377 * initial open
1378 */
1379 rval = usbser_open_init(pp, minor);
1380
1381 break;
1382 case USBSER_PORT_OPENING_TTY:
1383 /*
1384 * dial-out thread can overtake the port
1385 * if tty open thread is sleeping waiting for carrier
1386 */
1387 if ((minor & OUTLINE) && (pp->port_flags & USBSER_FL_WOPEN)) {
1388 pp->port_state = USBSER_PORT_OPENING_OUT;
1389
1390 USB_DPRINTF_L3(DPRINT_OPEN, pp->port_lh,
1391 "usbser_open_state: overtake");
1392 }
1393
1394 /* FALLTHRU */
1395 case USBSER_PORT_OPENING_OUT:
1396 /*
1397 * if no other open in progress, setup the line
1398 */
1399 if (USBSER_NO_OTHER_OPEN(pp, minor)) {
1400 rval = usbser_open_line_setup(pp, minor, flag);
1401
1402 break;
1403 }
1404
1405 /* FALLTHRU */
1406 case USBSER_PORT_CLOSING:
1407 /*
1408 * wait until close active phase ends
1409 */
1410 if (cv_wait_sig(&pp->port_state_cv, &pp->port_mutex) == 0) {
1411 rval = EINTR;
1412 }
1413
1414 break;
1415 case USBSER_PORT_OPEN:
1416 if ((pp->port_ttycommon.t_flags & TS_XCLUDE) &&
1417 secpolicy_excl_open(cr) != 0) {
1418 /*
1419 * exclusive use
1420 */
1421 rval = EBUSY;
1422 } else if (USBSER_OPEN_IN_OTHER_MODE(pp, minor)) {
1423 /*
1424 * tty and dial-out modes are mutually exclusive
1425 */
1426 rval = EBUSY;
1427 } else {
1428 /*
1429 * port is being re-open in the same mode
1430 */
1431 rval = usbser_open_line_setup(pp, minor, flag);
1432 }
1433
1434 break;
1435 default:
1436 rval = ENXIO;
1437
1438 break;
1439 }
1440
1441 if (rval == USBSER_CONTINUE) {
1442
1443 goto loop;
1444 }
1445
1446 /*
1447 * initial open requires additional handling
1448 */
1449 if (USBSER_IS_OPENING(pp)) {
1450 if (rval == USBSER_COMPLETE) {
1451 if (pp->port_state == USBSER_PORT_OPENING_OUT) {
1452 pp->port_flags |= USBSER_FL_OUT;
1453 }
1454 pp->port_state = USBSER_PORT_OPEN;
1455 cv_broadcast(&pp->port_state_cv);
1456
1457 usbser_open_queues_init(pp, rq);
1458 } else {
1459 usbser_open_fini(pp);
1460 }
1461 }
1462 mutex_exit(&pp->port_mutex);
1463
1464 return (rval);
1465 }
1466
1467
1468 /*
1469 * initialize the port when opened for the first time
1470 */
1471 static int
usbser_open_init(usbser_port_t * pp,int minor)1472 usbser_open_init(usbser_port_t *pp, int minor)
1473 {
1474 usbser_state_t *usp = pp->port_usp;
1475 tty_common_t *tp = &pp->port_ttycommon;
1476 int rval = ENXIO;
1477
1478 ASSERT(pp->port_state == USBSER_PORT_CLOSED);
1479
1480 /*
1481 * init state
1482 */
1483 pp->port_act = 0;
1484 pp->port_flags &= USBSER_FL_PRESERVE;
1485 pp->port_flowc = '\0';
1486 pp->port_wq_data_cnt = 0;
1487
1488 if (minor & OUTLINE) {
1489 pp->port_state = USBSER_PORT_OPENING_OUT;
1490 } else {
1491 pp->port_state = USBSER_PORT_OPENING_TTY;
1492 }
1493
1494 /*
1495 * init termios settings
1496 */
1497 tp->t_iflag = 0;
1498 tp->t_iocpending = NULL;
1499 tp->t_size.ws_row = tp->t_size.ws_col = 0;
1500 tp->t_size.ws_xpixel = tp->t_size.ws_ypixel = 0;
1501 tp->t_startc = CSTART;
1502 tp->t_stopc = CSTOP;
1503
1504 usbser_check_port_props(pp);
1505
1506 /*
1507 * dispatch wq and rq threads:
1508 * although queues are not enabled at this point,
1509 * we will need wq to run status processing callback
1510 */
1511 usbser_thr_dispatch(&pp->port_wq_thread);
1512 usbser_thr_dispatch(&pp->port_rq_thread);
1513
1514 /*
1515 * open DSD port
1516 */
1517 mutex_exit(&pp->port_mutex);
1518 rval = USBSER_DS_OPEN_PORT(usp, pp->port_num);
1519 mutex_enter(&pp->port_mutex);
1520
1521 if (rval != USB_SUCCESS) {
1522
1523 return (ENXIO);
1524 }
1525 pp->port_flags |= USBSER_FL_DSD_OPEN;
1526
1527 /*
1528 * program port with default parameters
1529 */
1530 if ((rval = usbser_port_program(pp)) != 0) {
1531
1532 return (ENXIO);
1533 }
1534
1535 return (USBSER_CONTINUE);
1536 }
1537
1538
1539 /*
1540 * create a pair of minor nodes for the port
1541 */
1542 static void
usbser_check_port_props(usbser_port_t * pp)1543 usbser_check_port_props(usbser_port_t *pp)
1544 {
1545 dev_info_t *dip = pp->port_usp->us_dip;
1546 tty_common_t *tp = &pp->port_ttycommon;
1547 struct termios *termiosp;
1548 uint_t len;
1549 char name[20];
1550
1551 /*
1552 * take default modes from "ttymodes" property if it exists
1553 */
1554 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ddi_root_node(), 0,
1555 "ttymodes", (uchar_t **)&termiosp, &len) == DDI_PROP_SUCCESS) {
1556
1557 if (len == sizeof (struct termios)) {
1558 tp->t_cflag = termiosp->c_cflag;
1559
1560 if (termiosp->c_iflag & (IXON | IXANY)) {
1561 tp->t_iflag =
1562 termiosp->c_iflag & (IXON | IXANY);
1563 tp->t_startc = termiosp->c_cc[VSTART];
1564 tp->t_stopc = termiosp->c_cc[VSTOP];
1565 }
1566 }
1567 ddi_prop_free(termiosp);
1568 }
1569
1570 /*
1571 * look for "ignore-cd" or "port-N-ignore-cd" property
1572 */
1573 (void) sprintf(name, "port-%d-ignore-cd", pp->port_num);
1574 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1575 "ignore-cd", 0) ||
1576 ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, name, 0)) {
1577 pp->port_flags |= USBSER_FL_IGNORE_CD;
1578 } else {
1579 pp->port_flags &= ~USBSER_FL_IGNORE_CD;
1580 }
1581 }
1582
1583
1584 /*
1585 * undo what was done in usbser_open_init()
1586 */
1587 static void
usbser_open_fini(usbser_port_t * pp)1588 usbser_open_fini(usbser_port_t *pp)
1589 {
1590 uint_t port_num = pp->port_num;
1591 usbser_state_t *usp = pp->port_usp;
1592
1593 /*
1594 * close DSD if it is open
1595 */
1596 if (pp->port_flags & USBSER_FL_DSD_OPEN) {
1597 mutex_exit(&pp->port_mutex);
1598 if (USBSER_DS_CLOSE_PORT(usp, port_num) != USB_SUCCESS) {
1599 USB_DPRINTF_L2(DPRINT_CLOSE, pp->port_lh,
1600 "usbser_open_fini: CLOSE_PORT fail");
1601 }
1602 mutex_enter(&pp->port_mutex);
1603 }
1604
1605 /*
1606 * cancel threads
1607 */
1608 usbser_thr_cancel(&pp->port_wq_thread);
1609 usbser_thr_cancel(&pp->port_rq_thread);
1610
1611 /*
1612 * unpdate soft state
1613 */
1614 pp->port_state = USBSER_PORT_CLOSED;
1615 cv_broadcast(&pp->port_state_cv);
1616 cv_broadcast(&pp->port_car_cv);
1617 }
1618
1619
1620 /*
1621 * setup serial line
1622 */
1623 static int
usbser_open_line_setup(usbser_port_t * pp,int minor,int flag)1624 usbser_open_line_setup(usbser_port_t *pp, int minor, int flag)
1625 {
1626 int rval;
1627
1628 mutex_exit(&pp->port_mutex);
1629 /*
1630 * prevent opening a disconnected device
1631 */
1632 if (!usbser_dev_is_online(pp->port_usp)) {
1633 mutex_enter(&pp->port_mutex);
1634
1635 return (ENXIO);
1636 }
1637
1638 /* raise DTR on every open */
1639 (void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR, TIOCM_DTR);
1640
1641 mutex_enter(&pp->port_mutex);
1642 /*
1643 * check carrier
1644 */
1645 rval = usbser_open_carrier_check(pp, minor, flag);
1646
1647 return (rval);
1648 }
1649
1650
1651 /*
1652 * check carrier and wait if needed
1653 */
1654 static int
usbser_open_carrier_check(usbser_port_t * pp,int minor,int flag)1655 usbser_open_carrier_check(usbser_port_t *pp, int minor, int flag)
1656 {
1657 tty_common_t *tp = &pp->port_ttycommon;
1658 int val = 0;
1659 int rval;
1660
1661 if (pp->port_flags & USBSER_FL_IGNORE_CD) {
1662 tp->t_flags |= TS_SOFTCAR;
1663 }
1664
1665 /*
1666 * check carrier
1667 */
1668 if (tp->t_flags & TS_SOFTCAR) {
1669 pp->port_flags |= USBSER_FL_CARR_ON;
1670 } else if (USBSER_DS_GET_MODEM_CTL(pp, TIOCM_CD, &val) != USB_SUCCESS) {
1671
1672 return (ENXIO);
1673 } else if (val & TIOCM_CD) {
1674 pp->port_flags |= USBSER_FL_CARR_ON;
1675 } else {
1676 pp->port_flags &= ~USBSER_FL_CARR_ON;
1677 }
1678
1679 /*
1680 * don't block if 1) not allowed to, 2) this is a local device,
1681 * 3) opening in dial-out mode, or 4) carrier is already on
1682 */
1683 if ((flag & (FNDELAY | FNONBLOCK)) || (tp->t_cflag & CLOCAL) ||
1684 (minor & OUTLINE) || (pp->port_flags & USBSER_FL_CARR_ON)) {
1685
1686 return (USBSER_COMPLETE);
1687 }
1688
1689 /*
1690 * block until carrier up (only in tty mode)
1691 */
1692 USB_DPRINTF_L4(DPRINT_OPEN, pp->port_lh,
1693 "usbser_open_carrier_check: waiting for carrier...");
1694
1695 pp->port_flags |= USBSER_FL_WOPEN;
1696
1697 rval = cv_wait_sig(&pp->port_car_cv, &pp->port_mutex);
1698
1699 pp->port_flags &= ~USBSER_FL_WOPEN;
1700
1701 if (rval == 0) {
1702 /*
1703 * interrupted with a signal
1704 */
1705 return (EINTR);
1706 } else {
1707 /*
1708 * try again
1709 */
1710 return (USBSER_CONTINUE);
1711 }
1712 }
1713
1714
1715 /*
1716 * during open, setup queues and message processing
1717 */
1718 static void
usbser_open_queues_init(usbser_port_t * pp,queue_t * rq)1719 usbser_open_queues_init(usbser_port_t *pp, queue_t *rq)
1720 {
1721 pp->port_ttycommon.t_readq = rq;
1722 pp->port_ttycommon.t_writeq = WR(rq);
1723 rq->q_ptr = WR(rq)->q_ptr = (caddr_t)pp;
1724
1725 qprocson(rq);
1726 }
1727
1728
1729 /*
1730 * clean up queues and message processing
1731 */
1732 static void
usbser_open_queues_fini(usbser_port_t * pp)1733 usbser_open_queues_fini(usbser_port_t *pp)
1734 {
1735 queue_t *rq = pp->port_ttycommon.t_readq;
1736
1737 mutex_exit(&pp->port_mutex);
1738 /*
1739 * clean up queues
1740 */
1741 qprocsoff(rq);
1742
1743 /*
1744 * free unused messages
1745 */
1746 flushq(rq, FLUSHALL);
1747 flushq(WR(rq), FLUSHALL);
1748
1749 rq->q_ptr = WR(rq)->q_ptr = NULL;
1750 ttycommon_close(&pp->port_ttycommon);
1751 mutex_enter(&pp->port_mutex);
1752 }
1753
1754
1755 /*
1756 * during close, wait until pending data is gone or the signal is sent
1757 */
1758 static void
usbser_close_drain(usbser_port_t * pp)1759 usbser_close_drain(usbser_port_t *pp)
1760 {
1761 int need_drain;
1762 clock_t until;
1763 int rval = USB_SUCCESS;
1764
1765 /*
1766 * port_wq_data_cnt indicates amount of data on the write queue,
1767 * which becomes zero when all data is submitted to DSD. But usbser
1768 * stays busy until it gets tx callback from DSD, signalling that
1769 * data has been sent over USB. To be continued in the next comment...
1770 */
1771 until = ddi_get_lbolt() +
1772 drv_usectohz(USBSER_WQ_DRAIN_TIMEOUT * 1000000);
1773
1774 while ((pp->port_wq_data_cnt > 0) && USBSER_PORT_IS_BUSY(pp)) {
1775 if ((rval = cv_timedwait_sig(&pp->port_act_cv, &pp->port_mutex,
1776 until)) <= 0) {
1777
1778 break;
1779 }
1780 }
1781
1782 /* don't drain if timed out or received a signal */
1783 need_drain = (pp->port_wq_data_cnt == 0) || !USBSER_PORT_IS_BUSY(pp) ||
1784 (rval != USB_SUCCESS);
1785
1786 mutex_exit(&pp->port_mutex);
1787 /*
1788 * Once the data reaches USB serial box, it may still be stored in its
1789 * internal output buffer (FIFO). We call DSD drain to ensure that all
1790 * the data is transmitted transmitted over the serial line.
1791 */
1792 if (need_drain) {
1793 rval = USBSER_DS_FIFO_DRAIN(pp, USBSER_TX_FIFO_DRAIN_TIMEOUT);
1794 if (rval != USB_SUCCESS) {
1795 (void) USBSER_DS_FIFO_FLUSH(pp, DS_TX);
1796 }
1797 } else {
1798 (void) USBSER_DS_FIFO_FLUSH(pp, DS_TX);
1799 }
1800 mutex_enter(&pp->port_mutex);
1801 }
1802
1803
1804 /*
1805 * during close, cancel break/delay
1806 */
1807 static void
usbser_close_cancel_break(usbser_port_t * pp)1808 usbser_close_cancel_break(usbser_port_t *pp)
1809 {
1810 timeout_id_t delay_id;
1811
1812 if (pp->port_act & USBSER_ACT_BREAK) {
1813 delay_id = pp->port_delay_id;
1814 pp->port_delay_id = 0;
1815
1816 mutex_exit(&pp->port_mutex);
1817 (void) untimeout(delay_id);
1818 (void) USBSER_DS_BREAK_CTL(pp, DS_OFF);
1819 mutex_enter(&pp->port_mutex);
1820
1821 pp->port_act &= ~USBSER_ACT_BREAK;
1822 }
1823 }
1824
1825
1826 /*
1827 * during close, drop RTS/DTR if necessary
1828 */
1829 static void
usbser_close_hangup(usbser_port_t * pp)1830 usbser_close_hangup(usbser_port_t *pp)
1831 {
1832 /*
1833 * drop DTR and RTS if HUPCL is set
1834 */
1835 if (pp->port_ttycommon.t_cflag & HUPCL) {
1836 mutex_exit(&pp->port_mutex);
1837 (void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_RTS | TIOCM_DTR, 0);
1838 mutex_enter(&pp->port_mutex);
1839 }
1840 }
1841
1842
1843 /*
1844 * state cleanup during close
1845 */
1846 static void
usbser_close_cleanup(usbser_port_t * pp)1847 usbser_close_cleanup(usbser_port_t *pp)
1848 {
1849 usbser_open_queues_fini(pp);
1850
1851 usbser_open_fini(pp);
1852 }
1853
1854
1855 /*
1856 *
1857 * thread management
1858 * -----------------
1859 *
1860 *
1861 * dispatch a thread
1862 */
1863 static void
usbser_thr_dispatch(usbser_thread_t * thr)1864 usbser_thr_dispatch(usbser_thread_t *thr)
1865 {
1866 usbser_port_t *pp = thr->thr_port;
1867 usbser_state_t *usp = pp->port_usp;
1868 /*LINTED E_FUNC_SET_NOT_USED*/
1869 int rval;
1870
1871 ASSERT(mutex_owned(&pp->port_mutex));
1872 ASSERT((thr->thr_flags & USBSER_THR_RUNNING) == 0);
1873
1874 thr->thr_flags = USBSER_THR_RUNNING;
1875
1876 rval = ddi_taskq_dispatch(usp->us_taskq, thr->thr_func, thr->thr_arg,
1877 DDI_SLEEP);
1878 ASSERT(rval == DDI_SUCCESS);
1879 }
1880
1881
1882 /*
1883 * cancel a thread
1884 */
1885 static void
usbser_thr_cancel(usbser_thread_t * thr)1886 usbser_thr_cancel(usbser_thread_t *thr)
1887 {
1888 usbser_port_t *pp = thr->thr_port;
1889
1890 ASSERT(mutex_owned(&pp->port_mutex));
1891
1892 thr->thr_flags &= ~USBSER_THR_RUNNING;
1893 cv_signal(&thr->thr_cv);
1894
1895 /* wait until the thread actually exits */
1896 do {
1897 cv_wait(&thr->thr_cv, &pp->port_mutex);
1898
1899 } while ((thr->thr_flags & USBSER_THR_EXITED) == 0);
1900 }
1901
1902
1903 /*
1904 * wake thread
1905 */
1906 static void
usbser_thr_wake(usbser_thread_t * thr)1907 usbser_thr_wake(usbser_thread_t *thr)
1908 {
1909 ASSERT(mutex_owned(&thr->thr_port->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 = USB_SUCCESS;
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 = USB_FAILURE;
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 #ifdef DEBUG
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 static char *
usbser_ioctl2str(int ioctl)3333 usbser_ioctl2str(int ioctl)
3334 {
3335 char *str;
3336
3337 switch (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;
3362 }
3363
3364 return (str);
3365 }
3366 #endif
3367 /*
3368 * Polled IO support
3369 */
3370
3371 /* called once by consconfig() when polledio is opened */
3372 static int
usbser_polledio_init(usbser_port_t * pp)3373 usbser_polledio_init(usbser_port_t *pp)
3374 {
3375 int err;
3376 usb_pipe_handle_t hdl;
3377 ds_ops_t *ds_ops = pp->port_ds_ops;
3378
3379 /* only one serial line console supported */
3380 if (console_input != NULL)
3381 return (USB_FAILURE);
3382
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);
3387
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);
3392 if (err)
3393 return (USB_FAILURE);
3394
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,
3398 &console_output);
3399 if (err) {
3400 (void) usb_console_input_fini(console_input);
3401 console_input = NULL;
3402 return (USB_FAILURE);
3403 }
3404
3405 return (USB_SUCCESS);
3406 }
3407
3408 /* called once by consconfig() when polledio is closed */
3409 /*ARGSUSED*/
usbser_polledio_fini(usbser_port_t * pp)3410 static void usbser_polledio_fini(usbser_port_t *pp)
3411 {
3412 /* Since we can't move the console, there is nothing to do. */
3413 }
3414
3415 /*ARGSUSED*/
3416 static void
usbser_polledio_enter(cons_polledio_arg_t arg)3417 usbser_polledio_enter(cons_polledio_arg_t arg)
3418 {
3419 (void) usb_console_input_enter(console_input);
3420 (void) usb_console_output_enter(console_output);
3421 }
3422
3423 /*ARGSUSED*/
3424 static void
usbser_polledio_exit(cons_polledio_arg_t arg)3425 usbser_polledio_exit(cons_polledio_arg_t arg)
3426 {
3427 (void) usb_console_output_exit(console_output);
3428 (void) usb_console_input_exit(console_input);
3429 }
3430
3431 /*ARGSUSED*/
3432 static void
usbser_putchar(cons_polledio_arg_t arg,uchar_t c)3433 usbser_putchar(cons_polledio_arg_t arg, uchar_t c)
3434 {
3435 static uchar_t cr[2] = {'\r', '\n'};
3436 uint_t nout;
3437
3438 if (c == '\n')
3439 (void) usb_console_write(console_output, cr, 2, &nout);
3440 else
3441 (void) usb_console_write(console_output, &c, 1, &nout);
3442 }
3443
3444 /*ARGSUSED*/
3445 static int
usbser_getchar(cons_polledio_arg_t arg)3446 usbser_getchar(cons_polledio_arg_t arg)
3447 {
3448 while (!usbser_ischar(arg))
3449 ;
3450
3451 return (*console_input_start++);
3452 }
3453
3454 /*ARGSUSED*/
3455 static boolean_t
usbser_ischar(cons_polledio_arg_t arg)3456 usbser_ischar(cons_polledio_arg_t arg)
3457 {
3458 uint_t num_bytes;
3459
3460 if (console_input_start < console_input_end)
3461 return (B_TRUE);
3462
3463 if (usb_console_read(console_input, &num_bytes) != USB_SUCCESS)
3464 return (B_FALSE);
3465
3466 console_input_start = console_input_buf;
3467 console_input_end = console_input_buf + num_bytes;
3468
3469 return (num_bytes != 0);
3470 }
3471