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, 0) != 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, 0) != 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 int rval;
1869
1870 ASSERT(mutex_owned(&pp->port_mutex));
1871 ASSERT((thr->thr_flags & USBSER_THR_RUNNING) == 0);
1872
1873 thr->thr_flags = USBSER_THR_RUNNING;
1874
1875 rval = ddi_taskq_dispatch(usp->us_taskq, thr->thr_func, thr->thr_arg,
1876 DDI_SLEEP);
1877 ASSERT(rval == DDI_SUCCESS);
1878 }
1879
1880
1881 /*
1882 * cancel a thread
1883 */
1884 static void
usbser_thr_cancel(usbser_thread_t * thr)1885 usbser_thr_cancel(usbser_thread_t *thr)
1886 {
1887 usbser_port_t *pp = thr->thr_port;
1888
1889 ASSERT(mutex_owned(&pp->port_mutex));
1890
1891 thr->thr_flags &= ~USBSER_THR_RUNNING;
1892 cv_signal(&thr->thr_cv);
1893
1894 /* wait until the thread actually exits */
1895 do {
1896 cv_wait(&thr->thr_cv, &pp->port_mutex);
1897
1898 } while ((thr->thr_flags & USBSER_THR_EXITED) == 0);
1899 }
1900
1901
1902 /*
1903 * wake thread
1904 */
1905 static void
usbser_thr_wake(usbser_thread_t * thr)1906 usbser_thr_wake(usbser_thread_t *thr)
1907 {
1908 ASSERT(mutex_owned(&thr->thr_port->port_mutex));
1909
1910 thr->thr_flags |= USBSER_THR_WAKE;
1911 cv_signal(&thr->thr_cv);
1912 }
1913
1914
1915 /*
1916 * thread handling write queue requests
1917 */
1918 static void
usbser_wq_thread(void * arg)1919 usbser_wq_thread(void *arg)
1920 {
1921 usbser_thread_t *thr = (usbser_thread_t *)arg;
1922 usbser_port_t *pp = thr->thr_port;
1923
1924 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wq_thread: enter");
1925
1926 mutex_enter(&pp->port_mutex);
1927 while (thr->thr_flags & USBSER_THR_RUNNING) {
1928 /*
1929 * when woken, see what we should do
1930 */
1931 if (thr->thr_flags & USBSER_THR_WAKE) {
1932 thr->thr_flags &= ~USBSER_THR_WAKE;
1933
1934 /*
1935 * status callback pending?
1936 */
1937 if (pp->port_flags & USBSER_FL_STATUS_CB) {
1938 usbser_status_proc_cb(pp);
1939 }
1940
1941 usbser_wmsg(pp);
1942 } else {
1943 /*
1944 * sleep until woken up to do some work, e.g:
1945 * - new message arrives;
1946 * - data transmit completes;
1947 * - status callback pending;
1948 * - wq thread is cancelled;
1949 */
1950 cv_wait(&thr->thr_cv, &pp->port_mutex);
1951 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
1952 "usbser_wq_thread: wakeup");
1953 }
1954 }
1955 thr->thr_flags |= USBSER_THR_EXITED;
1956 cv_signal(&thr->thr_cv);
1957 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wq_thread: exit");
1958 mutex_exit(&pp->port_mutex);
1959 }
1960
1961
1962 /*
1963 * thread handling read queue requests
1964 */
1965 static void
usbser_rq_thread(void * arg)1966 usbser_rq_thread(void *arg)
1967 {
1968 usbser_thread_t *thr = (usbser_thread_t *)arg;
1969 usbser_port_t *pp = thr->thr_port;
1970
1971 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_rq_thread: enter");
1972
1973 mutex_enter(&pp->port_mutex);
1974 while (thr->thr_flags & USBSER_THR_RUNNING) {
1975 /*
1976 * read service routine will wake us when
1977 * more space is available on the read queue
1978 */
1979 if (thr->thr_flags & USBSER_THR_WAKE) {
1980 thr->thr_flags &= ~USBSER_THR_WAKE;
1981
1982 /*
1983 * don't process messages until queue is enabled
1984 */
1985 if (!pp->port_ttycommon.t_readq) {
1986
1987 continue;
1988 }
1989
1990 /*
1991 * check whether we need to resume receive
1992 */
1993 if (pp->port_flags & USBSER_FL_RX_STOPPED) {
1994 pp->port_flowc = pp->port_ttycommon.t_startc;
1995 usbser_inbound_flow_ctl(pp);
1996 }
1997
1998 /*
1999 * grab more data if available
2000 */
2001 mutex_exit(&pp->port_mutex);
2002 usbser_rx_cb((caddr_t)pp);
2003 mutex_enter(&pp->port_mutex);
2004 } else {
2005 cv_wait(&thr->thr_cv, &pp->port_mutex);
2006 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
2007 "usbser_rq_thread: wakeup");
2008 }
2009 }
2010 thr->thr_flags |= USBSER_THR_EXITED;
2011 cv_signal(&thr->thr_cv);
2012 USB_DPRINTF_L4(DPRINT_RQ, pp->port_lh, "usbser_rq_thread: exit");
2013 mutex_exit(&pp->port_mutex);
2014 }
2015
2016
2017 /*
2018 * DSD callbacks
2019 * -------------
2020 *
2021 * Note: to avoid deadlocks with DSD, these callbacks
2022 * should not call DSD functions that can block.
2023 *
2024 *
2025 * transmit callback
2026 *
2027 * invoked by DSD when the last byte of data is transmitted over USB
2028 */
2029 static void
usbser_tx_cb(caddr_t arg)2030 usbser_tx_cb(caddr_t arg)
2031 {
2032 usbser_port_t *pp = (usbser_port_t *)arg;
2033 int online;
2034
2035 online = usbser_dev_is_online(pp->port_usp);
2036
2037 mutex_enter(&pp->port_mutex);
2038 USB_DPRINTF_L4(DPRINT_TX_CB, pp->port_lh,
2039 "usbser_tx_cb: act=%x curthread=%p", pp->port_act,
2040 (void *)curthread);
2041
2042 usbser_release_port_act(pp, USBSER_ACT_TX);
2043
2044 /*
2045 * as long as port access is ok and the port is not busy on
2046 * TX, break, ctrl or delay, the wq_thread should be waken
2047 * to do further process for next message
2048 */
2049 if (online && USBSER_PORT_ACCESS_OK(pp) &&
2050 !USBSER_PORT_IS_BUSY_NON_RX(pp)) {
2051 /*
2052 * wake wq thread for further data/ioctl processing
2053 */
2054 usbser_thr_wake(&pp->port_wq_thread);
2055 }
2056 mutex_exit(&pp->port_mutex);
2057 }
2058
2059
2060 /*
2061 * receive callback
2062 *
2063 * invoked by DSD when there is more data for us to pick
2064 */
2065 static void
usbser_rx_cb(caddr_t arg)2066 usbser_rx_cb(caddr_t arg)
2067 {
2068 usbser_port_t *pp = (usbser_port_t *)arg;
2069 queue_t *rq, *wq;
2070 mblk_t *mp; /* current mblk */
2071 mblk_t *data, *data_tail; /* M_DATA mblk list and its tail */
2072 mblk_t *emp; /* error (M_BREAK) mblk */
2073
2074 USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh, "usbser_rx_cb");
2075
2076 if (!usbser_dev_is_online(pp->port_usp)) {
2077
2078 return;
2079 }
2080
2081 /* get data from DSD */
2082 if ((mp = USBSER_DS_RX(pp)) == NULL) {
2083
2084 return;
2085 }
2086
2087 mutex_enter(&pp->port_mutex);
2088 if ((!USBSER_PORT_ACCESS_OK(pp)) ||
2089 ((pp->port_ttycommon.t_cflag & CREAD) == 0)) {
2090 freemsg(mp);
2091 mutex_exit(&pp->port_mutex);
2092 USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
2093 "usbser_rx_cb: access not ok or receiver disabled");
2094
2095 return;
2096 }
2097
2098 usbser_serialize_port_act(pp, USBSER_ACT_RX);
2099
2100 rq = pp->port_ttycommon.t_readq;
2101 wq = pp->port_ttycommon.t_writeq;
2102 mutex_exit(&pp->port_mutex);
2103
2104 /*
2105 * DSD data is a b_cont-linked list of M_DATA and M_BREAK blocks.
2106 * M_DATA is correctly received data.
2107 * M_BREAK is a character with either framing or parity error.
2108 *
2109 * this loop runs through the list of mblks. when it meets an M_BREAK,
2110 * it sends all leading M_DATA's in one shot, then sends M_BREAK.
2111 * in the trivial case when list contains only M_DATA's, the loop
2112 * does nothing but set data variable.
2113 */
2114 data = data_tail = NULL;
2115 while (mp) {
2116 /*
2117 * skip data until we meet M_BREAK or end of list
2118 */
2119 if (DB_TYPE(mp) == M_DATA) {
2120 if (data == NULL) {
2121 data = mp;
2122 }
2123 data_tail = mp;
2124 mp = mp->b_cont;
2125
2126 continue;
2127 }
2128
2129 /* detach data list from mp */
2130 if (data_tail) {
2131 data_tail->b_cont = NULL;
2132 }
2133 /* detach emp from the list */
2134 emp = mp;
2135 mp = mp->b_cont;
2136 emp->b_cont = NULL;
2137
2138 /* DSD shouldn't send anything but M_DATA or M_BREAK */
2139 if ((DB_TYPE(emp) != M_BREAK) || (MBLKL(emp) != 2)) {
2140 freemsg(emp);
2141 USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
2142 "usbser_rx_cb: bad message");
2143
2144 continue;
2145 }
2146
2147 /*
2148 * first tweak and send M_DATA's
2149 */
2150 if (data) {
2151 usbser_rx_massage_data(pp, data);
2152 usbser_rx_cb_put(pp, rq, wq, data);
2153 data = data_tail = NULL;
2154 }
2155
2156 /*
2157 * now tweak and send M_BREAK
2158 */
2159 mutex_enter(&pp->port_mutex);
2160 usbser_rx_massage_mbreak(pp, emp);
2161 mutex_exit(&pp->port_mutex);
2162 usbser_rx_cb_put(pp, rq, wq, emp);
2163 }
2164
2165 /* send the rest of the data, if any */
2166 if (data) {
2167 usbser_rx_massage_data(pp, data);
2168 usbser_rx_cb_put(pp, rq, wq, data);
2169 }
2170
2171 mutex_enter(&pp->port_mutex);
2172 usbser_release_port_act(pp, USBSER_ACT_RX);
2173 mutex_exit(&pp->port_mutex);
2174 }
2175
2176 /*
2177 * the joys of termio -- this is to accomodate Unix98 assertion:
2178 *
2179 * If PARENB is supported and is set, when PARMRK is set, and CSIZE is
2180 * set to CS8, and IGNPAR is clear, and ISTRIP is clear, a valid
2181 * character of '\377' is read as '\377', '\377'.
2182 *
2183 * Posix Ref: Assertion 7.1.2.2-16(C)
2184 *
2185 * this requires the driver to scan every incoming valid character
2186 */
2187 static void
usbser_rx_massage_data(usbser_port_t * pp,mblk_t * mp)2188 usbser_rx_massage_data(usbser_port_t *pp, mblk_t *mp)
2189 {
2190 tty_common_t *tp = &pp->port_ttycommon;
2191 uchar_t *p;
2192 mblk_t *newmp;
2193 int tailsz;
2194
2195 /* avoid scanning if possible */
2196 mutex_enter(&pp->port_mutex);
2197 if (!((tp->t_cflag & PARENB) && (tp->t_iflag & PARMRK) &&
2198 ((tp->t_cflag & CSIZE) == CS8) &&
2199 ((tp->t_iflag & (IGNPAR|ISTRIP)) == 0))) {
2200 mutex_exit(&pp->port_mutex);
2201
2202 return;
2203 }
2204 mutex_exit(&pp->port_mutex);
2205
2206 while (mp) {
2207 for (p = mp->b_rptr; p < mp->b_wptr; ) {
2208 if (*p++ != 0377) {
2209
2210 continue;
2211 }
2212 USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
2213 "usbser_rx_massage_data: mp=%p off=%ld(%ld)",
2214 (void *)mp, _PTRDIFF(p, mp->b_rptr) - 1,
2215 (long)MBLKL(mp));
2216
2217 /*
2218 * insert another 0377 after this one. all data after
2219 * the original 0377 have to be copied to the new mblk
2220 */
2221 tailsz = _PTRDIFF(mp->b_wptr, p);
2222 if ((newmp = allocb(tailsz + 1, BPRI_HI)) == NULL) {
2223 USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
2224 "usbser_rx_massage_data: allocb failed");
2225
2226 continue;
2227 }
2228
2229 /* fill in the new mblk */
2230 *newmp->b_wptr++ = 0377;
2231 if (tailsz > 0) {
2232 bcopy(p, newmp->b_wptr, tailsz);
2233 newmp->b_wptr += tailsz;
2234 }
2235 /* shrink the original mblk */
2236 mp->b_wptr = p;
2237
2238 newmp->b_cont = mp->b_cont;
2239 mp->b_cont = newmp;
2240 p = newmp->b_rptr + 1;
2241 mp = newmp;
2242 }
2243 mp = mp->b_cont;
2244 }
2245 }
2246
2247 /*
2248 * more joys of termio
2249 */
2250 static void
usbser_rx_massage_mbreak(usbser_port_t * pp,mblk_t * mp)2251 usbser_rx_massage_mbreak(usbser_port_t *pp, mblk_t *mp)
2252 {
2253 tty_common_t *tp = &pp->port_ttycommon;
2254 uchar_t err, c;
2255
2256 err = *mp->b_rptr;
2257 c = *(mp->b_rptr + 1);
2258
2259 if ((err & (DS_FRAMING_ERR | DS_BREAK_ERR)) && (c == 0)) {
2260 /* break */
2261 mp->b_rptr += 2;
2262 } else if (!(tp->t_iflag & INPCK) && (err & (DS_PARITY_ERR))) {
2263 /* Posix Ref: Assertion 7.1.2.2-20(C) */
2264 mp->b_rptr++;
2265 DB_TYPE(mp) = M_DATA;
2266 } else {
2267 /* for ldterm to handle */
2268 mp->b_rptr++;
2269 }
2270
2271 USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
2272 "usbser_rx_massage_mbreak: type=%x len=%ld [0]=0%o",
2273 DB_TYPE(mp), (long)MBLKL(mp), (MBLKL(mp) > 0) ? *mp->b_rptr : 45);
2274 }
2275
2276
2277 /*
2278 * in rx callback, try to send an mblk upstream
2279 */
2280 static void
usbser_rx_cb_put(usbser_port_t * pp,queue_t * rq,queue_t * wq,mblk_t * mp)2281 usbser_rx_cb_put(usbser_port_t *pp, queue_t *rq, queue_t *wq, mblk_t *mp)
2282 {
2283 if (canputnext(rq)) {
2284 putnext(rq, mp);
2285 } else if (canput(rq) && putq(rq, mp)) {
2286 /*
2287 * full queue indicates the need for inbound flow control
2288 */
2289 (void) putctl(wq, M_STOPI);
2290 usbser_st_put_stopi++;
2291
2292 USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
2293 "usbser_rx_cb: cannot putnext, flow ctl");
2294 } else {
2295 freemsg(mp);
2296 usbser_st_rx_data_loss++;
2297 (void) putctl(wq, M_STOPI);
2298 usbser_st_put_stopi++;
2299
2300 USB_DPRINTF_L1(DPRINT_RX_CB, pp->port_lh,
2301 "input overrun");
2302 }
2303 }
2304
2305
2306 /*
2307 * modem status change callback
2308 *
2309 * each time external status lines are changed, DSD calls this routine
2310 */
2311 static void
usbser_status_cb(caddr_t arg)2312 usbser_status_cb(caddr_t arg)
2313 {
2314 usbser_port_t *pp = (usbser_port_t *)arg;
2315
2316 USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_cb");
2317
2318 if (!usbser_dev_is_online(pp->port_usp)) {
2319
2320 return;
2321 }
2322
2323 /*
2324 * actual processing will be done in usbser_status_proc_cb()
2325 * running in wq thread
2326 */
2327 mutex_enter(&pp->port_mutex);
2328 if (USBSER_PORT_ACCESS_OK(pp) || USBSER_IS_OPENING(pp)) {
2329 pp->port_flags |= USBSER_FL_STATUS_CB;
2330 usbser_thr_wake(&pp->port_wq_thread);
2331 }
2332 mutex_exit(&pp->port_mutex);
2333 }
2334
2335
2336 /*
2337 * modem status change
2338 */
2339 static void
usbser_status_proc_cb(usbser_port_t * pp)2340 usbser_status_proc_cb(usbser_port_t *pp)
2341 {
2342 tty_common_t *tp = &pp->port_ttycommon;
2343 queue_t *rq, *wq;
2344 int status;
2345 int drop_dtr = 0;
2346 int rq_msg = 0, wq_msg = 0;
2347
2348 USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_proc_cb");
2349
2350 pp->port_flags &= ~USBSER_FL_STATUS_CB;
2351
2352 mutex_exit(&pp->port_mutex);
2353 if (!usbser_dev_is_online(pp->port_usp)) {
2354 mutex_enter(&pp->port_mutex);
2355
2356 return;
2357 }
2358
2359 /* get modem status */
2360 if (USBSER_DS_GET_MODEM_CTL(pp, -1, &status) != USB_SUCCESS) {
2361 mutex_enter(&pp->port_mutex);
2362
2363 return;
2364 }
2365
2366 mutex_enter(&pp->port_mutex);
2367 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2368
2369 rq = pp->port_ttycommon.t_readq;
2370 wq = pp->port_ttycommon.t_writeq;
2371
2372 /*
2373 * outbound flow control
2374 */
2375 if (tp->t_cflag & CRTSCTS) {
2376 if (!(status & TIOCM_CTS)) {
2377 /*
2378 * CTS dropped, stop xmit
2379 */
2380 if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
2381 wq_msg = M_STOP;
2382 }
2383 } else if (pp->port_flags & USBSER_FL_TX_STOPPED) {
2384 /*
2385 * CTS raised, resume xmit
2386 */
2387 wq_msg = M_START;
2388 }
2389 }
2390
2391 /*
2392 * check carrier
2393 */
2394 if ((status & TIOCM_CD) || (tp->t_flags & TS_SOFTCAR)) {
2395 /*
2396 * carrier present
2397 */
2398 if ((pp->port_flags & USBSER_FL_CARR_ON) == 0) {
2399 pp->port_flags |= USBSER_FL_CARR_ON;
2400
2401 rq_msg = M_UNHANGUP;
2402 /*
2403 * wake open
2404 */
2405 if (pp->port_flags & USBSER_FL_WOPEN) {
2406 cv_broadcast(&pp->port_car_cv);
2407 }
2408
2409 USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2410 "usbser_status_cb: carr on");
2411 }
2412 } else if (pp->port_flags & USBSER_FL_CARR_ON) {
2413 pp->port_flags &= ~USBSER_FL_CARR_ON;
2414 /*
2415 * carrier went away: if not local line, drop DTR
2416 */
2417 if (!(tp->t_cflag & CLOCAL)) {
2418 drop_dtr = 1;
2419 rq_msg = M_HANGUP;
2420 }
2421 if ((pp->port_flags & USBSER_FL_TX_STOPPED) && (wq_msg == 0)) {
2422 wq_msg = M_START;
2423 }
2424
2425 USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2426 "usbser_status_cb: carr off");
2427 }
2428 mutex_exit(&pp->port_mutex);
2429
2430 USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2431 "usbser_status_cb: rq_msg=%d wq_msg=%d", rq_msg, wq_msg);
2432
2433 /*
2434 * commit postponed actions now
2435 * do so only if port is fully open (queues are enabled)
2436 */
2437 if (rq) {
2438 if (rq_msg) {
2439 (void) putnextctl(rq, rq_msg);
2440 }
2441 if (drop_dtr) {
2442 (void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR, 0);
2443 }
2444 if (wq_msg) {
2445 (void) putctl(wq, wq_msg);
2446 }
2447 }
2448
2449 mutex_enter(&pp->port_mutex);
2450 usbser_release_port_act(pp, USBSER_ACT_CTL);
2451 }
2452
2453
2454 /*
2455 * serial support
2456 * --------------
2457 *
2458 *
2459 * this routine is run by wq thread every time it's woken,
2460 * i.e. when the queue contains messages to process
2461 */
2462 static void
usbser_wmsg(usbser_port_t * pp)2463 usbser_wmsg(usbser_port_t *pp)
2464 {
2465 queue_t *q = pp->port_ttycommon.t_writeq;
2466 mblk_t *mp;
2467 int msgtype;
2468
2469 ASSERT(mutex_owned(&pp->port_mutex));
2470
2471 if (q == NULL) {
2472 USB_DPRINTF_L3(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=NULL");
2473
2474 return;
2475 }
2476 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=%p act=%x 0x%x",
2477 (void *)q, pp->port_act, q->q_first ? DB_TYPE(q->q_first) : 0xff);
2478
2479 while ((mp = getq(q)) != NULL) {
2480 msgtype = DB_TYPE(mp);
2481 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: "
2482 "type=%s (0x%x)", usbser_msgtype2str(msgtype), msgtype);
2483
2484 switch (msgtype) {
2485 /*
2486 * high-priority messages
2487 */
2488 case M_STOP:
2489 usbser_stop(pp, mp);
2490
2491 break;
2492 case M_START:
2493 usbser_start(pp, mp);
2494
2495 break;
2496 case M_STOPI:
2497 usbser_stopi(pp, mp);
2498
2499 break;
2500 case M_STARTI:
2501 usbser_starti(pp, mp);
2502
2503 break;
2504 case M_IOCDATA:
2505 usbser_iocdata(pp, mp);
2506
2507 break;
2508 case M_FLUSH:
2509 usbser_flush(pp, mp);
2510
2511 break;
2512 /*
2513 * normal-priority messages
2514 */
2515 case M_BREAK:
2516 usbser_break(pp, mp);
2517
2518 break;
2519 case M_DELAY:
2520 usbser_delay(pp, mp);
2521
2522 break;
2523 case M_DATA:
2524 if (usbser_data(pp, mp) != USB_SUCCESS) {
2525 (void) putbq(q, mp);
2526
2527 return;
2528 }
2529
2530 break;
2531 case M_IOCTL:
2532 if (usbser_ioctl(pp, mp) != USB_SUCCESS) {
2533 (void) putbq(q, mp);
2534
2535 return;
2536 }
2537
2538 break;
2539 default:
2540 freemsg(mp);
2541
2542 break;
2543 }
2544 }
2545 }
2546
2547
2548 /*
2549 * process M_DATA message
2550 */
2551 static int
usbser_data(usbser_port_t * pp,mblk_t * mp)2552 usbser_data(usbser_port_t *pp, mblk_t *mp)
2553 {
2554 /* put off until current transfer ends or delay is over */
2555 if ((pp->port_act & USBSER_ACT_TX) ||
2556 (pp->port_act & USBSER_ACT_DELAY)) {
2557
2558 return (USB_FAILURE);
2559 }
2560 if (MBLKL(mp) <= 0) {
2561 freemsg(mp);
2562
2563 return (USB_SUCCESS);
2564 }
2565
2566 pp->port_act |= USBSER_ACT_TX;
2567 pp->port_wq_data_cnt -= msgdsize(mp);
2568
2569 mutex_exit(&pp->port_mutex);
2570 /* DSD is required to accept data block in any case */
2571 (void) USBSER_DS_TX(pp, mp);
2572 mutex_enter(&pp->port_mutex);
2573
2574 return (USB_SUCCESS);
2575 }
2576
2577
2578 /*
2579 * process an M_IOCTL message
2580 */
2581 static int
usbser_ioctl(usbser_port_t * pp,mblk_t * mp)2582 usbser_ioctl(usbser_port_t *pp, mblk_t *mp)
2583 {
2584 tty_common_t *tp = &pp->port_ttycommon;
2585 queue_t *q = tp->t_writeq;
2586 struct iocblk *iocp;
2587 int cmd;
2588 mblk_t *datamp;
2589 int error = 0, rval = USB_SUCCESS;
2590 int val;
2591
2592 ASSERT(mutex_owned(&pp->port_mutex));
2593 ASSERT(DB_TYPE(mp) == M_IOCTL);
2594
2595 iocp = (struct iocblk *)mp->b_rptr;
2596 cmd = iocp->ioc_cmd;
2597
2598 USB_DPRINTF_L4(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
2599 "mp=%p %s (0x%x)", (void *)mp, usbser_ioctl2str(cmd), cmd);
2600
2601 if (tp->t_iocpending != NULL) {
2602 /*
2603 * We were holding an ioctl response pending the
2604 * availability of an mblk to hold data to be passed up;
2605 * another ioctl came through, which means that ioctl
2606 * must have timed out or been aborted.
2607 */
2608 freemsg(tp->t_iocpending);
2609 tp->t_iocpending = NULL;
2610 }
2611
2612 switch (cmd) {
2613 case TIOCMGET:
2614 case TIOCMBIC:
2615 case TIOCMBIS:
2616 case TIOCMSET:
2617 case CONSOPENPOLLEDIO:
2618 case CONSCLOSEPOLLEDIO:
2619 case CONSSETABORTENABLE:
2620 case CONSGETABORTENABLE:
2621 /*
2622 * For the above ioctls do not call ttycommon_ioctl() because
2623 * this function frees up the message block (mp->b_cont) that
2624 * contains the address of the user variable where we need to
2625 * pass back the bit array.
2626 */
2627 error = -1;
2628 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2629 mutex_exit(&pp->port_mutex);
2630 break;
2631
2632 case TCSBRK:
2633 /* serialize breaks */
2634 if (pp->port_act & USBSER_ACT_BREAK)
2635 return (USB_FAILURE);
2636 /*FALLTHRU*/
2637 default:
2638 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2639 mutex_exit(&pp->port_mutex);
2640 (void) ttycommon_ioctl(tp, q, mp, &error);
2641 break;
2642 }
2643
2644 if (error == 0) {
2645 /*
2646 * ttycommon_ioctl() did most of the work
2647 * we just use the data it set up
2648 */
2649 switch (cmd) {
2650 case TCSETSF:
2651 case TCSETSW:
2652 case TCSETA:
2653 case TCSETAW:
2654 case TCSETAF:
2655 (void) USBSER_DS_FIFO_DRAIN(pp, DS_TX);
2656 /*FALLTHRU*/
2657
2658 case TCSETS:
2659 mutex_enter(&pp->port_mutex);
2660 error = usbser_port_program(pp);
2661 mutex_exit(&pp->port_mutex);
2662 break;
2663 }
2664 goto end;
2665
2666 } else if (error > 0) {
2667 USB_DPRINTF_L3(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
2668 "ttycommon_ioctl returned %d", error);
2669 goto end;
2670 }
2671
2672 /*
2673 * error < 0: ttycommon_ioctl() didn't do anything, we process it here
2674 */
2675 error = 0;
2676 switch (cmd) {
2677 case TCSBRK:
2678 if ((error = miocpullup(mp, sizeof (int))) != 0)
2679 break;
2680
2681 /* drain output */
2682 (void) USBSER_DS_FIFO_DRAIN(pp, USBSER_TX_FIFO_DRAIN_TIMEOUT);
2683
2684 /*
2685 * if required, set break
2686 */
2687 if (*(int *)mp->b_cont->b_rptr == 0) {
2688 if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS) {
2689 error = EIO;
2690 break;
2691 }
2692
2693 mutex_enter(&pp->port_mutex);
2694 pp->port_act |= USBSER_ACT_BREAK;
2695 pp->port_delay_id = timeout(usbser_restart, pp,
2696 drv_usectohz(250000));
2697 mutex_exit(&pp->port_mutex);
2698 }
2699 mioc2ack(mp, NULL, 0, 0);
2700 break;
2701
2702 case TIOCSBRK: /* set break */
2703 if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS)
2704 error = EIO;
2705 else
2706 mioc2ack(mp, NULL, 0, 0);
2707 break;
2708
2709 case TIOCCBRK: /* clear break */
2710 if (USBSER_DS_BREAK_CTL(pp, DS_OFF) != USB_SUCCESS)
2711 error = EIO;
2712 else
2713 mioc2ack(mp, NULL, 0, 0);
2714 break;
2715
2716 case TIOCMSET: /* set all modem bits */
2717 case TIOCMBIS: /* bis modem bits */
2718 case TIOCMBIC: /* bic modem bits */
2719 if (iocp->ioc_count == TRANSPARENT) {
2720 mcopyin(mp, NULL, sizeof (int), NULL);
2721 break;
2722 }
2723 if ((error = miocpullup(mp, sizeof (int))) != 0)
2724 break;
2725
2726 val = *(int *)mp->b_cont->b_rptr;
2727 if (cmd == TIOCMSET) {
2728 rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
2729 } else if (cmd == TIOCMBIS) {
2730 rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
2731 } else if (cmd == TIOCMBIC) {
2732 rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
2733 }
2734 if (rval == USB_SUCCESS)
2735 mioc2ack(mp, NULL, 0, 0);
2736 else
2737 error = EIO;
2738 break;
2739
2740 case TIOCSILOOP:
2741 if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
2742 if (USBSER_DS_LOOPBACK(pp, DS_ON) == USB_SUCCESS)
2743 mioc2ack(mp, NULL, 0, 0);
2744 else
2745 error = EIO;
2746 } else {
2747 error = EINVAL;
2748 }
2749 break;
2750
2751 case TIOCCILOOP:
2752 if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
2753 if (USBSER_DS_LOOPBACK(pp, DS_OFF) == USB_SUCCESS)
2754 mioc2ack(mp, NULL, 0, 0);
2755 else
2756 error = EIO;
2757 } else {
2758 error = EINVAL;
2759 }
2760 break;
2761
2762 case TIOCMGET: /* get all modem bits */
2763 if ((datamp = allocb(sizeof (int), BPRI_MED)) == NULL) {
2764 error = EAGAIN;
2765 break;
2766 }
2767 rval = USBSER_DS_GET_MODEM_CTL(pp, -1, (int *)datamp->b_rptr);
2768 if (rval != USB_SUCCESS) {
2769 error = EIO;
2770 break;
2771 }
2772 if (iocp->ioc_count == TRANSPARENT)
2773 mcopyout(mp, NULL, sizeof (int), NULL, datamp);
2774 else
2775 mioc2ack(mp, datamp, sizeof (int), 0);
2776 break;
2777
2778 case CONSOPENPOLLEDIO:
2779 error = usbser_polledio_init(pp);
2780 if (error != 0)
2781 break;
2782
2783 error = miocpullup(mp, sizeof (struct cons_polledio *));
2784 if (error != 0)
2785 break;
2786
2787 *(struct cons_polledio **)mp->b_cont->b_rptr = &usbser_polledio;
2788
2789 mp->b_datap->db_type = M_IOCACK;
2790 break;
2791
2792 case CONSCLOSEPOLLEDIO:
2793 usbser_polledio_fini(pp);
2794 mp->b_datap->db_type = M_IOCACK;
2795 iocp->ioc_error = 0;
2796 iocp->ioc_rval = 0;
2797 break;
2798
2799 case CONSSETABORTENABLE:
2800 error = secpolicy_console(iocp->ioc_cr);
2801 if (error != 0)
2802 break;
2803
2804 if (iocp->ioc_count != TRANSPARENT) {
2805 error = EINVAL;
2806 break;
2807 }
2808
2809 /*
2810 * To do: implement console abort support
2811 * This involves adding a console flag to usbser
2812 * state structure. If flag is set, parse input stream
2813 * for abort sequence (see asy for example).
2814 *
2815 * For now, run mdb -K to get kmdb prompt.
2816 */
2817 if (*(intptr_t *)mp->b_cont->b_rptr)
2818 usbser_console_abort = 1;
2819 else
2820 usbser_console_abort = 0;
2821
2822 mp->b_datap->db_type = M_IOCACK;
2823 iocp->ioc_error = 0;
2824 iocp->ioc_rval = 0;
2825 break;
2826
2827 case CONSGETABORTENABLE:
2828 /*CONSTANTCONDITION*/
2829 ASSERT(sizeof (boolean_t) <= sizeof (boolean_t *));
2830 /*
2831 * Store the return value right in the payload
2832 * we were passed. Crude.
2833 */
2834 mcopyout(mp, NULL, sizeof (boolean_t), NULL, NULL);
2835 *(boolean_t *)mp->b_cont->b_rptr = (usbser_console_abort != 0);
2836 break;
2837
2838 default:
2839 error = EINVAL;
2840 break;
2841 }
2842 end:
2843 if (error != 0)
2844 miocnak(q, mp, 0, error);
2845 else
2846 qreply(q, mp);
2847
2848 mutex_enter(&pp->port_mutex);
2849 usbser_release_port_act(pp, USBSER_ACT_CTL);
2850
2851 return (USB_SUCCESS);
2852 }
2853
2854
2855 /*
2856 * process M_IOCDATA message
2857 */
2858 static void
usbser_iocdata(usbser_port_t * pp,mblk_t * mp)2859 usbser_iocdata(usbser_port_t *pp, mblk_t *mp)
2860 {
2861 tty_common_t *tp = &pp->port_ttycommon;
2862 queue_t *q = tp->t_writeq;
2863 struct copyresp *csp;
2864 int cmd;
2865 int val;
2866 int rval = USB_FAILURE;
2867
2868 ASSERT(mutex_owned(&pp->port_mutex));
2869
2870 csp = (struct copyresp *)mp->b_rptr;
2871 cmd = csp->cp_cmd;
2872
2873 if (csp->cp_rval != 0) {
2874 freemsg(mp);
2875 return;
2876 }
2877
2878 switch (cmd) {
2879 case TIOCMSET: /* set all modem bits */
2880 case TIOCMBIS: /* bis modem bits */
2881 case TIOCMBIC: /* bic modem bits */
2882 if ((mp->b_cont == NULL) ||
2883 (MBLKL(mp->b_cont) < sizeof (int))) {
2884 miocnak(q, mp, 0, EINVAL);
2885 break;
2886 }
2887 val = *(int *)mp->b_cont->b_rptr;
2888
2889 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2890 mutex_exit(&pp->port_mutex);
2891
2892 if (cmd == TIOCMSET) {
2893 rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
2894 } else if (cmd == TIOCMBIS) {
2895 rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
2896 } else if (cmd == TIOCMBIC) {
2897 rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
2898 }
2899
2900 if (mp->b_cont) {
2901 freemsg(mp->b_cont);
2902 mp->b_cont = NULL;
2903 }
2904
2905 if (rval == USB_SUCCESS)
2906 miocack(q, mp, 0, 0);
2907 else
2908 miocnak(q, mp, 0, EIO);
2909
2910 mutex_enter(&pp->port_mutex);
2911 usbser_release_port_act(pp, USBSER_ACT_CTL);
2912 break;
2913
2914 case TIOCMGET: /* get all modem bits */
2915 mutex_exit(&pp->port_mutex);
2916 miocack(q, mp, 0, 0);
2917 mutex_enter(&pp->port_mutex);
2918 break;
2919
2920 default:
2921 mutex_exit(&pp->port_mutex);
2922 miocnak(q, mp, 0, EINVAL);
2923 mutex_enter(&pp->port_mutex);
2924 break;
2925 }
2926 }
2927
2928
2929 /*
2930 * handle M_START[I]/M_STOP[I] messages
2931 */
2932 static void
usbser_stop(usbser_port_t * pp,mblk_t * mp)2933 usbser_stop(usbser_port_t *pp, mblk_t *mp)
2934 {
2935 usbser_st_mstop++;
2936 if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
2937 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2938 pp->port_flags |= USBSER_FL_TX_STOPPED;
2939
2940 mutex_exit(&pp->port_mutex);
2941 USBSER_DS_STOP(pp, DS_TX);
2942 mutex_enter(&pp->port_mutex);
2943
2944 usbser_release_port_act(pp, USBSER_ACT_TX);
2945 usbser_release_port_act(pp, USBSER_ACT_CTL);
2946 }
2947 freemsg(mp);
2948 }
2949
2950
2951 static void
usbser_start(usbser_port_t * pp,mblk_t * mp)2952 usbser_start(usbser_port_t *pp, mblk_t *mp)
2953 {
2954 usbser_st_mstart++;
2955 if (pp->port_flags & USBSER_FL_TX_STOPPED) {
2956 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2957 pp->port_flags &= ~USBSER_FL_TX_STOPPED;
2958
2959 mutex_exit(&pp->port_mutex);
2960 USBSER_DS_START(pp, DS_TX);
2961 mutex_enter(&pp->port_mutex);
2962 usbser_release_port_act(pp, USBSER_ACT_CTL);
2963 }
2964 freemsg(mp);
2965 }
2966
2967
2968 static void
usbser_stopi(usbser_port_t * pp,mblk_t * mp)2969 usbser_stopi(usbser_port_t *pp, mblk_t *mp)
2970 {
2971 usbser_st_mstopi++;
2972 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2973 pp->port_flowc = pp->port_ttycommon.t_stopc;
2974 usbser_inbound_flow_ctl(pp);
2975 usbser_release_port_act(pp, USBSER_ACT_CTL);
2976 freemsg(mp);
2977 }
2978
2979 static void
usbser_starti(usbser_port_t * pp,mblk_t * mp)2980 usbser_starti(usbser_port_t *pp, mblk_t *mp)
2981 {
2982 usbser_st_mstarti++;
2983 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2984 pp->port_flowc = pp->port_ttycommon.t_startc;
2985 usbser_inbound_flow_ctl(pp);
2986 usbser_release_port_act(pp, USBSER_ACT_CTL);
2987 freemsg(mp);
2988 }
2989
2990 /*
2991 * process M_FLUSH message
2992 */
2993 static void
usbser_flush(usbser_port_t * pp,mblk_t * mp)2994 usbser_flush(usbser_port_t *pp, mblk_t *mp)
2995 {
2996 queue_t *q = pp->port_ttycommon.t_writeq;
2997
2998 if (*mp->b_rptr & FLUSHW) {
2999 mutex_exit(&pp->port_mutex);
3000 (void) USBSER_DS_FIFO_FLUSH(pp, DS_TX); /* flush FIFO buffers */
3001 flushq(q, FLUSHDATA); /* flush write queue */
3002 mutex_enter(&pp->port_mutex);
3003
3004 usbser_release_port_act(pp, USBSER_ACT_TX);
3005
3006 *mp->b_rptr &= ~FLUSHW;
3007 }
3008 if (*mp->b_rptr & FLUSHR) {
3009 /*
3010 * flush FIFO buffers
3011 */
3012 mutex_exit(&pp->port_mutex);
3013 (void) USBSER_DS_FIFO_FLUSH(pp, DS_RX);
3014 flushq(RD(q), FLUSHDATA);
3015 qreply(q, mp);
3016 mutex_enter(&pp->port_mutex);
3017 } else {
3018 freemsg(mp);
3019 }
3020 }
3021
3022 /*
3023 * process M_BREAK message
3024 */
3025 static void
usbser_break(usbser_port_t * pp,mblk_t * mp)3026 usbser_break(usbser_port_t *pp, mblk_t *mp)
3027 {
3028 int rval;
3029
3030 /*
3031 * set the break and arrange for usbser_restart() to be called in 1/4 s
3032 */
3033 mutex_exit(&pp->port_mutex);
3034 rval = USBSER_DS_BREAK_CTL(pp, DS_ON);
3035 mutex_enter(&pp->port_mutex);
3036
3037 if (rval == USB_SUCCESS) {
3038 pp->port_act |= USBSER_ACT_BREAK;
3039 pp->port_delay_id = timeout(usbser_restart, pp,
3040 drv_usectohz(250000));
3041 }
3042 freemsg(mp);
3043 }
3044
3045
3046 /*
3047 * process M_DELAY message
3048 */
3049 static void
usbser_delay(usbser_port_t * pp,mblk_t * mp)3050 usbser_delay(usbser_port_t *pp, mblk_t *mp)
3051 {
3052 /*
3053 * arrange for usbser_restart() to be called when the delay expires
3054 */
3055 pp->port_act |= USBSER_ACT_DELAY;
3056 pp->port_delay_id = timeout(usbser_restart, pp,
3057 (clock_t)(*(uchar_t *)mp->b_rptr + 6));
3058 freemsg(mp);
3059 }
3060
3061
3062 /*
3063 * restart output on a line after a delay or break timer expired
3064 */
3065 static void
usbser_restart(void * arg)3066 usbser_restart(void *arg)
3067 {
3068 usbser_port_t *pp = (usbser_port_t *)arg;
3069
3070 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_restart");
3071
3072 mutex_enter(&pp->port_mutex);
3073 /* if cancelled, return immediately */
3074 if (pp->port_delay_id == 0) {
3075 mutex_exit(&pp->port_mutex);
3076
3077 return;
3078 }
3079 pp->port_delay_id = 0;
3080
3081 /* clear break if necessary */
3082 if (pp->port_act & USBSER_ACT_BREAK) {
3083 mutex_exit(&pp->port_mutex);
3084 (void) USBSER_DS_BREAK_CTL(pp, DS_OFF);
3085 mutex_enter(&pp->port_mutex);
3086 }
3087
3088 usbser_release_port_act(pp, USBSER_ACT_BREAK | USBSER_ACT_DELAY);
3089
3090 /* wake wq thread to resume message processing */
3091 usbser_thr_wake(&pp->port_wq_thread);
3092 mutex_exit(&pp->port_mutex);
3093 }
3094
3095
3096 /*
3097 * program port hardware with the chosen parameters
3098 * most of the operation is based on the values of 'c_iflag' and 'c_cflag'
3099 */
3100 static int
usbser_port_program(usbser_port_t * pp)3101 usbser_port_program(usbser_port_t *pp)
3102 {
3103 tty_common_t *tp = &pp->port_ttycommon;
3104 int baudrate;
3105 int c_flag;
3106 ds_port_param_entry_t pe[6];
3107 ds_port_params_t params;
3108 int flow_ctl, ctl_val;
3109 int err = 0;
3110
3111 baudrate = tp->t_cflag & CBAUD;
3112 if (tp->t_cflag & CBAUDEXT) {
3113 baudrate += 16;
3114 }
3115
3116 /*
3117 * set input speed same as output, as split speed not supported
3118 */
3119 if (tp->t_cflag & (CIBAUD|CIBAUDEXT)) {
3120 tp->t_cflag &= ~(CIBAUD);
3121 if (baudrate > CBAUD) {
3122 tp->t_cflag |= CIBAUDEXT;
3123 tp->t_cflag |=
3124 (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD);
3125 } else {
3126 tp->t_cflag &= ~CIBAUDEXT;
3127 tp->t_cflag |= ((baudrate << IBSHIFT) & CIBAUD);
3128 }
3129 }
3130
3131 c_flag = tp->t_cflag;
3132
3133 /*
3134 * flow control
3135 */
3136 flow_ctl = tp->t_iflag & (IXON | IXANY | IXOFF);
3137 if (c_flag & CRTSCTS) {
3138 flow_ctl |= CTSXON;
3139 }
3140 if (c_flag & CRTSXOFF) {
3141 flow_ctl |= RTSXOFF;
3142 }
3143
3144 /*
3145 * fill in port parameters we need to set:
3146 *
3147 * baud rate
3148 */
3149 pe[0].param = DS_PARAM_BAUD;
3150 pe[0].val.ui = baudrate;
3151
3152 /* stop bits */
3153 pe[1].param = DS_PARAM_STOPB;
3154 pe[1].val.ui = c_flag & CSTOPB;
3155
3156 /* parity */
3157 pe[2].param = DS_PARAM_PARITY;
3158 pe[2].val.ui = c_flag & (PARENB | PARODD);
3159
3160 /* char size */
3161 pe[3].param = DS_PARAM_CHARSZ;
3162 pe[3].val.ui = c_flag & CSIZE;
3163
3164 /* start & stop chars */
3165 pe[4].param = DS_PARAM_XON_XOFF;
3166 pe[4].val.uc[0] = tp->t_startc;
3167 pe[4].val.uc[1] = tp->t_stopc;
3168
3169 /* flow control */
3170 pe[5].param = DS_PARAM_FLOW_CTL;
3171 pe[5].val.ui = flow_ctl;
3172
3173 params.tp_entries = &pe[0];
3174 params.tp_cnt = 6;
3175
3176 /* control signals */
3177 ctl_val = TIOCM_DTR | TIOCM_RTS;
3178 if (baudrate == 0) {
3179 ctl_val &= ~TIOCM_DTR; /* zero baudrate means drop DTR */
3180 }
3181 if (pp->port_flags & USBSER_FL_RX_STOPPED) {
3182 ctl_val &= ~TIOCM_RTS;
3183 }
3184
3185 /* submit */
3186 mutex_exit(&pp->port_mutex);
3187 err = USBSER_DS_SET_PORT_PARAMS(pp, ¶ms);
3188 if (err != USB_SUCCESS) {
3189 mutex_enter(&pp->port_mutex);
3190
3191 return (EINVAL);
3192 }
3193
3194 err = USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR | TIOCM_RTS, ctl_val);
3195 mutex_enter(&pp->port_mutex);
3196
3197 return ((err == USB_SUCCESS) ? 0 : EIO);
3198 }
3199
3200
3201 /*
3202 * check if any inbound flow control action needed
3203 */
3204 static void
usbser_inbound_flow_ctl(usbser_port_t * pp)3205 usbser_inbound_flow_ctl(usbser_port_t *pp)
3206 {
3207 tcflag_t need_hw;
3208 int rts;
3209 char c = pp->port_flowc;
3210 mblk_t *mp = NULL;
3211
3212 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
3213 "usbser_inbound_flow_ctl: c=%x cflag=%x port_flags=%x",
3214 c, pp->port_ttycommon.t_cflag, pp->port_flags);
3215
3216 if (c == '\0') {
3217
3218 return;
3219 }
3220 pp->port_flowc = '\0';
3221
3222 /*
3223 * if inbound hardware flow control enabled, we need to frob RTS
3224 */
3225 need_hw = (pp->port_ttycommon.t_cflag & CRTSXOFF);
3226 if (c == pp->port_ttycommon.t_startc) {
3227 rts = TIOCM_RTS;
3228 pp->port_flags &= ~USBSER_FL_RX_STOPPED;
3229 } else {
3230 rts = 0;
3231 pp->port_flags |= USBSER_FL_RX_STOPPED;
3232 }
3233
3234 /*
3235 * if character flow control active, transmit a start or stop char,
3236 */
3237 if (pp->port_ttycommon.t_iflag & IXOFF) {
3238 if ((mp = allocb(1, BPRI_LO)) == NULL) {
3239 USB_DPRINTF_L2(DPRINT_WQ, pp->port_lh,
3240 "usbser_inbound_flow_ctl: allocb failed");
3241 } else {
3242 *mp->b_wptr++ = c;
3243 pp->port_flags |= USBSER_ACT_TX;
3244 }
3245 }
3246
3247 mutex_exit(&pp->port_mutex);
3248 if (need_hw) {
3249 (void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_RTS, rts);
3250 }
3251 if (mp) {
3252 (void) USBSER_DS_TX(pp, mp);
3253 }
3254 mutex_enter(&pp->port_mutex);
3255 }
3256
3257
3258 /*
3259 * misc
3260 * ----
3261 *
3262 *
3263 * returns != 0 if device is online, 0 otherwise
3264 */
3265 static int
usbser_dev_is_online(usbser_state_t * usp)3266 usbser_dev_is_online(usbser_state_t *usp)
3267 {
3268 int rval;
3269
3270 mutex_enter(&usp->us_mutex);
3271 rval = (usp->us_dev_state == USB_DEV_ONLINE);
3272 mutex_exit(&usp->us_mutex);
3273
3274 return (rval);
3275 }
3276
3277 /*
3278 * serialize port activities defined by 'act' mask
3279 */
3280 static void
usbser_serialize_port_act(usbser_port_t * pp,int act)3281 usbser_serialize_port_act(usbser_port_t *pp, int act)
3282 {
3283 while (pp->port_act & act)
3284 cv_wait(&pp->port_act_cv, &pp->port_mutex);
3285 pp->port_act |= act;
3286 }
3287
3288
3289 /*
3290 * indicate that port activity is finished
3291 */
3292 static void
usbser_release_port_act(usbser_port_t * pp,int act)3293 usbser_release_port_act(usbser_port_t *pp, int act)
3294 {
3295 pp->port_act &= ~act;
3296 cv_broadcast(&pp->port_act_cv);
3297 }
3298
3299 #ifdef DEBUG
3300 /*
3301 * message type to string and back conversion.
3302 *
3303 * pardon breaks on the same line, but as long as cstyle doesn't
3304 * complain, I'd like to keep this form for trivial cases like this.
3305 * associative arrays in the kernel, anyone?
3306 */
3307 static char *
usbser_msgtype2str(int type)3308 usbser_msgtype2str(int type)
3309 {
3310 char *str;
3311
3312 switch (type) {
3313 case M_STOP: str = "M_STOP"; break;
3314 case M_START: str = "M_START"; break;
3315 case M_STOPI: str = "M_STOPI"; break;
3316 case M_STARTI: str = "M_STARTI"; break;
3317 case M_DATA: str = "M_DATA"; break;
3318 case M_DELAY: str = "M_DELAY"; break;
3319 case M_BREAK: str = "M_BREAK"; break;
3320 case M_IOCTL: str = "M_IOCTL"; break;
3321 case M_IOCDATA: str = "M_IOCDATA"; break;
3322 case M_FLUSH: str = "M_FLUSH"; break;
3323 case M_CTL: str = "M_CTL"; break;
3324 case M_READ: str = "M_READ"; break;
3325 default: str = "unknown"; break;
3326 }
3327
3328 return (str);
3329 }
3330
3331 static char *
usbser_ioctl2str(int ioctl)3332 usbser_ioctl2str(int ioctl)
3333 {
3334 char *str;
3335
3336 switch (ioctl) {
3337 case TCGETA: str = "TCGETA"; break;
3338 case TCSETA: str = "TCSETA"; break;
3339 case TCSETAF: str = "TCSETAF"; break;
3340 case TCSETAW: str = "TCSETAW"; break;
3341 case TCSBRK: str = "TCSBRK"; break;
3342 case TCXONC: str = "TCXONC"; break;
3343 case TCFLSH: str = "TCFLSH"; break;
3344 case TCGETS: str = "TCGETS"; break;
3345 case TCSETS: str = "TCSETS"; break;
3346 case TCSETSF: str = "TCSETSF"; break;
3347 case TCSETSW: str = "TCSETSW"; break;
3348 case TIOCSBRK: str = "TIOCSBRK"; break;
3349 case TIOCCBRK: str = "TIOCCBRK"; break;
3350 case TIOCMSET: str = "TIOCMSET"; break;
3351 case TIOCMBIS: str = "TIOCMBIS"; break;
3352 case TIOCMBIC: str = "TIOCMBIC"; break;
3353 case TIOCMGET: str = "TIOCMGET"; break;
3354 case TIOCSILOOP: str = "TIOCSILOOP"; break;
3355 case TIOCCILOOP: str = "TIOCCILOOP"; break;
3356 case TCGETX: str = "TCGETX"; break;
3357 case TCSETX: str = "TCGETX"; break;
3358 case TCSETXW: str = "TCGETX"; break;
3359 case TCSETXF: str = "TCGETX"; break;
3360 default: str = "unknown"; break;
3361 }
3362
3363 return (str);
3364 }
3365 #endif
3366 /*
3367 * Polled IO support
3368 */
3369
3370 /* called once by consconfig() when polledio is opened */
3371 static int
usbser_polledio_init(usbser_port_t * pp)3372 usbser_polledio_init(usbser_port_t *pp)
3373 {
3374 int err;
3375 usb_pipe_handle_t hdl;
3376 ds_ops_t *ds_ops = pp->port_ds_ops;
3377
3378 /* only one serial line console supported */
3379 if (console_input != NULL)
3380 return (USB_FAILURE);
3381
3382 /* check if underlying driver supports polled io */
3383 if (ds_ops->ds_version < DS_OPS_VERSION_V1 ||
3384 ds_ops->ds_out_pipe == NULL || ds_ops->ds_in_pipe == NULL)
3385 return (USB_FAILURE);
3386
3387 /* init polled input pipe */
3388 hdl = ds_ops->ds_in_pipe(pp->port_ds_hdl, pp->port_num);
3389 err = usb_console_input_init(pp->port_usp->us_dip, hdl,
3390 &console_input_buf, &console_input);
3391 if (err)
3392 return (USB_FAILURE);
3393
3394 /* init polled output pipe */
3395 hdl = ds_ops->ds_out_pipe(pp->port_ds_hdl, pp->port_num);
3396 err = usb_console_output_init(pp->port_usp->us_dip, hdl,
3397 &console_output);
3398 if (err) {
3399 (void) usb_console_input_fini(console_input);
3400 console_input = NULL;
3401 return (USB_FAILURE);
3402 }
3403
3404 return (USB_SUCCESS);
3405 }
3406
3407 /* called once by consconfig() when polledio is closed */
3408 /*ARGSUSED*/
usbser_polledio_fini(usbser_port_t * pp)3409 static void usbser_polledio_fini(usbser_port_t *pp)
3410 {
3411 /* Since we can't move the console, there is nothing to do. */
3412 }
3413
3414 /*ARGSUSED*/
3415 static void
usbser_polledio_enter(cons_polledio_arg_t arg)3416 usbser_polledio_enter(cons_polledio_arg_t arg)
3417 {
3418 (void) usb_console_input_enter(console_input);
3419 (void) usb_console_output_enter(console_output);
3420 }
3421
3422 /*ARGSUSED*/
3423 static void
usbser_polledio_exit(cons_polledio_arg_t arg)3424 usbser_polledio_exit(cons_polledio_arg_t arg)
3425 {
3426 (void) usb_console_output_exit(console_output);
3427 (void) usb_console_input_exit(console_input);
3428 }
3429
3430 /*ARGSUSED*/
3431 static void
usbser_putchar(cons_polledio_arg_t arg,uchar_t c)3432 usbser_putchar(cons_polledio_arg_t arg, uchar_t c)
3433 {
3434 static uchar_t cr[2] = {'\r', '\n'};
3435 uint_t nout;
3436
3437 if (c == '\n')
3438 (void) usb_console_write(console_output, cr, 2, &nout);
3439 else
3440 (void) usb_console_write(console_output, &c, 1, &nout);
3441 }
3442
3443 /*ARGSUSED*/
3444 static int
usbser_getchar(cons_polledio_arg_t arg)3445 usbser_getchar(cons_polledio_arg_t arg)
3446 {
3447 while (!usbser_ischar(arg))
3448 ;
3449
3450 return (*console_input_start++);
3451 }
3452
3453 /*ARGSUSED*/
3454 static boolean_t
usbser_ischar(cons_polledio_arg_t arg)3455 usbser_ischar(cons_polledio_arg_t arg)
3456 {
3457 uint_t num_bytes;
3458
3459 if (console_input_start < console_input_end)
3460 return (B_TRUE);
3461
3462 if (usb_console_read(console_input, &num_bytes) != USB_SUCCESS)
3463 return (B_FALSE);
3464
3465 console_input_start = console_input_buf;
3466 console_input_end = console_input_buf + num_bytes;
3467
3468 return (num_bytes != 0);
3469 }
3470