Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/usb/clients/usbser/usbser.c
+++ new/usr/src/uts/common/io/usb/clients/usbser/usbser.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26
27 27 /*
28 28 *
29 29 * USB generic serial driver (GSD)
30 30 *
31 31 */
32 32 #include <sys/types.h>
33 33 #include <sys/param.h>
34 34 #include <sys/stream.h>
35 35 #include <sys/stropts.h>
36 36 #include <sys/errno.h>
37 37 #include <sys/cred.h>
38 38 #include <sys/conf.h>
39 39 #include <sys/stat.h>
40 40 #include <sys/modctl.h>
41 41 #include <sys/ddi.h>
42 42 #include <sys/sunddi.h>
43 43 #include <sys/sunndi.h>
44 44 #include <sys/termio.h>
45 45 #include <sys/termiox.h>
46 46 #include <sys/stropts.h>
47 47 #include <sys/stream.h>
48 48 #include <sys/strsubr.h>
49 49 #include <sys/strsun.h>
50 50 #include <sys/strtty.h>
51 51 #include <sys/policy.h>
52 52 #include <sys/consdev.h>
53 53
54 54 #include <sys/usb/usba.h>
55 55 #include <sys/usb/clients/usbser/usbser_var.h>
56 56 #include <sys/usb/clients/usbser/usbser_dsdi.h>
57 57 #include <sys/usb/clients/usbser/usbser_rseq.h>
58 58 #include <sys/usb/usba/genconsole.h>
59 59
60 60 /* autoconfiguration subroutines */
61 61 static int usbser_rseq_do_cb(rseq_t *, int, uintptr_t);
62 62 static int usbser_free_soft_state(usbser_state_t *);
63 63 static int usbser_init_soft_state(usbser_state_t *);
64 64 static int usbser_fini_soft_state(usbser_state_t *);
65 65 static int usbser_attach_dev(usbser_state_t *);
66 66 static void usbser_detach_dev(usbser_state_t *);
67 67 static int usbser_attach_ports(usbser_state_t *);
68 68 static int usbser_create_port_minor_nodes(usbser_state_t *, int);
69 69 static void usbser_detach_ports(usbser_state_t *);
70 70 static int usbser_create_taskq(usbser_state_t *);
71 71 static void usbser_destroy_taskq(usbser_state_t *);
72 72 static void usbser_set_dev_state_init(usbser_state_t *);
73 73
74 74 /* hotplugging and power management */
75 75 static int usbser_disconnect_cb(dev_info_t *);
76 76 static int usbser_reconnect_cb(dev_info_t *);
77 77 static void usbser_disconnect_ports(usbser_state_t *);
78 78 static int usbser_cpr_suspend(dev_info_t *);
79 79 static int usbser_suspend_ports(usbser_state_t *);
80 80 static void usbser_cpr_resume(dev_info_t *);
81 81 static int usbser_restore_device_state(usbser_state_t *);
82 82 static void usbser_restore_ports_state(usbser_state_t *);
83 83
84 84 /* STREAMS subroutines */
85 85 static int usbser_open_setup(queue_t *, usbser_port_t *, int, int,
86 86 cred_t *);
87 87 static int usbser_open_init(usbser_port_t *, int);
88 88 static void usbser_check_port_props(usbser_port_t *);
89 89 static void usbser_open_fini(usbser_port_t *);
90 90 static int usbser_open_line_setup(usbser_port_t *, int, int);
91 91 static int usbser_open_carrier_check(usbser_port_t *, int, int);
92 92 static void usbser_open_queues_init(usbser_port_t *, queue_t *);
93 93 static void usbser_open_queues_fini(usbser_port_t *);
94 94 static void usbser_close_drain(usbser_port_t *);
95 95 static void usbser_close_cancel_break(usbser_port_t *);
96 96 static void usbser_close_hangup(usbser_port_t *);
97 97 static void usbser_close_cleanup(usbser_port_t *);
98 98
99 99 /* threads */
100 100 static void usbser_thr_dispatch(usbser_thread_t *);
101 101 static void usbser_thr_cancel(usbser_thread_t *);
102 102 static void usbser_thr_wake(usbser_thread_t *);
103 103 static void usbser_wq_thread(void *);
104 104 static void usbser_rq_thread(void *);
105 105
106 106 /* DSD callbacks */
107 107 static void usbser_tx_cb(caddr_t);
108 108 static void usbser_rx_cb(caddr_t);
109 109 static void usbser_rx_massage_data(usbser_port_t *, mblk_t *);
110 110 static void usbser_rx_massage_mbreak(usbser_port_t *, mblk_t *);
111 111 static void usbser_rx_cb_put(usbser_port_t *, queue_t *, queue_t *,
112 112 mblk_t *);
113 113 static void usbser_status_cb(caddr_t);
114 114 static void usbser_status_proc_cb(usbser_port_t *);
115 115
116 116 /* serial support */
117 117 static void usbser_wmsg(usbser_port_t *);
118 118 static int usbser_data(usbser_port_t *, mblk_t *);
119 119 static int usbser_ioctl(usbser_port_t *, mblk_t *);
120 120 static void usbser_iocdata(usbser_port_t *, mblk_t *);
121 121 static void usbser_stop(usbser_port_t *, mblk_t *);
122 122 static void usbser_start(usbser_port_t *, mblk_t *);
123 123 static void usbser_stopi(usbser_port_t *, mblk_t *);
124 124 static void usbser_starti(usbser_port_t *, mblk_t *);
125 125 static void usbser_flush(usbser_port_t *, mblk_t *);
126 126 static void usbser_break(usbser_port_t *, mblk_t *);
127 127 static void usbser_delay(usbser_port_t *, mblk_t *);
128 128 static void usbser_restart(void *);
129 129 static int usbser_port_program(usbser_port_t *);
130 130 static void usbser_inbound_flow_ctl(usbser_port_t *);
131 131
132 132 /* misc */
133 133 static int usbser_dev_is_online(usbser_state_t *);
134 134 static void usbser_serialize_port_act(usbser_port_t *, int);
135 135 static void usbser_release_port_act(usbser_port_t *, int);
136 136 #ifdef DEBUG
137 137 static char *usbser_msgtype2str(int);
138 138 static char *usbser_ioctl2str(int);
139 139 #endif
140 140
141 141 /* USBA events */
142 142 usb_event_t usbser_usb_events = {
143 143 usbser_disconnect_cb, /* disconnect */
144 144 usbser_reconnect_cb, /* reconnect */
145 145 NULL, /* pre-suspend */
146 146 NULL, /* pre-resume */
147 147 };
148 148
149 149 /* debug support */
150 150 uint_t usbser_errlevel = USB_LOG_L4;
151 151 uint_t usbser_errmask = DPRINT_MASK_ALL;
152 152 uint_t usbser_instance_debug = (uint_t)-1;
153 153
154 154 /* usb serial console */
155 155 static struct usbser_state *usbser_list;
156 156 static kmutex_t usbser_lock;
157 157 static int usbser_console_abort;
158 158 static usb_console_info_t console_input, console_output;
159 159 static uchar_t *console_input_buf;
160 160 static uchar_t *console_input_start, *console_input_end;
161 161
162 162 _NOTE(SCHEME_PROTECTS_DATA("unshared", usbser_console_abort))
163 163 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input))
164 164 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_output))
165 165 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_start))
166 166 _NOTE(SCHEME_PROTECTS_DATA("unshared", console_input_end))
167 167
168 168 static void usbser_putchar(cons_polledio_arg_t, uchar_t);
169 169 static int usbser_getchar(cons_polledio_arg_t);
170 170 static boolean_t usbser_ischar(cons_polledio_arg_t);
171 171 static void usbser_polledio_enter(cons_polledio_arg_t);
172 172 static void usbser_polledio_exit(cons_polledio_arg_t);
173 173 static int usbser_polledio_init(usbser_port_t *);
174 174 static void usbser_polledio_fini(usbser_port_t *);
175 175
176 176 static struct cons_polledio usbser_polledio = {
177 177 CONSPOLLEDIO_V1,
178 178 NULL, /* to be set later */
179 179 usbser_putchar,
180 180 usbser_getchar,
181 181 usbser_ischar,
182 182 usbser_polledio_enter,
183 183 usbser_polledio_exit
184 184 };
185 185
186 186 /* various statistics. TODO: replace with kstats */
187 187 static int usbser_st_tx_data_loss = 0;
188 188 static int usbser_st_rx_data_loss = 0;
189 189 static int usbser_st_put_stopi = 0;
190 190 static int usbser_st_mstop = 0;
191 191 static int usbser_st_mstart = 0;
192 192 static int usbser_st_mstopi = 0;
193 193 static int usbser_st_mstarti = 0;
194 194 static int usbser_st_rsrv = 0;
195 195 _NOTE(SCHEME_PROTECTS_DATA("monotonic stats", usbser_st_{
196 196 tx_data_loss rx_data_loss put_stopi mstop mstart mstopi mstarti rsrv}))
197 197 _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_bulk_req_t))
198 198 _NOTE(SCHEME_PROTECTS_DATA("unshared", usb_intr_req_t))
199 199
200 200 /* taskq parameter */
201 201 extern pri_t minclsyspri;
202 202
203 203 /*
204 204 * tell warlock not to worry about STREAMS structures
205 205 */
206 206 _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk datab msgb queue copyreq))
207 207
208 208 /*
↓ open down ↓ |
208 lines elided |
↑ open up ↑ |
209 209 * modload support
210 210 */
211 211 extern struct mod_ops mod_miscops;
212 212
213 213 static struct modlmisc modlmisc = {
214 214 &mod_miscops, /* Type of module */
215 215 "USB generic serial module"
216 216 };
217 217
218 218 static struct modlinkage modlinkage = {
219 - MODREV_1, (void *)&modlmisc, NULL
219 + MODREV_1, { (void *)&modlmisc, NULL }
220 220 };
221 221
222 222
223 223 #define RSEQ(f1, f2) RSEQE(f1, usbser_rseq_do_cb, f2, NULL)
224 224
225 225
226 226 /*
227 227 * loadable module entry points
228 228 * ----------------------------
229 229 */
230 230
231 231 int
232 232 _init(void)
233 233 {
234 234 int err;
235 235
236 236 mutex_init(&usbser_lock, NULL, MUTEX_DRIVER, (void *)NULL);
237 237
238 238 if ((err = mod_install(&modlinkage)) != 0)
239 239 mutex_destroy(&usbser_lock);
240 240
241 241 return (err);
242 242 }
243 243
244 244
245 245 int
246 246 _fini(void)
247 247 {
248 248 int err;
249 249
250 250 if ((err = mod_remove(&modlinkage)) != 0)
251 251 return (err);
252 252
253 253 mutex_destroy(&usbser_lock);
254 254
255 255 return (0);
256 256 }
257 257
258 258
259 259 int
260 260 _info(struct modinfo *modinfop)
261 261 {
262 262 return (mod_info(&modlinkage, modinfop));
263 263 }
264 264
265 265
266 266 /*
267 267 * soft state size
268 268 */
269 269 int
270 270 usbser_soft_state_size()
271 271 {
272 272 return (sizeof (usbser_state_t));
273 273 }
274 274
275 275
276 276 /*
277 277 * autoconfiguration entry points
278 278 * ------------------------------
279 279 */
280 280
281 281 /*ARGSUSED*/
282 282 int
283 283 usbser_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
284 284 void **result, void *statep)
285 285 {
286 286 int instance;
287 287 int ret = DDI_FAILURE;
288 288 usbser_state_t *usbserp;
289 289
290 290 instance = USBSER_MINOR2INST(getminor((dev_t)arg));
291 291
292 292 switch (infocmd) {
293 293 case DDI_INFO_DEVT2DEVINFO:
294 294 *result = NULL;
295 295 usbserp = ddi_get_soft_state(statep, instance);
296 296 if (usbserp != NULL) {
297 297 *result = usbserp->us_dip;
298 298 if (*result != NULL) {
299 299 ret = DDI_SUCCESS;
300 300 }
301 301 }
302 302
303 303 break;
304 304 case DDI_INFO_DEVT2INSTANCE:
305 305 *result = (void *)(uintptr_t)instance;
306 306 ret = DDI_SUCCESS;
307 307
308 308 break;
309 309 default:
310 310 break;
311 311 }
312 312
313 313 return (ret);
314 314 }
315 315
316 316 /*
317 317 * device attach
318 318 */
319 319 static rseq_t rseq_att[] = {
320 320 RSEQ(NULL, usbser_free_soft_state),
321 321 RSEQ(usbser_init_soft_state, usbser_fini_soft_state),
322 322 RSEQ(usbser_attach_dev, usbser_detach_dev),
323 323 RSEQ(usbser_attach_ports, usbser_detach_ports),
324 324 RSEQ(usbser_create_taskq, usbser_destroy_taskq),
325 325 RSEQ(NULL, usbser_set_dev_state_init)
326 326 };
327 327
328 328 static void
329 329 usbser_insert(struct usbser_state *usp)
330 330 {
331 331 struct usbser_state *tmp;
332 332
333 333 mutex_enter(&usbser_lock);
334 334 tmp = usbser_list;
335 335 if (tmp == NULL)
336 336 usbser_list = usp;
337 337 else {
338 338 while (tmp->us_next)
339 339 tmp = tmp->us_next;
340 340 tmp->us_next = usp;
341 341 }
342 342 mutex_exit(&usbser_lock);
343 343 }
344 344
345 345 static void
346 346 usbser_remove(struct usbser_state *usp)
347 347 {
348 348 struct usbser_state *tmp, *prev = NULL;
349 349
350 350 mutex_enter(&usbser_lock);
351 351 tmp = usbser_list;
352 352 while (tmp != usp) {
353 353 prev = tmp;
354 354 tmp = tmp->us_next;
355 355 }
356 356 ASSERT(tmp == usp); /* must exist, else attach/detach wrong */
357 357 if (prev)
358 358 prev->us_next = usp->us_next;
359 359 else
360 360 usbser_list = usp->us_next;
361 361 usp->us_next = NULL;
362 362 mutex_exit(&usbser_lock);
363 363 }
364 364
365 365 /*
366 366 * Return the first serial device, with dip held. This is called
367 367 * from the console subsystem to place console on usb serial device.
368 368 */
369 369 dev_info_t *
370 370 usbser_first_device(void)
371 371 {
372 372 dev_info_t *dip = NULL;
373 373
374 374 mutex_enter(&usbser_lock);
375 375 if (usbser_list) {
376 376 dip = usbser_list->us_dip;
377 377 ndi_hold_devi(dip);
378 378 }
379 379 mutex_exit(&usbser_lock);
380 380
381 381 return (dip);
382 382 }
383 383
384 384 int
385 385 usbser_attach(dev_info_t *dip, ddi_attach_cmd_t cmd,
386 386 void *statep, ds_ops_t *ds_ops)
387 387 {
388 388 int instance;
389 389 usbser_state_t *usp;
390 390
391 391 instance = ddi_get_instance(dip);
392 392
393 393 switch (cmd) {
394 394 case DDI_ATTACH:
395 395
396 396 break;
397 397 case DDI_RESUME:
398 398 usbser_cpr_resume(dip);
399 399
400 400 return (DDI_SUCCESS);
401 401 default:
402 402
403 403 return (DDI_FAILURE);
404 404 }
405 405
406 406 /* allocate and get soft state */
407 407 if (ddi_soft_state_zalloc(statep, instance) != DDI_SUCCESS) {
408 408
409 409 return (DDI_FAILURE);
410 410 }
411 411 if ((usp = ddi_get_soft_state(statep, instance)) == NULL) {
412 412 ddi_soft_state_free(statep, instance);
413 413
414 414 return (DDI_FAILURE);
415 415 }
416 416
417 417 usp->us_statep = statep;
418 418 usp->us_dip = dip;
419 419 usp->us_instance = instance;
420 420 usp->us_ds_ops = ds_ops;
421 421
422 422 if (rseq_do(rseq_att, NELEM(rseq_att), (uintptr_t)usp, 0) == RSEQ_OK) {
423 423 ddi_report_dev(dip);
424 424 usbser_insert(usp);
425 425
426 426 return (DDI_SUCCESS);
427 427 } else {
428 428
429 429 return (DDI_FAILURE);
430 430 }
431 431 }
432 432
433 433 /*
434 434 * device detach
435 435 */
436 436 int
437 437 usbser_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, void *statep)
438 438 {
439 439 int instance = ddi_get_instance(dip);
440 440 usbser_state_t *usp;
441 441 int rval;
442 442
443 443 usp = ddi_get_soft_state(statep, instance);
444 444
445 445 switch (cmd) {
446 446 case DDI_DETACH:
447 447 USB_DPRINTF_L4(DPRINT_DETACH, usp->us_lh, "usbser_detach");
448 448 usbser_remove(usp);
449 449 (void) rseq_undo(rseq_att, NELEM(rseq_att), (uintptr_t)usp, 0);
450 450 USB_DPRINTF_L4(DPRINT_DETACH, NULL,
451 451 "usbser_detach.%d: end", instance);
452 452
453 453 return (DDI_SUCCESS);
454 454 case DDI_SUSPEND:
455 455 rval = usbser_cpr_suspend(dip);
456 456
457 457 return ((rval == USB_SUCCESS)? DDI_SUCCESS : DDI_FAILURE);
458 458 default:
459 459
460 460 return (DDI_FAILURE);
461 461 }
462 462 }
463 463
464 464 /*
465 465 * STREAMS entry points
466 466 * --------------------
467 467 *
468 468 *
469 469 * port open
470 470 */
471 471 /*ARGSUSED*/
472 472 int
473 473 usbser_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr,
474 474 void *statep)
475 475 {
476 476 usbser_state_t *usp;
477 477 usbser_port_t *pp;
478 478 int minor = getminor(*dev);
479 479 int instance;
480 480 uint_t port_num;
481 481 int rval;
482 482
483 483 instance = USBSER_MINOR2INST(minor);
484 484 if (instance < 0) {
485 485
486 486 return (ENXIO);
487 487 }
488 488
489 489 usp = ddi_get_soft_state(statep, instance);
490 490 if (usp == NULL) {
491 491
492 492 return (ENXIO);
493 493 }
494 494
495 495 /* don't allow to open disconnected device */
496 496 mutex_enter(&usp->us_mutex);
497 497 if (usp->us_dev_state == USB_DEV_DISCONNECTED) {
498 498 mutex_exit(&usp->us_mutex);
499 499
500 500 return (ENXIO);
501 501 }
502 502 mutex_exit(&usp->us_mutex);
503 503
504 504 /* get port soft state */
505 505 port_num = USBSER_MINOR2PORT(minor);
506 506 if (port_num >= usp->us_port_cnt) {
507 507
508 508 return (ENXIO);
509 509 }
510 510 pp = &usp->us_ports[port_num];
511 511
512 512 /* set up everything for open */
513 513 rval = usbser_open_setup(rq, pp, minor, flag, cr);
514 514
515 515 USB_DPRINTF_L4(DPRINT_OPEN, pp->port_lh, "usbser_open: rval=%d", rval);
516 516
517 517 return (rval);
518 518 }
519 519
520 520
521 521 /*
522 522 * port close
523 523 *
524 524 * some things driver should do when the last app closes the line:
525 525 *
526 526 * drain data;
527 527 * cancel break/delay;
528 528 * hangup line (if necessary);
529 529 * DSD close;
530 530 * cleanup soft state;
531 531 */
532 532 /*ARGSUSED*/
533 533 int
534 534 usbser_close(queue_t *rq, int flag, cred_t *cr)
535 535 {
536 536 usbser_port_t *pp = (usbser_port_t *)rq->q_ptr;
537 537 int online;
538 538
539 539 if (pp == NULL) {
540 540
541 541 return (ENXIO);
542 542 }
543 543
544 544 online = usbser_dev_is_online(pp->port_usp);
545 545
546 546 /*
547 547 * in the closing state new activities will not be initiated
548 548 */
549 549 mutex_enter(&pp->port_mutex);
550 550 pp->port_state = USBSER_PORT_CLOSING;
551 551
552 552 if (online) {
553 553 /* drain the data */
554 554 usbser_close_drain(pp);
555 555 }
556 556
557 557 /* stop break/delay */
558 558 usbser_close_cancel_break(pp);
559 559
560 560 if (online) {
561 561 /* hangup line */
562 562 usbser_close_hangup(pp);
563 563 }
564 564
565 565 /*
566 566 * close DSD, cleanup state and transition to 'closed' state
567 567 */
568 568 usbser_close_cleanup(pp);
569 569 mutex_exit(&pp->port_mutex);
570 570
571 571 USB_DPRINTF_L4(DPRINT_CLOSE, pp->port_lh, "usbser_close: end");
572 572
573 573 return (0);
574 574 }
575 575
576 576
577 577 /*
578 578 * read side service routine: send as much as possible messages upstream
579 579 * and if there is still place on the queue, enable receive (if not already)
580 580 */
581 581 int
582 582 usbser_rsrv(queue_t *q)
583 583 {
584 584 usbser_port_t *pp = (usbser_port_t *)q->q_ptr;
585 585 mblk_t *mp;
586 586
587 587 usbser_st_rsrv++;
588 588 USB_DPRINTF_L4(DPRINT_RQ, pp->port_lh, "usbser_rsrv");
589 589
590 590 while (canputnext(q) && (mp = getq(q))) {
591 591 putnext(q, mp);
592 592 }
593 593
594 594 if (canputnext(q)) {
595 595 mutex_enter(&pp->port_mutex);
596 596 ASSERT(pp->port_state != USBSER_PORT_CLOSED);
597 597
598 598 if (USBSER_PORT_ACCESS_OK(pp)) {
599 599 usbser_thr_wake(&pp->port_rq_thread);
600 600 }
601 601 mutex_exit(&pp->port_mutex);
602 602 }
603 603
604 604 return (0);
605 605 }
606 606
607 607
608 608 /*
609 609 * wput: put message on the queue and wake wq thread
610 610 */
611 611 int
612 612 usbser_wput(queue_t *q, mblk_t *mp)
613 613 {
614 614 usbser_port_t *pp = (usbser_port_t *)q->q_ptr;
615 615
616 616 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wput");
617 617
618 618 mutex_enter(&pp->port_mutex);
619 619 ASSERT(pp->port_state != USBSER_PORT_CLOSED);
620 620
621 621 /* ignore new messages if port is already closing */
622 622 if (pp->port_state == USBSER_PORT_CLOSING) {
623 623 freemsg(mp);
624 624 } else if (putq(q, mp)) {
625 625 /*
626 626 * this counter represents amount of tx data on the wq.
627 627 * each time the data is passed to DSD for transmission,
628 628 * the counter is decremented accordingly
629 629 */
630 630 pp->port_wq_data_cnt += msgdsize(mp);
631 631 } else {
632 632 usbser_st_tx_data_loss++;
633 633 }
634 634 mutex_exit(&pp->port_mutex);
635 635
636 636 return (0);
637 637 }
638 638
639 639
640 640 /*
641 641 * we need wsrv() routine to take advantage of STREAMS flow control:
642 642 * without it the framework will consider we are always able to process msgs
643 643 */
644 644 int
645 645 usbser_wsrv(queue_t *q)
646 646 {
647 647 usbser_port_t *pp = (usbser_port_t *)q->q_ptr;
648 648
649 649 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wsrv");
650 650
651 651 mutex_enter(&pp->port_mutex);
652 652 ASSERT(pp->port_state != USBSER_PORT_CLOSED);
653 653
654 654 if (USBSER_PORT_ACCESS_OK(pp)) {
655 655 usbser_thr_wake(&pp->port_wq_thread);
656 656 }
657 657 mutex_exit(&pp->port_mutex);
658 658
659 659 return (0);
660 660 }
661 661
662 662
663 663 /*
664 664 * power entry point
665 665 */
666 666 int
667 667 usbser_power(dev_info_t *dip, int comp, int level)
668 668 {
669 669 void *statep;
670 670 usbser_state_t *usp;
671 671 int new_state;
672 672 int rval;
673 673
674 674 statep = ddi_get_driver_private(dip);
675 675 usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
676 676
677 677 USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
678 678 "usbser_power: dip=0x%p, comp=%d, level=%d",
679 679 (void *)dip, comp, level);
680 680
681 681 mutex_enter(&usp->us_mutex);
682 682 new_state = usp->us_dev_state;
683 683 mutex_exit(&usp->us_mutex);
684 684
685 685 /* let DSD do the job */
686 686 rval = USBSER_DS_USB_POWER(usp, comp, level, &new_state);
687 687
688 688 /* stay in sync with DSD */
689 689 mutex_enter(&usp->us_mutex);
690 690 usp->us_dev_state = new_state;
691 691 mutex_exit(&usp->us_mutex);
692 692
693 693 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
694 694 }
695 695
696 696
697 697 /*
698 698 *
699 699 * configuration entry point subroutines
700 700 * -------------------------------------
701 701 *
702 702 * rseq callback
703 703 */
704 704 static int
705 705 usbser_rseq_do_cb(rseq_t *rseq, int num, uintptr_t arg)
706 706 {
707 707 usbser_state_t *usp = (usbser_state_t *)arg;
708 708 int rval = rseq[num].r_do.s_rval;
709 709 char *name = rseq[num].r_do.s_name;
710 710
711 711 if (rval != DDI_SUCCESS) {
712 712 USB_DPRINTF_L2(DPRINT_ATTACH, usp->us_lh,
713 713 "do %s failed (%d)", name, rval);
714 714
715 715 return (RSEQ_UNDO);
716 716 } else {
717 717
718 718 return (RSEQ_OK);
719 719 }
720 720 }
721 721
722 722
723 723 /*
724 724 * free soft state
725 725 */
726 726 static int
727 727 usbser_free_soft_state(usbser_state_t *usp)
728 728 {
729 729 ddi_soft_state_free(usp->us_statep, usp->us_instance);
730 730
731 731 return (USB_SUCCESS);
732 732 }
733 733
734 734 /*
735 735 * init instance soft state
736 736 */
737 737 static int
738 738 usbser_init_soft_state(usbser_state_t *usp)
739 739 {
740 740 usp->us_lh = usb_alloc_log_hdl(usp->us_dip, "usbs[*].",
741 741 &usbser_errlevel, &usbser_errmask, &usbser_instance_debug,
742 742 0);
743 743 mutex_init(&usp->us_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
744 744
745 745 /* save state pointer for use in event callbacks */
746 746 ddi_set_driver_private(usp->us_dip, usp->us_statep);
747 747
748 748 usp->us_dev_state = USBSER_DEV_INIT;
749 749
750 750 return (DDI_SUCCESS);
751 751 }
752 752
753 753 /*
754 754 * fini instance soft state
755 755 */
756 756 static int
757 757 usbser_fini_soft_state(usbser_state_t *usp)
758 758 {
759 759 usb_free_log_hdl(usp->us_lh);
760 760 mutex_destroy(&usp->us_mutex);
761 761 ddi_set_driver_private(usp->us_dip, NULL);
762 762
763 763 return (DDI_SUCCESS);
764 764 }
765 765
766 766 /*
767 767 * attach entire device
768 768 */
769 769 static int
770 770 usbser_attach_dev(usbser_state_t *usp)
771 771 {
772 772 ds_attach_info_t ai;
773 773 int rval;
774 774
775 775 usp->us_dev_state = USB_DEV_ONLINE;
776 776
777 777 ai.ai_dip = usp->us_dip;
778 778 ai.ai_usb_events = &usbser_usb_events;
779 779 ai.ai_hdl = &usp->us_ds_hdl;
780 780 ai.ai_port_cnt = &usp->us_port_cnt;
781 781
782 782 rval = USBSER_DS_ATTACH(usp, &ai);
783 783
784 784 if ((rval != USB_SUCCESS) || (usp->us_ds_hdl == NULL) ||
785 785 (usp->us_port_cnt == 0)) {
786 786 USB_DPRINTF_L4(DPRINT_ATTACH, usp->us_lh, "usbser_attach_dev: "
787 787 "failed %d %p %d", rval, usp->us_ds_hdl, usp->us_port_cnt);
788 788
789 789 return (DDI_FAILURE);
790 790 }
791 791
792 792 USB_DPRINTF_L4(DPRINT_ATTACH, usp->us_lh,
793 793 "usbser_attach_dev: port_cnt = %d", usp->us_port_cnt);
794 794
795 795 return (DDI_SUCCESS);
796 796 }
797 797
798 798
799 799 /*
800 800 * detach entire device
801 801 */
802 802 static void
803 803 usbser_detach_dev(usbser_state_t *usp)
804 804 {
805 805 USBSER_DS_DETACH(usp);
806 806 }
807 807
808 808
809 809 /*
810 810 * attach each individual port
811 811 */
812 812 static int
813 813 usbser_attach_ports(usbser_state_t *usp)
814 814 {
815 815 int i;
816 816 usbser_port_t *pp;
817 817 ds_cb_t ds_cb;
818 818
819 819 /*
820 820 * allocate port array
821 821 */
822 822 usp->us_ports = kmem_zalloc(usp->us_port_cnt *
823 823 sizeof (usbser_port_t), KM_SLEEP);
824 824
825 825 /* callback handlers */
826 826 ds_cb.cb_tx = usbser_tx_cb;
827 827 ds_cb.cb_rx = usbser_rx_cb;
828 828 ds_cb.cb_status = usbser_status_cb;
829 829
830 830 /*
831 831 * initialize each port
832 832 */
833 833 for (i = 0; i < usp->us_port_cnt; i++) {
834 834 pp = &usp->us_ports[i];
835 835
836 836 /*
837 837 * initialize data
838 838 */
839 839 pp->port_num = i;
840 840 pp->port_usp = usp;
841 841 pp->port_ds_ops = usp->us_ds_ops;
842 842 pp->port_ds_hdl = usp->us_ds_hdl;
843 843
844 844 /* allocate log handle */
845 845 (void) sprintf(pp->port_lh_name, "usbs[%d].", i);
846 846 pp->port_lh = usb_alloc_log_hdl(usp->us_dip,
847 847 pp->port_lh_name, &usbser_errlevel, &usbser_errmask,
848 848 &usbser_instance_debug, 0);
849 849
850 850 mutex_init(&pp->port_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
851 851 cv_init(&pp->port_state_cv, NULL, CV_DEFAULT, NULL);
852 852 cv_init(&pp->port_act_cv, NULL, CV_DEFAULT, NULL);
853 853 cv_init(&pp->port_car_cv, NULL, CV_DEFAULT, NULL);
854 854
855 855 /*
856 856 * init threads
857 857 */
858 858 pp->port_wq_thread.thr_port = pp;
859 859 pp->port_wq_thread.thr_func = usbser_wq_thread;
860 860 pp->port_wq_thread.thr_arg = (void *)&pp->port_wq_thread;
861 861 cv_init(&pp->port_wq_thread.thr_cv, NULL, CV_DEFAULT, NULL);
862 862
863 863 pp->port_rq_thread.thr_port = pp;
864 864 pp->port_rq_thread.thr_func = usbser_rq_thread;
865 865 pp->port_rq_thread.thr_arg = (void *)&pp->port_rq_thread;
866 866 cv_init(&pp->port_rq_thread.thr_cv, NULL, CV_DEFAULT, NULL);
867 867
868 868 /*
869 869 * register callbacks
870 870 */
871 871 ds_cb.cb_arg = (caddr_t)pp;
872 872 USBSER_DS_REGISTER_CB(usp, i, &ds_cb);
873 873
874 874 pp->port_state = USBSER_PORT_CLOSED;
875 875
876 876 if (usbser_create_port_minor_nodes(usp, i) != USB_SUCCESS) {
877 877 usbser_detach_ports(usp);
878 878
879 879 return (DDI_FAILURE);
880 880 }
881 881 }
882 882
883 883 return (DDI_SUCCESS);
884 884 }
885 885
886 886
887 887 /*
888 888 * create a pair of minor nodes for the port
889 889 */
890 890 static int
891 891 usbser_create_port_minor_nodes(usbser_state_t *usp, int port_num)
892 892 {
893 893 int instance = usp->us_instance;
894 894 minor_t minor;
895 895 char name[16];
896 896
897 897 /*
898 898 * tty node
899 899 */
900 900 (void) sprintf(name, "%d", port_num);
901 901 minor = USBSER_MAKEMINOR(instance, port_num, 0);
902 902
903 903 if (ddi_create_minor_node(usp->us_dip, name,
904 904 S_IFCHR, minor, DDI_NT_SERIAL, NULL) != DDI_SUCCESS) {
905 905
906 906 return (USB_FAILURE);
907 907 }
908 908
909 909 /*
910 910 * dial-out node
911 911 */
912 912 (void) sprintf(name, "%d,cu", port_num);
913 913 minor = USBSER_MAKEMINOR(instance, port_num, OUTLINE);
914 914
915 915 if (ddi_create_minor_node(usp->us_dip, name,
916 916 S_IFCHR, minor, DDI_NT_SERIAL_DO, NULL) != DDI_SUCCESS) {
917 917
918 918 return (USB_FAILURE);
919 919 }
920 920
921 921 return (USB_SUCCESS);
922 922 }
923 923
924 924
925 925 /*
926 926 * detach each port individually
927 927 */
928 928 static void
929 929 usbser_detach_ports(usbser_state_t *usp)
930 930 {
931 931 int i;
932 932 int sz;
933 933 usbser_port_t *pp;
934 934
935 935 /*
936 936 * remove all minor nodes
937 937 */
938 938 ddi_remove_minor_node(usp->us_dip, NULL);
939 939
940 940 for (i = 0; i < usp->us_port_cnt; i++) {
941 941 pp = &usp->us_ports[i];
942 942
943 943 if (pp->port_state != USBSER_PORT_CLOSED) {
944 944 ASSERT(pp->port_state == USBSER_PORT_NOT_INIT);
945 945
946 946 continue;
947 947 }
948 948
949 949 USBSER_DS_UNREGISTER_CB(usp, i);
950 950
951 951 mutex_destroy(&pp->port_mutex);
952 952 cv_destroy(&pp->port_state_cv);
953 953 cv_destroy(&pp->port_act_cv);
954 954 cv_destroy(&pp->port_car_cv);
955 955
956 956 cv_destroy(&pp->port_wq_thread.thr_cv);
957 957 cv_destroy(&pp->port_rq_thread.thr_cv);
958 958
959 959 usb_free_log_hdl(pp->port_lh);
960 960 }
961 961
962 962 /*
963 963 * free memory
964 964 */
965 965 sz = usp->us_port_cnt * sizeof (usbser_port_t);
966 966 kmem_free(usp->us_ports, sz);
967 967 usp->us_ports = NULL;
968 968 }
969 969
970 970
971 971 /*
972 972 * create a taskq with two threads per port (read and write sides)
973 973 */
974 974 static int
975 975 usbser_create_taskq(usbser_state_t *usp)
976 976 {
977 977 int nthr = usp->us_port_cnt * 2;
978 978
979 979 usp->us_taskq = ddi_taskq_create(usp->us_dip, "usbser_taskq",
980 980 nthr, TASKQ_DEFAULTPRI, 0);
981 981
982 982 return ((usp->us_taskq == NULL) ? DDI_FAILURE : DDI_SUCCESS);
983 983 }
984 984
985 985
986 986 static void
987 987 usbser_destroy_taskq(usbser_state_t *usp)
988 988 {
989 989 ddi_taskq_destroy(usp->us_taskq);
990 990 }
991 991
992 992
993 993 static void
994 994 usbser_set_dev_state_init(usbser_state_t *usp)
995 995 {
996 996 mutex_enter(&usp->us_mutex);
997 997 usp->us_dev_state = USBSER_DEV_INIT;
998 998 mutex_exit(&usp->us_mutex);
999 999 }
1000 1000
1001 1001 /*
1002 1002 * hotplugging and power management
1003 1003 * ---------------------------------
1004 1004 *
1005 1005 * disconnect event callback
1006 1006 */
1007 1007 /*ARGSUSED*/
1008 1008 static int
1009 1009 usbser_disconnect_cb(dev_info_t *dip)
1010 1010 {
1011 1011 void *statep;
1012 1012 usbser_state_t *usp;
1013 1013
1014 1014 statep = ddi_get_driver_private(dip);
1015 1015 usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
1016 1016
1017 1017 USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
1018 1018 "usbser_disconnect_cb: dip=%p", (void *)dip);
1019 1019
1020 1020 mutex_enter(&usp->us_mutex);
1021 1021 switch (usp->us_dev_state) {
1022 1022 case USB_DEV_ONLINE:
1023 1023 case USB_DEV_PWRED_DOWN:
1024 1024 /* prevent further activity */
1025 1025 usp->us_dev_state = USB_DEV_DISCONNECTED;
1026 1026 mutex_exit(&usp->us_mutex);
1027 1027
1028 1028 /* see if any of the ports are open and do necessary handling */
1029 1029 usbser_disconnect_ports(usp);
1030 1030
1031 1031 /* call DSD to do any necessary work */
1032 1032 if (USBSER_DS_DISCONNECT(usp) != USB_DEV_DISCONNECTED) {
1033 1033 USB_DPRINTF_L2(DPRINT_EVENTS, usp->us_lh,
1034 1034 "usbser_disconnect_cb: ds_disconnect failed");
1035 1035 }
1036 1036
1037 1037 break;
1038 1038 case USB_DEV_SUSPENDED:
1039 1039 /* we remain suspended */
1040 1040 default:
1041 1041 mutex_exit(&usp->us_mutex);
1042 1042
1043 1043 break;
1044 1044 }
1045 1045
1046 1046 return (USB_SUCCESS);
1047 1047 }
1048 1048
1049 1049
1050 1050 /*
1051 1051 * reconnect event callback
1052 1052 */
1053 1053 /*ARGSUSED*/
1054 1054 static int
1055 1055 usbser_reconnect_cb(dev_info_t *dip)
1056 1056 {
1057 1057 void *statep;
1058 1058 usbser_state_t *usp;
1059 1059
1060 1060 statep = ddi_get_driver_private(dip);
1061 1061 usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
1062 1062
1063 1063 USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
1064 1064 "usbser_reconnect_cb: dip=%p", (void *)dip);
1065 1065
1066 1066 (void) usbser_restore_device_state(usp);
1067 1067
1068 1068 return (USB_SUCCESS);
1069 1069 }
1070 1070
1071 1071
1072 1072 /*
1073 1073 * if any of the ports is open during disconnect,
1074 1074 * send M_HANGUP message upstream and log a warning
1075 1075 */
1076 1076 static void
1077 1077 usbser_disconnect_ports(usbser_state_t *usp)
1078 1078 {
1079 1079 usbser_port_t *pp;
1080 1080 queue_t *rq;
1081 1081 int complain = 0;
1082 1082 int hangup = 0;
1083 1083 timeout_id_t delay_id = 0;
1084 1084 int i;
1085 1085
1086 1086 if (usp->us_ports == NULL) {
1087 1087 return;
1088 1088 }
1089 1089
1090 1090 for (i = 0; i < usp->us_port_cnt; i++) {
1091 1091 pp = &usp->us_ports[i];
1092 1092
1093 1093 mutex_enter(&pp->port_mutex);
1094 1094 if (pp->port_state == USBSER_PORT_OPEN ||
1095 1095 USBSER_IS_OPENING(pp) ||
1096 1096 pp->port_state == USBSER_PORT_CLOSING) {
1097 1097 complain = 1;
1098 1098 }
1099 1099
1100 1100 if (pp->port_state == USBSER_PORT_OPEN) {
1101 1101 rq = pp->port_ttycommon.t_readq;
1102 1102
1103 1103 /*
1104 1104 * hangup the stream; will send actual
1105 1105 * M_HANGUP message after releasing mutex
1106 1106 */
1107 1107 pp->port_flags |= USBSER_FL_HUNGUP;
1108 1108 hangup = 1;
1109 1109
1110 1110 /*
1111 1111 * cancel all activities
1112 1112 */
1113 1113 usbser_release_port_act(pp, USBSER_ACT_ALL);
1114 1114
1115 1115 delay_id = pp->port_delay_id;
1116 1116 pp->port_delay_id = 0;
1117 1117
1118 1118 /* mark disconnected */
1119 1119 pp->port_state = USBSER_PORT_DISCONNECTED;
1120 1120 cv_broadcast(&pp->port_state_cv);
1121 1121 }
1122 1122 mutex_exit(&pp->port_mutex);
1123 1123
1124 1124 if (hangup) {
1125 1125 (void) putnextctl(rq, M_HANGUP);
1126 1126 hangup = 0;
1127 1127 }
1128 1128
1129 1129 /*
1130 1130 * we couldn't untimeout while holding the mutex - do it now
1131 1131 */
1132 1132 if (delay_id) {
1133 1133 (void) untimeout(delay_id);
1134 1134 delay_id = 0;
1135 1135 }
1136 1136 }
1137 1137
1138 1138 /*
1139 1139 * complain about disconnecting device while open
1140 1140 */
1141 1141 if (complain) {
1142 1142 USB_DPRINTF_L0(DPRINT_EVENTS, usp->us_lh, "device was "
1143 1143 "disconnected while open. Data may have been lost");
1144 1144 }
1145 1145 }
1146 1146
1147 1147
1148 1148 /*
1149 1149 * do CPR suspend
1150 1150 *
1151 1151 * We use a trivial CPR strategy - fail if any of the device's ports are open.
1152 1152 * The problem with more sophisticated strategies is that each open port uses
1153 1153 * two threads that sit in the loop until the port is closed, while CPR has to
1154 1154 * stop all kernel threads to succeed. Stopping port threads is a rather
1155 1155 * intrusive and delicate procedure; I leave it as an RFE for now.
1156 1156 *
1157 1157 */
1158 1158 static int
1159 1159 usbser_cpr_suspend(dev_info_t *dip)
1160 1160 {
1161 1161 void *statep;
1162 1162 usbser_state_t *usp;
1163 1163 int new_state;
1164 1164 int rval;
1165 1165
1166 1166 statep = ddi_get_driver_private(dip);
1167 1167 usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
1168 1168
1169 1169 USB_DPRINTF_L4(DPRINT_EVENTS, usp->us_lh, "usbser_cpr_suspend");
1170 1170
1171 1171 /* suspend each port first */
1172 1172 if (usbser_suspend_ports(usp) != USB_SUCCESS) {
1173 1173 USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh,
1174 1174 "usbser_cpr_suspend: GSD failure");
1175 1175
1176 1176 return (USB_FAILURE);
1177 1177 }
1178 1178
1179 1179 new_state = USBSER_DS_SUSPEND(usp); /* let DSD do its part */
1180 1180
1181 1181 mutex_enter(&usp->us_mutex);
1182 1182 if (new_state == USB_DEV_SUSPENDED) {
1183 1183 rval = USB_SUCCESS;
1184 1184 } else {
1185 1185 ASSERT(new_state == USB_DEV_ONLINE);
1186 1186 rval = USB_FAILURE;
1187 1187 }
1188 1188 usp->us_dev_state = new_state;
1189 1189 mutex_exit(&usp->us_mutex);
1190 1190
1191 1191 return (rval);
1192 1192 }
1193 1193
1194 1194
1195 1195 static int
1196 1196 usbser_suspend_ports(usbser_state_t *usp)
1197 1197 {
1198 1198 usbser_port_t *pp;
1199 1199 int i;
1200 1200
1201 1201 for (i = 0; i < usp->us_port_cnt; i++) {
1202 1202 pp = &usp->us_ports[i];
1203 1203
1204 1204 mutex_enter(&pp->port_mutex);
1205 1205 if (pp->port_state != USBSER_PORT_CLOSED) {
1206 1206 mutex_exit(&pp->port_mutex);
1207 1207
1208 1208 return (USB_FAILURE);
1209 1209 }
1210 1210 mutex_exit(&pp->port_mutex);
1211 1211 }
1212 1212
1213 1213 return (USB_SUCCESS);
1214 1214 }
1215 1215
1216 1216
1217 1217 /*
1218 1218 * do CPR resume
1219 1219 *
1220 1220 * DSD will return USB_DEV_ONLINE in case of success
1221 1221 */
1222 1222 static void
1223 1223 usbser_cpr_resume(dev_info_t *dip)
1224 1224 {
1225 1225 void *statep;
1226 1226 usbser_state_t *usp;
1227 1227
1228 1228 statep = ddi_get_driver_private(dip);
1229 1229 usp = ddi_get_soft_state(statep, ddi_get_instance(dip));
1230 1230
1231 1231 USB_DPRINTF_L3(DPRINT_EVENTS, usp->us_lh, "usbser_cpr_resume");
1232 1232
1233 1233 (void) usbser_restore_device_state(usp);
1234 1234 }
1235 1235
1236 1236
1237 1237 /*
1238 1238 * restore device state after CPR resume or reconnect
1239 1239 */
1240 1240 static int
1241 1241 usbser_restore_device_state(usbser_state_t *usp)
1242 1242 {
1243 1243 int new_state, current_state;
1244 1244
1245 1245 /* needed as power up state of dev is "unknown" to system */
1246 1246 (void) pm_busy_component(usp->us_dip, 0);
1247 1247 (void) pm_raise_power(usp->us_dip, 0, USB_DEV_OS_FULL_PWR);
1248 1248
1249 1249 mutex_enter(&usp->us_mutex);
1250 1250 current_state = usp->us_dev_state;
1251 1251 mutex_exit(&usp->us_mutex);
1252 1252
1253 1253 ASSERT((current_state == USB_DEV_DISCONNECTED) ||
1254 1254 (current_state == USB_DEV_SUSPENDED));
1255 1255
1256 1256 /*
1257 1257 * call DSD to perform device-specific work
1258 1258 */
1259 1259 if (current_state == USB_DEV_DISCONNECTED) {
1260 1260 new_state = USBSER_DS_RECONNECT(usp);
1261 1261 } else {
1262 1262 new_state = USBSER_DS_RESUME(usp);
1263 1263 }
1264 1264
1265 1265 mutex_enter(&usp->us_mutex);
1266 1266 usp->us_dev_state = new_state;
1267 1267 mutex_exit(&usp->us_mutex);
1268 1268
1269 1269 if (new_state == USB_DEV_ONLINE) {
1270 1270 /*
1271 1271 * restore ports state
1272 1272 */
1273 1273 usbser_restore_ports_state(usp);
1274 1274 }
1275 1275
1276 1276 (void) pm_idle_component(usp->us_dip, 0);
1277 1277
1278 1278 return (USB_SUCCESS);
1279 1279 }
1280 1280
1281 1281
1282 1282 /*
1283 1283 * restore ports state after device reconnect/resume
1284 1284 */
1285 1285 static void
1286 1286 usbser_restore_ports_state(usbser_state_t *usp)
1287 1287 {
1288 1288 usbser_port_t *pp;
1289 1289 queue_t *rq;
1290 1290 int i;
1291 1291
1292 1292 for (i = 0; i < usp->us_port_cnt; i++) {
1293 1293 pp = &usp->us_ports[i];
1294 1294
1295 1295 mutex_enter(&pp->port_mutex);
1296 1296 /*
1297 1297 * only care about ports that are open
1298 1298 */
1299 1299 if ((pp->port_state != USBSER_PORT_SUSPENDED) &&
1300 1300 (pp->port_state != USBSER_PORT_DISCONNECTED)) {
1301 1301 mutex_exit(&pp->port_mutex);
1302 1302
1303 1303 continue;
1304 1304 }
1305 1305
1306 1306 pp->port_state = USBSER_PORT_OPEN;
1307 1307
1308 1308 /*
1309 1309 * if the stream was hung up during disconnect, restore it
1310 1310 */
1311 1311 if (pp->port_flags & USBSER_FL_HUNGUP) {
1312 1312 pp->port_flags &= ~USBSER_FL_HUNGUP;
1313 1313 rq = pp->port_ttycommon.t_readq;
1314 1314
1315 1315 mutex_exit(&pp->port_mutex);
1316 1316 (void) putnextctl(rq, M_UNHANGUP);
1317 1317 mutex_enter(&pp->port_mutex);
1318 1318 }
1319 1319
1320 1320 /*
1321 1321 * restore serial parameters
1322 1322 */
1323 1323 (void) usbser_port_program(pp);
1324 1324
1325 1325 /*
1326 1326 * wake anything that might be sleeping
1327 1327 */
1328 1328 cv_broadcast(&pp->port_state_cv);
1329 1329 cv_broadcast(&pp->port_act_cv);
1330 1330 usbser_thr_wake(&pp->port_wq_thread);
1331 1331 usbser_thr_wake(&pp->port_rq_thread);
1332 1332 mutex_exit(&pp->port_mutex);
1333 1333 }
1334 1334 }
1335 1335
1336 1336
1337 1337 /*
1338 1338 * STREAMS subroutines
1339 1339 * -------------------
1340 1340 *
1341 1341 *
1342 1342 * port open state machine
1343 1343 *
1344 1344 * here's a list of things that the driver has to do while open;
1345 1345 * because device can be opened any number of times,
1346 1346 * initial open has additional responsibilities:
1347 1347 *
1348 1348 * if (initial_open) {
1349 1349 * initialize soft state; \
1350 1350 * DSD open; - see usbser_open_init()
1351 1351 * dispatch threads; /
1352 1352 * }
1353 1353 * raise DTR;
1354 1354 * wait for carrier (if necessary);
1355 1355 *
1356 1356 * we should also take into consideration that two threads can try to open
1357 1357 * the same physical port simultaneously (/dev/term/N and /dev/cua/N).
1358 1358 *
1359 1359 * return values:
1360 1360 * 0 - success;
1361 1361 * >0 - fail with this error code;
1362 1362 */
1363 1363 static int
1364 1364 usbser_open_setup(queue_t *rq, usbser_port_t *pp, int minor, int flag,
1365 1365 cred_t *cr)
1366 1366 {
1367 1367 int rval = USBSER_CONTINUE;
1368 1368
1369 1369 mutex_enter(&pp->port_mutex);
1370 1370 /*
1371 1371 * refer to port state diagram in the header file
1372 1372 */
1373 1373 loop:
1374 1374 switch (pp->port_state) {
1375 1375 case USBSER_PORT_CLOSED:
1376 1376 /*
1377 1377 * initial open
1378 1378 */
1379 1379 rval = usbser_open_init(pp, minor);
1380 1380
1381 1381 break;
1382 1382 case USBSER_PORT_OPENING_TTY:
1383 1383 /*
1384 1384 * dial-out thread can overtake the port
1385 1385 * if tty open thread is sleeping waiting for carrier
1386 1386 */
1387 1387 if ((minor & OUTLINE) && (pp->port_flags & USBSER_FL_WOPEN)) {
1388 1388 pp->port_state = USBSER_PORT_OPENING_OUT;
1389 1389
1390 1390 USB_DPRINTF_L3(DPRINT_OPEN, pp->port_lh,
1391 1391 "usbser_open_state: overtake");
1392 1392 }
1393 1393
1394 1394 /* FALLTHRU */
1395 1395 case USBSER_PORT_OPENING_OUT:
1396 1396 /*
1397 1397 * if no other open in progress, setup the line
1398 1398 */
1399 1399 if (USBSER_NO_OTHER_OPEN(pp, minor)) {
1400 1400 rval = usbser_open_line_setup(pp, minor, flag);
1401 1401
1402 1402 break;
1403 1403 }
1404 1404
1405 1405 /* FALLTHRU */
1406 1406 case USBSER_PORT_CLOSING:
1407 1407 /*
1408 1408 * wait until close active phase ends
1409 1409 */
1410 1410 if (cv_wait_sig(&pp->port_state_cv, &pp->port_mutex) == 0) {
1411 1411 rval = EINTR;
1412 1412 }
1413 1413
1414 1414 break;
1415 1415 case USBSER_PORT_OPEN:
1416 1416 if ((pp->port_ttycommon.t_flags & TS_XCLUDE) &&
1417 1417 secpolicy_excl_open(cr) != 0) {
1418 1418 /*
1419 1419 * exclusive use
1420 1420 */
1421 1421 rval = EBUSY;
1422 1422 } else if (USBSER_OPEN_IN_OTHER_MODE(pp, minor)) {
1423 1423 /*
1424 1424 * tty and dial-out modes are mutually exclusive
1425 1425 */
1426 1426 rval = EBUSY;
1427 1427 } else {
1428 1428 /*
1429 1429 * port is being re-open in the same mode
1430 1430 */
1431 1431 rval = usbser_open_line_setup(pp, minor, flag);
1432 1432 }
1433 1433
1434 1434 break;
1435 1435 default:
1436 1436 rval = ENXIO;
1437 1437
1438 1438 break;
1439 1439 }
1440 1440
1441 1441 if (rval == USBSER_CONTINUE) {
1442 1442
1443 1443 goto loop;
1444 1444 }
1445 1445
1446 1446 /*
1447 1447 * initial open requires additional handling
1448 1448 */
1449 1449 if (USBSER_IS_OPENING(pp)) {
1450 1450 if (rval == USBSER_COMPLETE) {
1451 1451 if (pp->port_state == USBSER_PORT_OPENING_OUT) {
1452 1452 pp->port_flags |= USBSER_FL_OUT;
1453 1453 }
1454 1454 pp->port_state = USBSER_PORT_OPEN;
1455 1455 cv_broadcast(&pp->port_state_cv);
1456 1456
1457 1457 usbser_open_queues_init(pp, rq);
1458 1458 } else {
1459 1459 usbser_open_fini(pp);
1460 1460 }
1461 1461 }
1462 1462 mutex_exit(&pp->port_mutex);
1463 1463
1464 1464 return (rval);
1465 1465 }
1466 1466
1467 1467
1468 1468 /*
1469 1469 * initialize the port when opened for the first time
1470 1470 */
1471 1471 static int
1472 1472 usbser_open_init(usbser_port_t *pp, int minor)
1473 1473 {
1474 1474 usbser_state_t *usp = pp->port_usp;
1475 1475 tty_common_t *tp = &pp->port_ttycommon;
1476 1476 int rval = ENXIO;
1477 1477
1478 1478 ASSERT(pp->port_state == USBSER_PORT_CLOSED);
1479 1479
1480 1480 /*
1481 1481 * init state
1482 1482 */
1483 1483 pp->port_act = 0;
1484 1484 pp->port_flags &= USBSER_FL_PRESERVE;
1485 1485 pp->port_flowc = '\0';
1486 1486 pp->port_wq_data_cnt = 0;
1487 1487
1488 1488 if (minor & OUTLINE) {
1489 1489 pp->port_state = USBSER_PORT_OPENING_OUT;
1490 1490 } else {
1491 1491 pp->port_state = USBSER_PORT_OPENING_TTY;
1492 1492 }
1493 1493
1494 1494 /*
1495 1495 * init termios settings
1496 1496 */
1497 1497 tp->t_iflag = 0;
1498 1498 tp->t_iocpending = NULL;
1499 1499 tp->t_size.ws_row = tp->t_size.ws_col = 0;
1500 1500 tp->t_size.ws_xpixel = tp->t_size.ws_ypixel = 0;
1501 1501 tp->t_startc = CSTART;
1502 1502 tp->t_stopc = CSTOP;
1503 1503
1504 1504 usbser_check_port_props(pp);
1505 1505
1506 1506 /*
1507 1507 * dispatch wq and rq threads:
1508 1508 * although queues are not enabled at this point,
1509 1509 * we will need wq to run status processing callback
1510 1510 */
1511 1511 usbser_thr_dispatch(&pp->port_wq_thread);
1512 1512 usbser_thr_dispatch(&pp->port_rq_thread);
1513 1513
1514 1514 /*
1515 1515 * open DSD port
1516 1516 */
1517 1517 mutex_exit(&pp->port_mutex);
1518 1518 rval = USBSER_DS_OPEN_PORT(usp, pp->port_num);
1519 1519 mutex_enter(&pp->port_mutex);
1520 1520
1521 1521 if (rval != USB_SUCCESS) {
1522 1522
1523 1523 return (ENXIO);
1524 1524 }
1525 1525 pp->port_flags |= USBSER_FL_DSD_OPEN;
1526 1526
1527 1527 /*
1528 1528 * program port with default parameters
1529 1529 */
1530 1530 if ((rval = usbser_port_program(pp)) != 0) {
1531 1531
1532 1532 return (ENXIO);
1533 1533 }
1534 1534
1535 1535 return (USBSER_CONTINUE);
1536 1536 }
1537 1537
1538 1538
1539 1539 /*
1540 1540 * create a pair of minor nodes for the port
1541 1541 */
1542 1542 static void
1543 1543 usbser_check_port_props(usbser_port_t *pp)
1544 1544 {
1545 1545 dev_info_t *dip = pp->port_usp->us_dip;
1546 1546 tty_common_t *tp = &pp->port_ttycommon;
1547 1547 struct termios *termiosp;
1548 1548 uint_t len;
1549 1549 char name[20];
1550 1550
1551 1551 /*
1552 1552 * take default modes from "ttymodes" property if it exists
1553 1553 */
1554 1554 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ddi_root_node(), 0,
1555 1555 "ttymodes", (uchar_t **)&termiosp, &len) == DDI_PROP_SUCCESS) {
1556 1556
1557 1557 if (len == sizeof (struct termios)) {
1558 1558 tp->t_cflag = termiosp->c_cflag;
1559 1559
1560 1560 if (termiosp->c_iflag & (IXON | IXANY)) {
1561 1561 tp->t_iflag =
1562 1562 termiosp->c_iflag & (IXON | IXANY);
1563 1563 tp->t_startc = termiosp->c_cc[VSTART];
1564 1564 tp->t_stopc = termiosp->c_cc[VSTOP];
1565 1565 }
1566 1566 }
1567 1567 ddi_prop_free(termiosp);
1568 1568 }
1569 1569
1570 1570 /*
1571 1571 * look for "ignore-cd" or "port-N-ignore-cd" property
1572 1572 */
1573 1573 (void) sprintf(name, "port-%d-ignore-cd", pp->port_num);
1574 1574 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1575 1575 "ignore-cd", 0) ||
1576 1576 ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, name, 0)) {
1577 1577 pp->port_flags |= USBSER_FL_IGNORE_CD;
1578 1578 } else {
1579 1579 pp->port_flags &= ~USBSER_FL_IGNORE_CD;
1580 1580 }
1581 1581 }
1582 1582
1583 1583
1584 1584 /*
1585 1585 * undo what was done in usbser_open_init()
1586 1586 */
1587 1587 static void
1588 1588 usbser_open_fini(usbser_port_t *pp)
1589 1589 {
1590 1590 uint_t port_num = pp->port_num;
1591 1591 usbser_state_t *usp = pp->port_usp;
1592 1592
1593 1593 /*
1594 1594 * close DSD if it is open
1595 1595 */
1596 1596 if (pp->port_flags & USBSER_FL_DSD_OPEN) {
1597 1597 mutex_exit(&pp->port_mutex);
1598 1598 if (USBSER_DS_CLOSE_PORT(usp, port_num) != USB_SUCCESS) {
1599 1599 USB_DPRINTF_L2(DPRINT_CLOSE, pp->port_lh,
1600 1600 "usbser_open_fini: CLOSE_PORT fail");
1601 1601 }
1602 1602 mutex_enter(&pp->port_mutex);
1603 1603 }
1604 1604
1605 1605 /*
1606 1606 * cancel threads
1607 1607 */
1608 1608 usbser_thr_cancel(&pp->port_wq_thread);
1609 1609 usbser_thr_cancel(&pp->port_rq_thread);
1610 1610
1611 1611 /*
1612 1612 * unpdate soft state
1613 1613 */
1614 1614 pp->port_state = USBSER_PORT_CLOSED;
1615 1615 cv_broadcast(&pp->port_state_cv);
1616 1616 cv_broadcast(&pp->port_car_cv);
1617 1617 }
1618 1618
1619 1619
1620 1620 /*
1621 1621 * setup serial line
1622 1622 */
1623 1623 static int
1624 1624 usbser_open_line_setup(usbser_port_t *pp, int minor, int flag)
1625 1625 {
1626 1626 int rval;
1627 1627
1628 1628 mutex_exit(&pp->port_mutex);
1629 1629 /*
1630 1630 * prevent opening a disconnected device
1631 1631 */
1632 1632 if (!usbser_dev_is_online(pp->port_usp)) {
1633 1633 mutex_enter(&pp->port_mutex);
1634 1634
1635 1635 return (ENXIO);
1636 1636 }
1637 1637
1638 1638 /* raise DTR on every open */
1639 1639 (void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR, TIOCM_DTR);
1640 1640
1641 1641 mutex_enter(&pp->port_mutex);
1642 1642 /*
1643 1643 * check carrier
1644 1644 */
1645 1645 rval = usbser_open_carrier_check(pp, minor, flag);
1646 1646
1647 1647 return (rval);
1648 1648 }
1649 1649
1650 1650
1651 1651 /*
1652 1652 * check carrier and wait if needed
1653 1653 */
1654 1654 static int
1655 1655 usbser_open_carrier_check(usbser_port_t *pp, int minor, int flag)
1656 1656 {
1657 1657 tty_common_t *tp = &pp->port_ttycommon;
1658 1658 int val = 0;
1659 1659 int rval;
1660 1660
1661 1661 if (pp->port_flags & USBSER_FL_IGNORE_CD) {
1662 1662 tp->t_flags |= TS_SOFTCAR;
1663 1663 }
1664 1664
1665 1665 /*
1666 1666 * check carrier
1667 1667 */
1668 1668 if (tp->t_flags & TS_SOFTCAR) {
1669 1669 pp->port_flags |= USBSER_FL_CARR_ON;
1670 1670 } else if (USBSER_DS_GET_MODEM_CTL(pp, TIOCM_CD, &val) != USB_SUCCESS) {
1671 1671
1672 1672 return (ENXIO);
1673 1673 } else if (val & TIOCM_CD) {
1674 1674 pp->port_flags |= USBSER_FL_CARR_ON;
1675 1675 } else {
1676 1676 pp->port_flags &= ~USBSER_FL_CARR_ON;
1677 1677 }
1678 1678
1679 1679 /*
1680 1680 * don't block if 1) not allowed to, 2) this is a local device,
1681 1681 * 3) opening in dial-out mode, or 4) carrier is already on
1682 1682 */
1683 1683 if ((flag & (FNDELAY | FNONBLOCK)) || (tp->t_cflag & CLOCAL) ||
1684 1684 (minor & OUTLINE) || (pp->port_flags & USBSER_FL_CARR_ON)) {
1685 1685
1686 1686 return (USBSER_COMPLETE);
1687 1687 }
1688 1688
1689 1689 /*
1690 1690 * block until carrier up (only in tty mode)
1691 1691 */
1692 1692 USB_DPRINTF_L4(DPRINT_OPEN, pp->port_lh,
1693 1693 "usbser_open_carrier_check: waiting for carrier...");
1694 1694
1695 1695 pp->port_flags |= USBSER_FL_WOPEN;
1696 1696
1697 1697 rval = cv_wait_sig(&pp->port_car_cv, &pp->port_mutex);
1698 1698
1699 1699 pp->port_flags &= ~USBSER_FL_WOPEN;
1700 1700
1701 1701 if (rval == 0) {
1702 1702 /*
1703 1703 * interrupted with a signal
1704 1704 */
1705 1705 return (EINTR);
1706 1706 } else {
1707 1707 /*
1708 1708 * try again
1709 1709 */
1710 1710 return (USBSER_CONTINUE);
1711 1711 }
1712 1712 }
1713 1713
1714 1714
1715 1715 /*
1716 1716 * during open, setup queues and message processing
1717 1717 */
1718 1718 static void
1719 1719 usbser_open_queues_init(usbser_port_t *pp, queue_t *rq)
1720 1720 {
1721 1721 pp->port_ttycommon.t_readq = rq;
1722 1722 pp->port_ttycommon.t_writeq = WR(rq);
1723 1723 rq->q_ptr = WR(rq)->q_ptr = (caddr_t)pp;
1724 1724
1725 1725 qprocson(rq);
1726 1726 }
1727 1727
1728 1728
1729 1729 /*
1730 1730 * clean up queues and message processing
1731 1731 */
1732 1732 static void
1733 1733 usbser_open_queues_fini(usbser_port_t *pp)
1734 1734 {
1735 1735 queue_t *rq = pp->port_ttycommon.t_readq;
1736 1736
1737 1737 mutex_exit(&pp->port_mutex);
1738 1738 /*
1739 1739 * clean up queues
1740 1740 */
1741 1741 qprocsoff(rq);
1742 1742
1743 1743 /*
1744 1744 * free unused messages
1745 1745 */
1746 1746 flushq(rq, FLUSHALL);
1747 1747 flushq(WR(rq), FLUSHALL);
1748 1748
1749 1749 rq->q_ptr = WR(rq)->q_ptr = NULL;
1750 1750 ttycommon_close(&pp->port_ttycommon);
1751 1751 mutex_enter(&pp->port_mutex);
1752 1752 }
1753 1753
1754 1754
1755 1755 /*
1756 1756 * during close, wait until pending data is gone or the signal is sent
1757 1757 */
1758 1758 static void
1759 1759 usbser_close_drain(usbser_port_t *pp)
1760 1760 {
1761 1761 int need_drain;
1762 1762 clock_t until;
1763 1763 int rval = USB_SUCCESS;
1764 1764
1765 1765 /*
1766 1766 * port_wq_data_cnt indicates amount of data on the write queue,
1767 1767 * which becomes zero when all data is submitted to DSD. But usbser
1768 1768 * stays busy until it gets tx callback from DSD, signalling that
1769 1769 * data has been sent over USB. To be continued in the next comment...
1770 1770 */
1771 1771 until = ddi_get_lbolt() +
1772 1772 drv_usectohz(USBSER_WQ_DRAIN_TIMEOUT * 1000000);
1773 1773
1774 1774 while ((pp->port_wq_data_cnt > 0) && USBSER_PORT_IS_BUSY(pp)) {
1775 1775 if ((rval = cv_timedwait_sig(&pp->port_act_cv, &pp->port_mutex,
1776 1776 until)) <= 0) {
1777 1777
1778 1778 break;
1779 1779 }
1780 1780 }
1781 1781
1782 1782 /* don't drain if timed out or received a signal */
1783 1783 need_drain = (pp->port_wq_data_cnt == 0) || !USBSER_PORT_IS_BUSY(pp) ||
1784 1784 (rval != USB_SUCCESS);
1785 1785
1786 1786 mutex_exit(&pp->port_mutex);
1787 1787 /*
1788 1788 * Once the data reaches USB serial box, it may still be stored in its
1789 1789 * internal output buffer (FIFO). We call DSD drain to ensure that all
1790 1790 * the data is transmitted transmitted over the serial line.
1791 1791 */
1792 1792 if (need_drain) {
1793 1793 rval = USBSER_DS_FIFO_DRAIN(pp, USBSER_TX_FIFO_DRAIN_TIMEOUT);
1794 1794 if (rval != USB_SUCCESS) {
1795 1795 (void) USBSER_DS_FIFO_FLUSH(pp, DS_TX);
1796 1796 }
1797 1797 } else {
1798 1798 (void) USBSER_DS_FIFO_FLUSH(pp, DS_TX);
1799 1799 }
1800 1800 mutex_enter(&pp->port_mutex);
1801 1801 }
1802 1802
1803 1803
1804 1804 /*
1805 1805 * during close, cancel break/delay
1806 1806 */
1807 1807 static void
1808 1808 usbser_close_cancel_break(usbser_port_t *pp)
1809 1809 {
1810 1810 timeout_id_t delay_id;
1811 1811
1812 1812 if (pp->port_act & USBSER_ACT_BREAK) {
1813 1813 delay_id = pp->port_delay_id;
1814 1814 pp->port_delay_id = 0;
1815 1815
1816 1816 mutex_exit(&pp->port_mutex);
1817 1817 (void) untimeout(delay_id);
1818 1818 (void) USBSER_DS_BREAK_CTL(pp, DS_OFF);
1819 1819 mutex_enter(&pp->port_mutex);
1820 1820
1821 1821 pp->port_act &= ~USBSER_ACT_BREAK;
1822 1822 }
1823 1823 }
1824 1824
1825 1825
1826 1826 /*
1827 1827 * during close, drop RTS/DTR if necessary
1828 1828 */
1829 1829 static void
1830 1830 usbser_close_hangup(usbser_port_t *pp)
1831 1831 {
1832 1832 /*
1833 1833 * drop DTR and RTS if HUPCL is set
1834 1834 */
1835 1835 if (pp->port_ttycommon.t_cflag & HUPCL) {
1836 1836 mutex_exit(&pp->port_mutex);
1837 1837 (void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_RTS | TIOCM_DTR, 0);
1838 1838 mutex_enter(&pp->port_mutex);
1839 1839 }
1840 1840 }
1841 1841
1842 1842
1843 1843 /*
1844 1844 * state cleanup during close
1845 1845 */
1846 1846 static void
1847 1847 usbser_close_cleanup(usbser_port_t *pp)
1848 1848 {
1849 1849 usbser_open_queues_fini(pp);
1850 1850
1851 1851 usbser_open_fini(pp);
1852 1852 }
1853 1853
1854 1854
1855 1855 /*
1856 1856 *
1857 1857 * thread management
1858 1858 * -----------------
1859 1859 *
1860 1860 *
1861 1861 * dispatch a thread
1862 1862 */
1863 1863 static void
1864 1864 usbser_thr_dispatch(usbser_thread_t *thr)
1865 1865 {
1866 1866 usbser_port_t *pp = thr->thr_port;
1867 1867 usbser_state_t *usp = pp->port_usp;
1868 1868 int rval;
1869 1869
1870 1870 ASSERT(mutex_owned(&pp->port_mutex));
1871 1871 ASSERT((thr->thr_flags & USBSER_THR_RUNNING) == 0);
1872 1872
1873 1873 thr->thr_flags = USBSER_THR_RUNNING;
1874 1874
1875 1875 rval = ddi_taskq_dispatch(usp->us_taskq, thr->thr_func, thr->thr_arg,
1876 1876 DDI_SLEEP);
1877 1877 ASSERT(rval == DDI_SUCCESS);
1878 1878 }
1879 1879
1880 1880
1881 1881 /*
1882 1882 * cancel a thread
1883 1883 */
1884 1884 static void
1885 1885 usbser_thr_cancel(usbser_thread_t *thr)
1886 1886 {
1887 1887 usbser_port_t *pp = thr->thr_port;
1888 1888
1889 1889 ASSERT(mutex_owned(&pp->port_mutex));
1890 1890
1891 1891 thr->thr_flags &= ~USBSER_THR_RUNNING;
1892 1892 cv_signal(&thr->thr_cv);
1893 1893
1894 1894 /* wait until the thread actually exits */
1895 1895 do {
1896 1896 cv_wait(&thr->thr_cv, &pp->port_mutex);
1897 1897
1898 1898 } while ((thr->thr_flags & USBSER_THR_EXITED) == 0);
1899 1899 }
1900 1900
1901 1901
1902 1902 /*
1903 1903 * wake thread
1904 1904 */
1905 1905 static void
1906 1906 usbser_thr_wake(usbser_thread_t *thr)
1907 1907 {
1908 1908 ASSERT(mutex_owned(&thr->thr_port->port_mutex));
1909 1909
1910 1910 thr->thr_flags |= USBSER_THR_WAKE;
1911 1911 cv_signal(&thr->thr_cv);
1912 1912 }
1913 1913
1914 1914
1915 1915 /*
1916 1916 * thread handling write queue requests
1917 1917 */
1918 1918 static void
1919 1919 usbser_wq_thread(void *arg)
1920 1920 {
1921 1921 usbser_thread_t *thr = (usbser_thread_t *)arg;
1922 1922 usbser_port_t *pp = thr->thr_port;
1923 1923
1924 1924 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wq_thread: enter");
1925 1925
1926 1926 mutex_enter(&pp->port_mutex);
1927 1927 while (thr->thr_flags & USBSER_THR_RUNNING) {
1928 1928 /*
1929 1929 * when woken, see what we should do
1930 1930 */
1931 1931 if (thr->thr_flags & USBSER_THR_WAKE) {
1932 1932 thr->thr_flags &= ~USBSER_THR_WAKE;
1933 1933
1934 1934 /*
1935 1935 * status callback pending?
1936 1936 */
1937 1937 if (pp->port_flags & USBSER_FL_STATUS_CB) {
1938 1938 usbser_status_proc_cb(pp);
1939 1939 }
1940 1940
1941 1941 usbser_wmsg(pp);
1942 1942 } else {
1943 1943 /*
1944 1944 * sleep until woken up to do some work, e.g:
1945 1945 * - new message arrives;
1946 1946 * - data transmit completes;
1947 1947 * - status callback pending;
1948 1948 * - wq thread is cancelled;
1949 1949 */
1950 1950 cv_wait(&thr->thr_cv, &pp->port_mutex);
1951 1951 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
1952 1952 "usbser_wq_thread: wakeup");
1953 1953 }
1954 1954 }
1955 1955 thr->thr_flags |= USBSER_THR_EXITED;
1956 1956 cv_signal(&thr->thr_cv);
1957 1957 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wq_thread: exit");
1958 1958 mutex_exit(&pp->port_mutex);
1959 1959 }
1960 1960
1961 1961
1962 1962 /*
1963 1963 * thread handling read queue requests
1964 1964 */
1965 1965 static void
1966 1966 usbser_rq_thread(void *arg)
1967 1967 {
1968 1968 usbser_thread_t *thr = (usbser_thread_t *)arg;
1969 1969 usbser_port_t *pp = thr->thr_port;
1970 1970
1971 1971 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_rq_thread: enter");
1972 1972
1973 1973 mutex_enter(&pp->port_mutex);
1974 1974 while (thr->thr_flags & USBSER_THR_RUNNING) {
1975 1975 /*
1976 1976 * read service routine will wake us when
1977 1977 * more space is available on the read queue
1978 1978 */
1979 1979 if (thr->thr_flags & USBSER_THR_WAKE) {
1980 1980 thr->thr_flags &= ~USBSER_THR_WAKE;
1981 1981
1982 1982 /*
1983 1983 * don't process messages until queue is enabled
1984 1984 */
1985 1985 if (!pp->port_ttycommon.t_readq) {
1986 1986
1987 1987 continue;
1988 1988 }
1989 1989
1990 1990 /*
1991 1991 * check whether we need to resume receive
1992 1992 */
1993 1993 if (pp->port_flags & USBSER_FL_RX_STOPPED) {
1994 1994 pp->port_flowc = pp->port_ttycommon.t_startc;
1995 1995 usbser_inbound_flow_ctl(pp);
1996 1996 }
1997 1997
1998 1998 /*
1999 1999 * grab more data if available
2000 2000 */
2001 2001 mutex_exit(&pp->port_mutex);
2002 2002 usbser_rx_cb((caddr_t)pp);
2003 2003 mutex_enter(&pp->port_mutex);
2004 2004 } else {
2005 2005 cv_wait(&thr->thr_cv, &pp->port_mutex);
2006 2006 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
2007 2007 "usbser_rq_thread: wakeup");
2008 2008 }
2009 2009 }
2010 2010 thr->thr_flags |= USBSER_THR_EXITED;
2011 2011 cv_signal(&thr->thr_cv);
2012 2012 USB_DPRINTF_L4(DPRINT_RQ, pp->port_lh, "usbser_rq_thread: exit");
2013 2013 mutex_exit(&pp->port_mutex);
2014 2014 }
2015 2015
2016 2016
2017 2017 /*
2018 2018 * DSD callbacks
2019 2019 * -------------
2020 2020 *
2021 2021 * Note: to avoid deadlocks with DSD, these callbacks
2022 2022 * should not call DSD functions that can block.
2023 2023 *
2024 2024 *
2025 2025 * transmit callback
2026 2026 *
2027 2027 * invoked by DSD when the last byte of data is transmitted over USB
2028 2028 */
2029 2029 static void
2030 2030 usbser_tx_cb(caddr_t arg)
2031 2031 {
2032 2032 usbser_port_t *pp = (usbser_port_t *)arg;
2033 2033 int online;
2034 2034
2035 2035 online = usbser_dev_is_online(pp->port_usp);
2036 2036
2037 2037 mutex_enter(&pp->port_mutex);
2038 2038 USB_DPRINTF_L4(DPRINT_TX_CB, pp->port_lh,
2039 2039 "usbser_tx_cb: act=%x curthread=%p", pp->port_act,
2040 2040 (void *)curthread);
2041 2041
2042 2042 usbser_release_port_act(pp, USBSER_ACT_TX);
2043 2043
2044 2044 /*
2045 2045 * as long as port access is ok and the port is not busy on
2046 2046 * TX, break, ctrl or delay, the wq_thread should be waken
2047 2047 * to do further process for next message
2048 2048 */
2049 2049 if (online && USBSER_PORT_ACCESS_OK(pp) &&
2050 2050 !USBSER_PORT_IS_BUSY_NON_RX(pp)) {
2051 2051 /*
2052 2052 * wake wq thread for further data/ioctl processing
2053 2053 */
2054 2054 usbser_thr_wake(&pp->port_wq_thread);
2055 2055 }
2056 2056 mutex_exit(&pp->port_mutex);
2057 2057 }
2058 2058
2059 2059
2060 2060 /*
2061 2061 * receive callback
2062 2062 *
2063 2063 * invoked by DSD when there is more data for us to pick
2064 2064 */
2065 2065 static void
2066 2066 usbser_rx_cb(caddr_t arg)
2067 2067 {
2068 2068 usbser_port_t *pp = (usbser_port_t *)arg;
2069 2069 queue_t *rq, *wq;
2070 2070 mblk_t *mp; /* current mblk */
2071 2071 mblk_t *data, *data_tail; /* M_DATA mblk list and its tail */
2072 2072 mblk_t *emp; /* error (M_BREAK) mblk */
2073 2073
2074 2074 USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh, "usbser_rx_cb");
2075 2075
2076 2076 if (!usbser_dev_is_online(pp->port_usp)) {
2077 2077
2078 2078 return;
2079 2079 }
2080 2080
2081 2081 /* get data from DSD */
2082 2082 if ((mp = USBSER_DS_RX(pp)) == NULL) {
2083 2083
2084 2084 return;
2085 2085 }
2086 2086
2087 2087 mutex_enter(&pp->port_mutex);
2088 2088 if ((!USBSER_PORT_ACCESS_OK(pp)) ||
2089 2089 ((pp->port_ttycommon.t_cflag & CREAD) == 0)) {
2090 2090 freemsg(mp);
2091 2091 mutex_exit(&pp->port_mutex);
2092 2092 USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
2093 2093 "usbser_rx_cb: access not ok or receiver disabled");
2094 2094
2095 2095 return;
2096 2096 }
2097 2097
2098 2098 usbser_serialize_port_act(pp, USBSER_ACT_RX);
2099 2099
2100 2100 rq = pp->port_ttycommon.t_readq;
2101 2101 wq = pp->port_ttycommon.t_writeq;
2102 2102 mutex_exit(&pp->port_mutex);
2103 2103
2104 2104 /*
2105 2105 * DSD data is a b_cont-linked list of M_DATA and M_BREAK blocks.
2106 2106 * M_DATA is correctly received data.
2107 2107 * M_BREAK is a character with either framing or parity error.
2108 2108 *
2109 2109 * this loop runs through the list of mblks. when it meets an M_BREAK,
2110 2110 * it sends all leading M_DATA's in one shot, then sends M_BREAK.
2111 2111 * in the trivial case when list contains only M_DATA's, the loop
2112 2112 * does nothing but set data variable.
2113 2113 */
2114 2114 data = data_tail = NULL;
2115 2115 while (mp) {
2116 2116 /*
2117 2117 * skip data until we meet M_BREAK or end of list
2118 2118 */
2119 2119 if (DB_TYPE(mp) == M_DATA) {
2120 2120 if (data == NULL) {
2121 2121 data = mp;
2122 2122 }
2123 2123 data_tail = mp;
2124 2124 mp = mp->b_cont;
2125 2125
2126 2126 continue;
2127 2127 }
2128 2128
2129 2129 /* detach data list from mp */
2130 2130 if (data_tail) {
2131 2131 data_tail->b_cont = NULL;
2132 2132 }
2133 2133 /* detach emp from the list */
2134 2134 emp = mp;
2135 2135 mp = mp->b_cont;
2136 2136 emp->b_cont = NULL;
2137 2137
2138 2138 /* DSD shouldn't send anything but M_DATA or M_BREAK */
2139 2139 if ((DB_TYPE(emp) != M_BREAK) || (MBLKL(emp) != 2)) {
2140 2140 freemsg(emp);
2141 2141 USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
2142 2142 "usbser_rx_cb: bad message");
2143 2143
2144 2144 continue;
2145 2145 }
2146 2146
2147 2147 /*
2148 2148 * first tweak and send M_DATA's
2149 2149 */
2150 2150 if (data) {
2151 2151 usbser_rx_massage_data(pp, data);
2152 2152 usbser_rx_cb_put(pp, rq, wq, data);
2153 2153 data = data_tail = NULL;
2154 2154 }
2155 2155
2156 2156 /*
2157 2157 * now tweak and send M_BREAK
2158 2158 */
2159 2159 mutex_enter(&pp->port_mutex);
2160 2160 usbser_rx_massage_mbreak(pp, emp);
2161 2161 mutex_exit(&pp->port_mutex);
2162 2162 usbser_rx_cb_put(pp, rq, wq, emp);
2163 2163 }
2164 2164
2165 2165 /* send the rest of the data, if any */
2166 2166 if (data) {
2167 2167 usbser_rx_massage_data(pp, data);
2168 2168 usbser_rx_cb_put(pp, rq, wq, data);
2169 2169 }
2170 2170
2171 2171 mutex_enter(&pp->port_mutex);
2172 2172 usbser_release_port_act(pp, USBSER_ACT_RX);
2173 2173 mutex_exit(&pp->port_mutex);
2174 2174 }
2175 2175
2176 2176 /*
2177 2177 * the joys of termio -- this is to accomodate Unix98 assertion:
2178 2178 *
2179 2179 * If PARENB is supported and is set, when PARMRK is set, and CSIZE is
2180 2180 * set to CS8, and IGNPAR is clear, and ISTRIP is clear, a valid
2181 2181 * character of '\377' is read as '\377', '\377'.
2182 2182 *
2183 2183 * Posix Ref: Assertion 7.1.2.2-16(C)
2184 2184 *
2185 2185 * this requires the driver to scan every incoming valid character
2186 2186 */
2187 2187 static void
2188 2188 usbser_rx_massage_data(usbser_port_t *pp, mblk_t *mp)
2189 2189 {
2190 2190 tty_common_t *tp = &pp->port_ttycommon;
2191 2191 uchar_t *p;
2192 2192 mblk_t *newmp;
2193 2193 int tailsz;
2194 2194
2195 2195 /* avoid scanning if possible */
2196 2196 mutex_enter(&pp->port_mutex);
2197 2197 if (!((tp->t_cflag & PARENB) && (tp->t_iflag & PARMRK) &&
2198 2198 ((tp->t_cflag & CSIZE) == CS8) &&
2199 2199 ((tp->t_iflag & (IGNPAR|ISTRIP)) == 0))) {
2200 2200 mutex_exit(&pp->port_mutex);
2201 2201
2202 2202 return;
2203 2203 }
2204 2204 mutex_exit(&pp->port_mutex);
2205 2205
2206 2206 while (mp) {
2207 2207 for (p = mp->b_rptr; p < mp->b_wptr; ) {
2208 2208 if (*p++ != 0377) {
2209 2209
2210 2210 continue;
2211 2211 }
2212 2212 USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
2213 2213 "usbser_rx_massage_data: mp=%p off=%ld(%ld)",
2214 2214 (void *)mp, _PTRDIFF(p, mp->b_rptr) - 1,
2215 2215 (long)MBLKL(mp));
2216 2216
2217 2217 /*
2218 2218 * insert another 0377 after this one. all data after
2219 2219 * the original 0377 have to be copied to the new mblk
2220 2220 */
2221 2221 tailsz = _PTRDIFF(mp->b_wptr, p);
2222 2222 if ((newmp = allocb(tailsz + 1, BPRI_HI)) == NULL) {
2223 2223 USB_DPRINTF_L2(DPRINT_RX_CB, pp->port_lh,
2224 2224 "usbser_rx_massage_data: allocb failed");
2225 2225
2226 2226 continue;
2227 2227 }
2228 2228
2229 2229 /* fill in the new mblk */
2230 2230 *newmp->b_wptr++ = 0377;
2231 2231 if (tailsz > 0) {
2232 2232 bcopy(p, newmp->b_wptr, tailsz);
2233 2233 newmp->b_wptr += tailsz;
2234 2234 }
2235 2235 /* shrink the original mblk */
2236 2236 mp->b_wptr = p;
2237 2237
2238 2238 newmp->b_cont = mp->b_cont;
2239 2239 mp->b_cont = newmp;
2240 2240 p = newmp->b_rptr + 1;
2241 2241 mp = newmp;
2242 2242 }
2243 2243 mp = mp->b_cont;
2244 2244 }
2245 2245 }
2246 2246
2247 2247 /*
2248 2248 * more joys of termio
2249 2249 */
2250 2250 static void
2251 2251 usbser_rx_massage_mbreak(usbser_port_t *pp, mblk_t *mp)
2252 2252 {
2253 2253 tty_common_t *tp = &pp->port_ttycommon;
2254 2254 uchar_t err, c;
2255 2255
2256 2256 err = *mp->b_rptr;
2257 2257 c = *(mp->b_rptr + 1);
2258 2258
2259 2259 if ((err & (DS_FRAMING_ERR | DS_BREAK_ERR)) && (c == 0)) {
2260 2260 /* break */
2261 2261 mp->b_rptr += 2;
2262 2262 } else if (!(tp->t_iflag & INPCK) && (err & (DS_PARITY_ERR))) {
2263 2263 /* Posix Ref: Assertion 7.1.2.2-20(C) */
2264 2264 mp->b_rptr++;
2265 2265 DB_TYPE(mp) = M_DATA;
2266 2266 } else {
2267 2267 /* for ldterm to handle */
2268 2268 mp->b_rptr++;
2269 2269 }
2270 2270
2271 2271 USB_DPRINTF_L4(DPRINT_RX_CB, pp->port_lh,
2272 2272 "usbser_rx_massage_mbreak: type=%x len=%ld [0]=0%o",
2273 2273 DB_TYPE(mp), (long)MBLKL(mp), (MBLKL(mp) > 0) ? *mp->b_rptr : 45);
2274 2274 }
2275 2275
2276 2276
2277 2277 /*
2278 2278 * in rx callback, try to send an mblk upstream
2279 2279 */
2280 2280 static void
2281 2281 usbser_rx_cb_put(usbser_port_t *pp, queue_t *rq, queue_t *wq, mblk_t *mp)
2282 2282 {
2283 2283 if (canputnext(rq)) {
2284 2284 putnext(rq, mp);
2285 2285 } else if (canput(rq) && putq(rq, mp)) {
2286 2286 /*
2287 2287 * full queue indicates the need for inbound flow control
2288 2288 */
2289 2289 (void) putctl(wq, M_STOPI);
2290 2290 usbser_st_put_stopi++;
2291 2291
2292 2292 USB_DPRINTF_L3(DPRINT_RX_CB, pp->port_lh,
2293 2293 "usbser_rx_cb: cannot putnext, flow ctl");
2294 2294 } else {
2295 2295 freemsg(mp);
2296 2296 usbser_st_rx_data_loss++;
2297 2297 (void) putctl(wq, M_STOPI);
2298 2298 usbser_st_put_stopi++;
2299 2299
2300 2300 USB_DPRINTF_L1(DPRINT_RX_CB, pp->port_lh,
2301 2301 "input overrun");
2302 2302 }
2303 2303 }
2304 2304
2305 2305
2306 2306 /*
2307 2307 * modem status change callback
2308 2308 *
2309 2309 * each time external status lines are changed, DSD calls this routine
2310 2310 */
2311 2311 static void
2312 2312 usbser_status_cb(caddr_t arg)
2313 2313 {
2314 2314 usbser_port_t *pp = (usbser_port_t *)arg;
2315 2315
2316 2316 USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_cb");
2317 2317
2318 2318 if (!usbser_dev_is_online(pp->port_usp)) {
2319 2319
2320 2320 return;
2321 2321 }
2322 2322
2323 2323 /*
2324 2324 * actual processing will be done in usbser_status_proc_cb()
2325 2325 * running in wq thread
2326 2326 */
2327 2327 mutex_enter(&pp->port_mutex);
2328 2328 if (USBSER_PORT_ACCESS_OK(pp) || USBSER_IS_OPENING(pp)) {
2329 2329 pp->port_flags |= USBSER_FL_STATUS_CB;
2330 2330 usbser_thr_wake(&pp->port_wq_thread);
2331 2331 }
2332 2332 mutex_exit(&pp->port_mutex);
2333 2333 }
2334 2334
2335 2335
2336 2336 /*
2337 2337 * modem status change
2338 2338 */
2339 2339 static void
2340 2340 usbser_status_proc_cb(usbser_port_t *pp)
2341 2341 {
2342 2342 tty_common_t *tp = &pp->port_ttycommon;
2343 2343 queue_t *rq, *wq;
2344 2344 int status;
2345 2345 int drop_dtr = 0;
2346 2346 int rq_msg = 0, wq_msg = 0;
2347 2347
2348 2348 USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh, "usbser_status_proc_cb");
2349 2349
2350 2350 pp->port_flags &= ~USBSER_FL_STATUS_CB;
2351 2351
2352 2352 mutex_exit(&pp->port_mutex);
2353 2353 if (!usbser_dev_is_online(pp->port_usp)) {
2354 2354 mutex_enter(&pp->port_mutex);
2355 2355
2356 2356 return;
2357 2357 }
2358 2358
2359 2359 /* get modem status */
2360 2360 if (USBSER_DS_GET_MODEM_CTL(pp, -1, &status) != USB_SUCCESS) {
2361 2361 mutex_enter(&pp->port_mutex);
2362 2362
2363 2363 return;
2364 2364 }
2365 2365
2366 2366 mutex_enter(&pp->port_mutex);
2367 2367 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2368 2368
2369 2369 rq = pp->port_ttycommon.t_readq;
2370 2370 wq = pp->port_ttycommon.t_writeq;
2371 2371
2372 2372 /*
2373 2373 * outbound flow control
2374 2374 */
2375 2375 if (tp->t_cflag & CRTSCTS) {
2376 2376 if (!(status & TIOCM_CTS)) {
2377 2377 /*
2378 2378 * CTS dropped, stop xmit
2379 2379 */
2380 2380 if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
2381 2381 wq_msg = M_STOP;
2382 2382 }
2383 2383 } else if (pp->port_flags & USBSER_FL_TX_STOPPED) {
2384 2384 /*
2385 2385 * CTS raised, resume xmit
2386 2386 */
2387 2387 wq_msg = M_START;
2388 2388 }
2389 2389 }
2390 2390
2391 2391 /*
2392 2392 * check carrier
2393 2393 */
2394 2394 if ((status & TIOCM_CD) || (tp->t_flags & TS_SOFTCAR)) {
2395 2395 /*
2396 2396 * carrier present
2397 2397 */
2398 2398 if ((pp->port_flags & USBSER_FL_CARR_ON) == 0) {
2399 2399 pp->port_flags |= USBSER_FL_CARR_ON;
2400 2400
2401 2401 rq_msg = M_UNHANGUP;
2402 2402 /*
2403 2403 * wake open
2404 2404 */
2405 2405 if (pp->port_flags & USBSER_FL_WOPEN) {
2406 2406 cv_broadcast(&pp->port_car_cv);
2407 2407 }
2408 2408
2409 2409 USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2410 2410 "usbser_status_cb: carr on");
2411 2411 }
2412 2412 } else if (pp->port_flags & USBSER_FL_CARR_ON) {
2413 2413 pp->port_flags &= ~USBSER_FL_CARR_ON;
2414 2414 /*
2415 2415 * carrier went away: if not local line, drop DTR
2416 2416 */
2417 2417 if (!(tp->t_cflag & CLOCAL)) {
2418 2418 drop_dtr = 1;
2419 2419 rq_msg = M_HANGUP;
2420 2420 }
2421 2421 if ((pp->port_flags & USBSER_FL_TX_STOPPED) && (wq_msg == 0)) {
2422 2422 wq_msg = M_START;
2423 2423 }
2424 2424
2425 2425 USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2426 2426 "usbser_status_cb: carr off");
2427 2427 }
2428 2428 mutex_exit(&pp->port_mutex);
2429 2429
2430 2430 USB_DPRINTF_L4(DPRINT_STATUS_CB, pp->port_lh,
2431 2431 "usbser_status_cb: rq_msg=%d wq_msg=%d", rq_msg, wq_msg);
2432 2432
2433 2433 /*
2434 2434 * commit postponed actions now
2435 2435 * do so only if port is fully open (queues are enabled)
2436 2436 */
2437 2437 if (rq) {
2438 2438 if (rq_msg) {
2439 2439 (void) putnextctl(rq, rq_msg);
2440 2440 }
2441 2441 if (drop_dtr) {
2442 2442 (void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR, 0);
2443 2443 }
2444 2444 if (wq_msg) {
2445 2445 (void) putctl(wq, wq_msg);
2446 2446 }
2447 2447 }
2448 2448
2449 2449 mutex_enter(&pp->port_mutex);
2450 2450 usbser_release_port_act(pp, USBSER_ACT_CTL);
2451 2451 }
2452 2452
2453 2453
2454 2454 /*
2455 2455 * serial support
2456 2456 * --------------
2457 2457 *
2458 2458 *
2459 2459 * this routine is run by wq thread every time it's woken,
2460 2460 * i.e. when the queue contains messages to process
2461 2461 */
2462 2462 static void
2463 2463 usbser_wmsg(usbser_port_t *pp)
2464 2464 {
2465 2465 queue_t *q = pp->port_ttycommon.t_writeq;
2466 2466 mblk_t *mp;
2467 2467 int msgtype;
2468 2468
2469 2469 ASSERT(mutex_owned(&pp->port_mutex));
2470 2470
2471 2471 if (q == NULL) {
2472 2472 USB_DPRINTF_L3(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=NULL");
2473 2473
2474 2474 return;
2475 2475 }
2476 2476 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: q=%p act=%x 0x%x",
2477 2477 (void *)q, pp->port_act, q->q_first ? DB_TYPE(q->q_first) : 0xff);
2478 2478
2479 2479 while ((mp = getq(q)) != NULL) {
2480 2480 msgtype = DB_TYPE(mp);
2481 2481 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_wmsg: "
2482 2482 "type=%s (0x%x)", usbser_msgtype2str(msgtype), msgtype);
2483 2483
2484 2484 switch (msgtype) {
2485 2485 /*
2486 2486 * high-priority messages
2487 2487 */
2488 2488 case M_STOP:
2489 2489 usbser_stop(pp, mp);
2490 2490
2491 2491 break;
2492 2492 case M_START:
2493 2493 usbser_start(pp, mp);
2494 2494
2495 2495 break;
2496 2496 case M_STOPI:
2497 2497 usbser_stopi(pp, mp);
2498 2498
2499 2499 break;
2500 2500 case M_STARTI:
2501 2501 usbser_starti(pp, mp);
2502 2502
2503 2503 break;
2504 2504 case M_IOCDATA:
2505 2505 usbser_iocdata(pp, mp);
2506 2506
2507 2507 break;
2508 2508 case M_FLUSH:
2509 2509 usbser_flush(pp, mp);
2510 2510
2511 2511 break;
2512 2512 /*
2513 2513 * normal-priority messages
2514 2514 */
2515 2515 case M_BREAK:
2516 2516 usbser_break(pp, mp);
2517 2517
2518 2518 break;
2519 2519 case M_DELAY:
2520 2520 usbser_delay(pp, mp);
2521 2521
2522 2522 break;
2523 2523 case M_DATA:
2524 2524 if (usbser_data(pp, mp) != USB_SUCCESS) {
2525 2525 (void) putbq(q, mp);
2526 2526
2527 2527 return;
2528 2528 }
2529 2529
2530 2530 break;
2531 2531 case M_IOCTL:
2532 2532 if (usbser_ioctl(pp, mp) != USB_SUCCESS) {
2533 2533 (void) putbq(q, mp);
2534 2534
2535 2535 return;
2536 2536 }
2537 2537
2538 2538 break;
2539 2539 default:
2540 2540 freemsg(mp);
2541 2541
2542 2542 break;
2543 2543 }
2544 2544 }
2545 2545 }
2546 2546
2547 2547
2548 2548 /*
2549 2549 * process M_DATA message
2550 2550 */
2551 2551 static int
2552 2552 usbser_data(usbser_port_t *pp, mblk_t *mp)
2553 2553 {
2554 2554 /* put off until current transfer ends or delay is over */
2555 2555 if ((pp->port_act & USBSER_ACT_TX) ||
2556 2556 (pp->port_act & USBSER_ACT_DELAY)) {
2557 2557
2558 2558 return (USB_FAILURE);
2559 2559 }
2560 2560 if (MBLKL(mp) <= 0) {
2561 2561 freemsg(mp);
2562 2562
2563 2563 return (USB_SUCCESS);
2564 2564 }
2565 2565
2566 2566 pp->port_act |= USBSER_ACT_TX;
2567 2567 pp->port_wq_data_cnt -= msgdsize(mp);
2568 2568
2569 2569 mutex_exit(&pp->port_mutex);
2570 2570 /* DSD is required to accept data block in any case */
2571 2571 (void) USBSER_DS_TX(pp, mp);
2572 2572 mutex_enter(&pp->port_mutex);
2573 2573
2574 2574 return (USB_SUCCESS);
2575 2575 }
2576 2576
2577 2577
2578 2578 /*
2579 2579 * process an M_IOCTL message
2580 2580 */
2581 2581 static int
2582 2582 usbser_ioctl(usbser_port_t *pp, mblk_t *mp)
2583 2583 {
2584 2584 tty_common_t *tp = &pp->port_ttycommon;
2585 2585 queue_t *q = tp->t_writeq;
2586 2586 struct iocblk *iocp;
2587 2587 int cmd;
2588 2588 mblk_t *datamp;
2589 2589 int error = 0, rval = USB_SUCCESS;
2590 2590 int val;
2591 2591
2592 2592 ASSERT(mutex_owned(&pp->port_mutex));
2593 2593 ASSERT(DB_TYPE(mp) == M_IOCTL);
2594 2594
2595 2595 iocp = (struct iocblk *)mp->b_rptr;
2596 2596 cmd = iocp->ioc_cmd;
2597 2597
2598 2598 USB_DPRINTF_L4(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
2599 2599 "mp=%p %s (0x%x)", (void *)mp, usbser_ioctl2str(cmd), cmd);
2600 2600
2601 2601 if (tp->t_iocpending != NULL) {
2602 2602 /*
2603 2603 * We were holding an ioctl response pending the
2604 2604 * availability of an mblk to hold data to be passed up;
2605 2605 * another ioctl came through, which means that ioctl
2606 2606 * must have timed out or been aborted.
2607 2607 */
2608 2608 freemsg(tp->t_iocpending);
2609 2609 tp->t_iocpending = NULL;
2610 2610 }
2611 2611
2612 2612 switch (cmd) {
2613 2613 case TIOCMGET:
2614 2614 case TIOCMBIC:
2615 2615 case TIOCMBIS:
2616 2616 case TIOCMSET:
2617 2617 case CONSOPENPOLLEDIO:
2618 2618 case CONSCLOSEPOLLEDIO:
2619 2619 case CONSSETABORTENABLE:
2620 2620 case CONSGETABORTENABLE:
2621 2621 /*
2622 2622 * For the above ioctls do not call ttycommon_ioctl() because
2623 2623 * this function frees up the message block (mp->b_cont) that
2624 2624 * contains the address of the user variable where we need to
2625 2625 * pass back the bit array.
2626 2626 */
2627 2627 error = -1;
2628 2628 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2629 2629 mutex_exit(&pp->port_mutex);
2630 2630 break;
2631 2631
2632 2632 case TCSBRK:
2633 2633 /* serialize breaks */
2634 2634 if (pp->port_act & USBSER_ACT_BREAK)
2635 2635 return (USB_FAILURE);
2636 2636 /*FALLTHRU*/
2637 2637 default:
2638 2638 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2639 2639 mutex_exit(&pp->port_mutex);
2640 2640 (void) ttycommon_ioctl(tp, q, mp, &error);
2641 2641 break;
2642 2642 }
2643 2643
2644 2644 if (error == 0) {
2645 2645 /*
2646 2646 * ttycommon_ioctl() did most of the work
2647 2647 * we just use the data it set up
2648 2648 */
2649 2649 switch (cmd) {
2650 2650 case TCSETSF:
2651 2651 case TCSETSW:
2652 2652 case TCSETA:
2653 2653 case TCSETAW:
2654 2654 case TCSETAF:
2655 2655 (void) USBSER_DS_FIFO_DRAIN(pp, DS_TX);
2656 2656 /*FALLTHRU*/
2657 2657
2658 2658 case TCSETS:
2659 2659 mutex_enter(&pp->port_mutex);
2660 2660 error = usbser_port_program(pp);
2661 2661 mutex_exit(&pp->port_mutex);
2662 2662 break;
2663 2663 }
2664 2664 goto end;
2665 2665
2666 2666 } else if (error > 0) {
2667 2667 USB_DPRINTF_L3(DPRINT_IOCTL, pp->port_lh, "usbser_ioctl: "
2668 2668 "ttycommon_ioctl returned %d", error);
2669 2669 goto end;
2670 2670 }
2671 2671
2672 2672 /*
2673 2673 * error < 0: ttycommon_ioctl() didn't do anything, we process it here
2674 2674 */
2675 2675 error = 0;
2676 2676 switch (cmd) {
2677 2677 case TCSBRK:
2678 2678 if ((error = miocpullup(mp, sizeof (int))) != 0)
2679 2679 break;
2680 2680
2681 2681 /* drain output */
2682 2682 (void) USBSER_DS_FIFO_DRAIN(pp, USBSER_TX_FIFO_DRAIN_TIMEOUT);
2683 2683
2684 2684 /*
2685 2685 * if required, set break
2686 2686 */
2687 2687 if (*(int *)mp->b_cont->b_rptr == 0) {
2688 2688 if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS) {
2689 2689 error = EIO;
2690 2690 break;
2691 2691 }
2692 2692
2693 2693 mutex_enter(&pp->port_mutex);
2694 2694 pp->port_act |= USBSER_ACT_BREAK;
2695 2695 pp->port_delay_id = timeout(usbser_restart, pp,
2696 2696 drv_usectohz(250000));
2697 2697 mutex_exit(&pp->port_mutex);
2698 2698 }
2699 2699 mioc2ack(mp, NULL, 0, 0);
2700 2700 break;
2701 2701
2702 2702 case TIOCSBRK: /* set break */
2703 2703 if (USBSER_DS_BREAK_CTL(pp, DS_ON) != USB_SUCCESS)
2704 2704 error = EIO;
2705 2705 else
2706 2706 mioc2ack(mp, NULL, 0, 0);
2707 2707 break;
2708 2708
2709 2709 case TIOCCBRK: /* clear break */
2710 2710 if (USBSER_DS_BREAK_CTL(pp, DS_OFF) != USB_SUCCESS)
2711 2711 error = EIO;
2712 2712 else
2713 2713 mioc2ack(mp, NULL, 0, 0);
2714 2714 break;
2715 2715
2716 2716 case TIOCMSET: /* set all modem bits */
2717 2717 case TIOCMBIS: /* bis modem bits */
2718 2718 case TIOCMBIC: /* bic modem bits */
2719 2719 if (iocp->ioc_count == TRANSPARENT) {
2720 2720 mcopyin(mp, NULL, sizeof (int), NULL);
2721 2721 break;
2722 2722 }
2723 2723 if ((error = miocpullup(mp, sizeof (int))) != 0)
2724 2724 break;
2725 2725
2726 2726 val = *(int *)mp->b_cont->b_rptr;
2727 2727 if (cmd == TIOCMSET) {
2728 2728 rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
2729 2729 } else if (cmd == TIOCMBIS) {
2730 2730 rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
2731 2731 } else if (cmd == TIOCMBIC) {
2732 2732 rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
2733 2733 }
2734 2734 if (rval == USB_SUCCESS)
2735 2735 mioc2ack(mp, NULL, 0, 0);
2736 2736 else
2737 2737 error = EIO;
2738 2738 break;
2739 2739
2740 2740 case TIOCSILOOP:
2741 2741 if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
2742 2742 if (USBSER_DS_LOOPBACK(pp, DS_ON) == USB_SUCCESS)
2743 2743 mioc2ack(mp, NULL, 0, 0);
2744 2744 else
2745 2745 error = EIO;
2746 2746 } else {
2747 2747 error = EINVAL;
2748 2748 }
2749 2749 break;
2750 2750
2751 2751 case TIOCCILOOP:
2752 2752 if (USBSER_DS_LOOPBACK_SUPPORTED(pp)) {
2753 2753 if (USBSER_DS_LOOPBACK(pp, DS_OFF) == USB_SUCCESS)
2754 2754 mioc2ack(mp, NULL, 0, 0);
2755 2755 else
2756 2756 error = EIO;
2757 2757 } else {
2758 2758 error = EINVAL;
2759 2759 }
2760 2760 break;
2761 2761
2762 2762 case TIOCMGET: /* get all modem bits */
2763 2763 if ((datamp = allocb(sizeof (int), BPRI_MED)) == NULL) {
2764 2764 error = EAGAIN;
2765 2765 break;
2766 2766 }
2767 2767 rval = USBSER_DS_GET_MODEM_CTL(pp, -1, (int *)datamp->b_rptr);
2768 2768 if (rval != USB_SUCCESS) {
2769 2769 error = EIO;
2770 2770 break;
2771 2771 }
2772 2772 if (iocp->ioc_count == TRANSPARENT)
2773 2773 mcopyout(mp, NULL, sizeof (int), NULL, datamp);
2774 2774 else
2775 2775 mioc2ack(mp, datamp, sizeof (int), 0);
2776 2776 break;
2777 2777
2778 2778 case CONSOPENPOLLEDIO:
2779 2779 error = usbser_polledio_init(pp);
2780 2780 if (error != 0)
2781 2781 break;
2782 2782
2783 2783 error = miocpullup(mp, sizeof (struct cons_polledio *));
2784 2784 if (error != 0)
2785 2785 break;
2786 2786
2787 2787 *(struct cons_polledio **)mp->b_cont->b_rptr = &usbser_polledio;
2788 2788
2789 2789 mp->b_datap->db_type = M_IOCACK;
2790 2790 break;
2791 2791
2792 2792 case CONSCLOSEPOLLEDIO:
2793 2793 usbser_polledio_fini(pp);
2794 2794 mp->b_datap->db_type = M_IOCACK;
2795 2795 iocp->ioc_error = 0;
2796 2796 iocp->ioc_rval = 0;
2797 2797 break;
2798 2798
2799 2799 case CONSSETABORTENABLE:
2800 2800 error = secpolicy_console(iocp->ioc_cr);
2801 2801 if (error != 0)
2802 2802 break;
2803 2803
2804 2804 if (iocp->ioc_count != TRANSPARENT) {
2805 2805 error = EINVAL;
2806 2806 break;
2807 2807 }
2808 2808
2809 2809 /*
2810 2810 * To do: implement console abort support
2811 2811 * This involves adding a console flag to usbser
2812 2812 * state structure. If flag is set, parse input stream
2813 2813 * for abort sequence (see asy for example).
2814 2814 *
2815 2815 * For now, run mdb -K to get kmdb prompt.
2816 2816 */
2817 2817 if (*(intptr_t *)mp->b_cont->b_rptr)
2818 2818 usbser_console_abort = 1;
2819 2819 else
2820 2820 usbser_console_abort = 0;
2821 2821
2822 2822 mp->b_datap->db_type = M_IOCACK;
2823 2823 iocp->ioc_error = 0;
2824 2824 iocp->ioc_rval = 0;
2825 2825 break;
2826 2826
2827 2827 case CONSGETABORTENABLE:
2828 2828 /*CONSTANTCONDITION*/
2829 2829 ASSERT(sizeof (boolean_t) <= sizeof (boolean_t *));
2830 2830 /*
2831 2831 * Store the return value right in the payload
2832 2832 * we were passed. Crude.
2833 2833 */
2834 2834 mcopyout(mp, NULL, sizeof (boolean_t), NULL, NULL);
2835 2835 *(boolean_t *)mp->b_cont->b_rptr = (usbser_console_abort != 0);
2836 2836 break;
2837 2837
2838 2838 default:
2839 2839 error = EINVAL;
2840 2840 break;
2841 2841 }
2842 2842 end:
2843 2843 if (error != 0)
2844 2844 miocnak(q, mp, 0, error);
2845 2845 else
2846 2846 qreply(q, mp);
2847 2847
2848 2848 mutex_enter(&pp->port_mutex);
2849 2849 usbser_release_port_act(pp, USBSER_ACT_CTL);
2850 2850
2851 2851 return (USB_SUCCESS);
2852 2852 }
2853 2853
2854 2854
2855 2855 /*
2856 2856 * process M_IOCDATA message
2857 2857 */
2858 2858 static void
2859 2859 usbser_iocdata(usbser_port_t *pp, mblk_t *mp)
2860 2860 {
2861 2861 tty_common_t *tp = &pp->port_ttycommon;
2862 2862 queue_t *q = tp->t_writeq;
2863 2863 struct copyresp *csp;
2864 2864 int cmd;
2865 2865 int val;
2866 2866 int rval = USB_FAILURE;
2867 2867
2868 2868 ASSERT(mutex_owned(&pp->port_mutex));
2869 2869
2870 2870 csp = (struct copyresp *)mp->b_rptr;
2871 2871 cmd = csp->cp_cmd;
2872 2872
2873 2873 if (csp->cp_rval != 0) {
2874 2874 freemsg(mp);
2875 2875 return;
2876 2876 }
2877 2877
2878 2878 switch (cmd) {
2879 2879 case TIOCMSET: /* set all modem bits */
2880 2880 case TIOCMBIS: /* bis modem bits */
2881 2881 case TIOCMBIC: /* bic modem bits */
2882 2882 if ((mp->b_cont == NULL) ||
2883 2883 (MBLKL(mp->b_cont) < sizeof (int))) {
2884 2884 miocnak(q, mp, 0, EINVAL);
2885 2885 break;
2886 2886 }
2887 2887 val = *(int *)mp->b_cont->b_rptr;
2888 2888
2889 2889 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2890 2890 mutex_exit(&pp->port_mutex);
2891 2891
2892 2892 if (cmd == TIOCMSET) {
2893 2893 rval = USBSER_DS_SET_MODEM_CTL(pp, -1, val);
2894 2894 } else if (cmd == TIOCMBIS) {
2895 2895 rval = USBSER_DS_SET_MODEM_CTL(pp, val, -1);
2896 2896 } else if (cmd == TIOCMBIC) {
2897 2897 rval = USBSER_DS_SET_MODEM_CTL(pp, val, 0);
2898 2898 }
2899 2899
2900 2900 if (mp->b_cont) {
2901 2901 freemsg(mp->b_cont);
2902 2902 mp->b_cont = NULL;
2903 2903 }
2904 2904
2905 2905 if (rval == USB_SUCCESS)
2906 2906 miocack(q, mp, 0, 0);
2907 2907 else
2908 2908 miocnak(q, mp, 0, EIO);
2909 2909
2910 2910 mutex_enter(&pp->port_mutex);
2911 2911 usbser_release_port_act(pp, USBSER_ACT_CTL);
2912 2912 break;
2913 2913
2914 2914 case TIOCMGET: /* get all modem bits */
2915 2915 mutex_exit(&pp->port_mutex);
2916 2916 miocack(q, mp, 0, 0);
2917 2917 mutex_enter(&pp->port_mutex);
2918 2918 break;
2919 2919
2920 2920 default:
2921 2921 mutex_exit(&pp->port_mutex);
2922 2922 miocnak(q, mp, 0, EINVAL);
2923 2923 mutex_enter(&pp->port_mutex);
2924 2924 break;
2925 2925 }
2926 2926 }
2927 2927
2928 2928
2929 2929 /*
2930 2930 * handle M_START[I]/M_STOP[I] messages
2931 2931 */
2932 2932 static void
2933 2933 usbser_stop(usbser_port_t *pp, mblk_t *mp)
2934 2934 {
2935 2935 usbser_st_mstop++;
2936 2936 if (!(pp->port_flags & USBSER_FL_TX_STOPPED)) {
2937 2937 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2938 2938 pp->port_flags |= USBSER_FL_TX_STOPPED;
2939 2939
2940 2940 mutex_exit(&pp->port_mutex);
2941 2941 USBSER_DS_STOP(pp, DS_TX);
2942 2942 mutex_enter(&pp->port_mutex);
2943 2943
2944 2944 usbser_release_port_act(pp, USBSER_ACT_TX);
2945 2945 usbser_release_port_act(pp, USBSER_ACT_CTL);
2946 2946 }
2947 2947 freemsg(mp);
2948 2948 }
2949 2949
2950 2950
2951 2951 static void
2952 2952 usbser_start(usbser_port_t *pp, mblk_t *mp)
2953 2953 {
2954 2954 usbser_st_mstart++;
2955 2955 if (pp->port_flags & USBSER_FL_TX_STOPPED) {
2956 2956 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2957 2957 pp->port_flags &= ~USBSER_FL_TX_STOPPED;
2958 2958
2959 2959 mutex_exit(&pp->port_mutex);
2960 2960 USBSER_DS_START(pp, DS_TX);
2961 2961 mutex_enter(&pp->port_mutex);
2962 2962 usbser_release_port_act(pp, USBSER_ACT_CTL);
2963 2963 }
2964 2964 freemsg(mp);
2965 2965 }
2966 2966
2967 2967
2968 2968 static void
2969 2969 usbser_stopi(usbser_port_t *pp, mblk_t *mp)
2970 2970 {
2971 2971 usbser_st_mstopi++;
2972 2972 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2973 2973 pp->port_flowc = pp->port_ttycommon.t_stopc;
2974 2974 usbser_inbound_flow_ctl(pp);
2975 2975 usbser_release_port_act(pp, USBSER_ACT_CTL);
2976 2976 freemsg(mp);
2977 2977 }
2978 2978
2979 2979 static void
2980 2980 usbser_starti(usbser_port_t *pp, mblk_t *mp)
2981 2981 {
2982 2982 usbser_st_mstarti++;
2983 2983 usbser_serialize_port_act(pp, USBSER_ACT_CTL);
2984 2984 pp->port_flowc = pp->port_ttycommon.t_startc;
2985 2985 usbser_inbound_flow_ctl(pp);
2986 2986 usbser_release_port_act(pp, USBSER_ACT_CTL);
2987 2987 freemsg(mp);
2988 2988 }
2989 2989
2990 2990 /*
2991 2991 * process M_FLUSH message
2992 2992 */
2993 2993 static void
2994 2994 usbser_flush(usbser_port_t *pp, mblk_t *mp)
2995 2995 {
2996 2996 queue_t *q = pp->port_ttycommon.t_writeq;
2997 2997
2998 2998 if (*mp->b_rptr & FLUSHW) {
2999 2999 mutex_exit(&pp->port_mutex);
3000 3000 (void) USBSER_DS_FIFO_FLUSH(pp, DS_TX); /* flush FIFO buffers */
3001 3001 flushq(q, FLUSHDATA); /* flush write queue */
3002 3002 mutex_enter(&pp->port_mutex);
3003 3003
3004 3004 usbser_release_port_act(pp, USBSER_ACT_TX);
3005 3005
3006 3006 *mp->b_rptr &= ~FLUSHW;
3007 3007 }
3008 3008 if (*mp->b_rptr & FLUSHR) {
3009 3009 /*
3010 3010 * flush FIFO buffers
3011 3011 */
3012 3012 mutex_exit(&pp->port_mutex);
3013 3013 (void) USBSER_DS_FIFO_FLUSH(pp, DS_RX);
3014 3014 flushq(RD(q), FLUSHDATA);
3015 3015 qreply(q, mp);
3016 3016 mutex_enter(&pp->port_mutex);
3017 3017 } else {
3018 3018 freemsg(mp);
3019 3019 }
3020 3020 }
3021 3021
3022 3022 /*
3023 3023 * process M_BREAK message
3024 3024 */
3025 3025 static void
3026 3026 usbser_break(usbser_port_t *pp, mblk_t *mp)
3027 3027 {
3028 3028 int rval;
3029 3029
3030 3030 /*
3031 3031 * set the break and arrange for usbser_restart() to be called in 1/4 s
3032 3032 */
3033 3033 mutex_exit(&pp->port_mutex);
3034 3034 rval = USBSER_DS_BREAK_CTL(pp, DS_ON);
3035 3035 mutex_enter(&pp->port_mutex);
3036 3036
3037 3037 if (rval == USB_SUCCESS) {
3038 3038 pp->port_act |= USBSER_ACT_BREAK;
3039 3039 pp->port_delay_id = timeout(usbser_restart, pp,
3040 3040 drv_usectohz(250000));
3041 3041 }
3042 3042 freemsg(mp);
3043 3043 }
3044 3044
3045 3045
3046 3046 /*
3047 3047 * process M_DELAY message
3048 3048 */
3049 3049 static void
3050 3050 usbser_delay(usbser_port_t *pp, mblk_t *mp)
3051 3051 {
3052 3052 /*
3053 3053 * arrange for usbser_restart() to be called when the delay expires
3054 3054 */
3055 3055 pp->port_act |= USBSER_ACT_DELAY;
3056 3056 pp->port_delay_id = timeout(usbser_restart, pp,
3057 3057 (clock_t)(*(uchar_t *)mp->b_rptr + 6));
3058 3058 freemsg(mp);
3059 3059 }
3060 3060
3061 3061
3062 3062 /*
3063 3063 * restart output on a line after a delay or break timer expired
3064 3064 */
3065 3065 static void
3066 3066 usbser_restart(void *arg)
3067 3067 {
3068 3068 usbser_port_t *pp = (usbser_port_t *)arg;
3069 3069
3070 3070 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh, "usbser_restart");
3071 3071
3072 3072 mutex_enter(&pp->port_mutex);
3073 3073 /* if cancelled, return immediately */
3074 3074 if (pp->port_delay_id == 0) {
3075 3075 mutex_exit(&pp->port_mutex);
3076 3076
3077 3077 return;
3078 3078 }
3079 3079 pp->port_delay_id = 0;
3080 3080
3081 3081 /* clear break if necessary */
3082 3082 if (pp->port_act & USBSER_ACT_BREAK) {
3083 3083 mutex_exit(&pp->port_mutex);
3084 3084 (void) USBSER_DS_BREAK_CTL(pp, DS_OFF);
3085 3085 mutex_enter(&pp->port_mutex);
3086 3086 }
3087 3087
3088 3088 usbser_release_port_act(pp, USBSER_ACT_BREAK | USBSER_ACT_DELAY);
3089 3089
3090 3090 /* wake wq thread to resume message processing */
3091 3091 usbser_thr_wake(&pp->port_wq_thread);
3092 3092 mutex_exit(&pp->port_mutex);
3093 3093 }
3094 3094
3095 3095
3096 3096 /*
3097 3097 * program port hardware with the chosen parameters
3098 3098 * most of the operation is based on the values of 'c_iflag' and 'c_cflag'
3099 3099 */
3100 3100 static int
3101 3101 usbser_port_program(usbser_port_t *pp)
3102 3102 {
3103 3103 tty_common_t *tp = &pp->port_ttycommon;
3104 3104 int baudrate;
3105 3105 int c_flag;
3106 3106 ds_port_param_entry_t pe[6];
3107 3107 ds_port_params_t params;
3108 3108 int flow_ctl, ctl_val;
3109 3109 int err = 0;
3110 3110
3111 3111 baudrate = tp->t_cflag & CBAUD;
3112 3112 if (tp->t_cflag & CBAUDEXT) {
3113 3113 baudrate += 16;
3114 3114 }
3115 3115
3116 3116 /*
3117 3117 * set input speed same as output, as split speed not supported
3118 3118 */
3119 3119 if (tp->t_cflag & (CIBAUD|CIBAUDEXT)) {
3120 3120 tp->t_cflag &= ~(CIBAUD);
3121 3121 if (baudrate > CBAUD) {
3122 3122 tp->t_cflag |= CIBAUDEXT;
3123 3123 tp->t_cflag |=
3124 3124 (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD);
3125 3125 } else {
3126 3126 tp->t_cflag &= ~CIBAUDEXT;
3127 3127 tp->t_cflag |= ((baudrate << IBSHIFT) & CIBAUD);
3128 3128 }
3129 3129 }
3130 3130
3131 3131 c_flag = tp->t_cflag;
3132 3132
3133 3133 /*
3134 3134 * flow control
3135 3135 */
3136 3136 flow_ctl = tp->t_iflag & (IXON | IXANY | IXOFF);
3137 3137 if (c_flag & CRTSCTS) {
3138 3138 flow_ctl |= CTSXON;
3139 3139 }
3140 3140 if (c_flag & CRTSXOFF) {
3141 3141 flow_ctl |= RTSXOFF;
3142 3142 }
3143 3143
3144 3144 /*
3145 3145 * fill in port parameters we need to set:
3146 3146 *
3147 3147 * baud rate
3148 3148 */
3149 3149 pe[0].param = DS_PARAM_BAUD;
3150 3150 pe[0].val.ui = baudrate;
3151 3151
3152 3152 /* stop bits */
3153 3153 pe[1].param = DS_PARAM_STOPB;
3154 3154 pe[1].val.ui = c_flag & CSTOPB;
3155 3155
3156 3156 /* parity */
3157 3157 pe[2].param = DS_PARAM_PARITY;
3158 3158 pe[2].val.ui = c_flag & (PARENB | PARODD);
3159 3159
3160 3160 /* char size */
3161 3161 pe[3].param = DS_PARAM_CHARSZ;
3162 3162 pe[3].val.ui = c_flag & CSIZE;
3163 3163
3164 3164 /* start & stop chars */
3165 3165 pe[4].param = DS_PARAM_XON_XOFF;
3166 3166 pe[4].val.uc[0] = tp->t_startc;
3167 3167 pe[4].val.uc[1] = tp->t_stopc;
3168 3168
3169 3169 /* flow control */
3170 3170 pe[5].param = DS_PARAM_FLOW_CTL;
3171 3171 pe[5].val.ui = flow_ctl;
3172 3172
3173 3173 params.tp_entries = &pe[0];
3174 3174 params.tp_cnt = 6;
3175 3175
3176 3176 /* control signals */
3177 3177 ctl_val = TIOCM_DTR | TIOCM_RTS;
3178 3178 if (baudrate == 0) {
3179 3179 ctl_val &= ~TIOCM_DTR; /* zero baudrate means drop DTR */
3180 3180 }
3181 3181 if (pp->port_flags & USBSER_FL_RX_STOPPED) {
3182 3182 ctl_val &= ~TIOCM_RTS;
3183 3183 }
3184 3184
3185 3185 /* submit */
3186 3186 mutex_exit(&pp->port_mutex);
3187 3187 err = USBSER_DS_SET_PORT_PARAMS(pp, ¶ms);
3188 3188 if (err != USB_SUCCESS) {
3189 3189 mutex_enter(&pp->port_mutex);
3190 3190
3191 3191 return (EINVAL);
3192 3192 }
3193 3193
3194 3194 err = USBSER_DS_SET_MODEM_CTL(pp, TIOCM_DTR | TIOCM_RTS, ctl_val);
3195 3195 mutex_enter(&pp->port_mutex);
3196 3196
3197 3197 return ((err == USB_SUCCESS) ? 0 : EIO);
3198 3198 }
3199 3199
3200 3200
3201 3201 /*
3202 3202 * check if any inbound flow control action needed
3203 3203 */
3204 3204 static void
3205 3205 usbser_inbound_flow_ctl(usbser_port_t *pp)
3206 3206 {
3207 3207 tcflag_t need_hw;
3208 3208 int rts;
3209 3209 char c = pp->port_flowc;
3210 3210 mblk_t *mp = NULL;
3211 3211
3212 3212 USB_DPRINTF_L4(DPRINT_WQ, pp->port_lh,
3213 3213 "usbser_inbound_flow_ctl: c=%x cflag=%x port_flags=%x",
3214 3214 c, pp->port_ttycommon.t_cflag, pp->port_flags);
3215 3215
3216 3216 if (c == '\0') {
3217 3217
3218 3218 return;
3219 3219 }
3220 3220 pp->port_flowc = '\0';
3221 3221
3222 3222 /*
3223 3223 * if inbound hardware flow control enabled, we need to frob RTS
3224 3224 */
3225 3225 need_hw = (pp->port_ttycommon.t_cflag & CRTSXOFF);
3226 3226 if (c == pp->port_ttycommon.t_startc) {
3227 3227 rts = TIOCM_RTS;
3228 3228 pp->port_flags &= ~USBSER_FL_RX_STOPPED;
3229 3229 } else {
3230 3230 rts = 0;
3231 3231 pp->port_flags |= USBSER_FL_RX_STOPPED;
3232 3232 }
3233 3233
3234 3234 /*
3235 3235 * if character flow control active, transmit a start or stop char,
3236 3236 */
3237 3237 if (pp->port_ttycommon.t_iflag & IXOFF) {
3238 3238 if ((mp = allocb(1, BPRI_LO)) == NULL) {
3239 3239 USB_DPRINTF_L2(DPRINT_WQ, pp->port_lh,
3240 3240 "usbser_inbound_flow_ctl: allocb failed");
3241 3241 } else {
3242 3242 *mp->b_wptr++ = c;
3243 3243 pp->port_flags |= USBSER_ACT_TX;
3244 3244 }
3245 3245 }
3246 3246
3247 3247 mutex_exit(&pp->port_mutex);
3248 3248 if (need_hw) {
3249 3249 (void) USBSER_DS_SET_MODEM_CTL(pp, TIOCM_RTS, rts);
3250 3250 }
3251 3251 if (mp) {
3252 3252 (void) USBSER_DS_TX(pp, mp);
3253 3253 }
3254 3254 mutex_enter(&pp->port_mutex);
3255 3255 }
3256 3256
3257 3257
3258 3258 /*
3259 3259 * misc
3260 3260 * ----
3261 3261 *
3262 3262 *
3263 3263 * returns != 0 if device is online, 0 otherwise
3264 3264 */
3265 3265 static int
3266 3266 usbser_dev_is_online(usbser_state_t *usp)
3267 3267 {
3268 3268 int rval;
3269 3269
3270 3270 mutex_enter(&usp->us_mutex);
3271 3271 rval = (usp->us_dev_state == USB_DEV_ONLINE);
3272 3272 mutex_exit(&usp->us_mutex);
3273 3273
3274 3274 return (rval);
3275 3275 }
3276 3276
3277 3277 /*
3278 3278 * serialize port activities defined by 'act' mask
3279 3279 */
3280 3280 static void
3281 3281 usbser_serialize_port_act(usbser_port_t *pp, int act)
3282 3282 {
3283 3283 while (pp->port_act & act)
3284 3284 cv_wait(&pp->port_act_cv, &pp->port_mutex);
3285 3285 pp->port_act |= act;
3286 3286 }
3287 3287
3288 3288
3289 3289 /*
3290 3290 * indicate that port activity is finished
3291 3291 */
3292 3292 static void
3293 3293 usbser_release_port_act(usbser_port_t *pp, int act)
3294 3294 {
3295 3295 pp->port_act &= ~act;
3296 3296 cv_broadcast(&pp->port_act_cv);
3297 3297 }
3298 3298
3299 3299 #ifdef DEBUG
3300 3300 /*
3301 3301 * message type to string and back conversion.
3302 3302 *
3303 3303 * pardon breaks on the same line, but as long as cstyle doesn't
3304 3304 * complain, I'd like to keep this form for trivial cases like this.
3305 3305 * associative arrays in the kernel, anyone?
3306 3306 */
3307 3307 static char *
3308 3308 usbser_msgtype2str(int type)
3309 3309 {
3310 3310 char *str;
3311 3311
3312 3312 switch (type) {
3313 3313 case M_STOP: str = "M_STOP"; break;
3314 3314 case M_START: str = "M_START"; break;
3315 3315 case M_STOPI: str = "M_STOPI"; break;
3316 3316 case M_STARTI: str = "M_STARTI"; break;
3317 3317 case M_DATA: str = "M_DATA"; break;
3318 3318 case M_DELAY: str = "M_DELAY"; break;
3319 3319 case M_BREAK: str = "M_BREAK"; break;
3320 3320 case M_IOCTL: str = "M_IOCTL"; break;
3321 3321 case M_IOCDATA: str = "M_IOCDATA"; break;
3322 3322 case M_FLUSH: str = "M_FLUSH"; break;
3323 3323 case M_CTL: str = "M_CTL"; break;
3324 3324 case M_READ: str = "M_READ"; break;
3325 3325 default: str = "unknown"; break;
3326 3326 }
3327 3327
3328 3328 return (str);
3329 3329 }
3330 3330
3331 3331 static char *
3332 3332 usbser_ioctl2str(int ioctl)
3333 3333 {
3334 3334 char *str;
3335 3335
3336 3336 switch (ioctl) {
3337 3337 case TCGETA: str = "TCGETA"; break;
3338 3338 case TCSETA: str = "TCSETA"; break;
3339 3339 case TCSETAF: str = "TCSETAF"; break;
3340 3340 case TCSETAW: str = "TCSETAW"; break;
3341 3341 case TCSBRK: str = "TCSBRK"; break;
3342 3342 case TCXONC: str = "TCXONC"; break;
3343 3343 case TCFLSH: str = "TCFLSH"; break;
3344 3344 case TCGETS: str = "TCGETS"; break;
3345 3345 case TCSETS: str = "TCSETS"; break;
3346 3346 case TCSETSF: str = "TCSETSF"; break;
3347 3347 case TCSETSW: str = "TCSETSW"; break;
3348 3348 case TIOCSBRK: str = "TIOCSBRK"; break;
3349 3349 case TIOCCBRK: str = "TIOCCBRK"; break;
3350 3350 case TIOCMSET: str = "TIOCMSET"; break;
3351 3351 case TIOCMBIS: str = "TIOCMBIS"; break;
3352 3352 case TIOCMBIC: str = "TIOCMBIC"; break;
3353 3353 case TIOCMGET: str = "TIOCMGET"; break;
3354 3354 case TIOCSILOOP: str = "TIOCSILOOP"; break;
3355 3355 case TIOCCILOOP: str = "TIOCCILOOP"; break;
3356 3356 case TCGETX: str = "TCGETX"; break;
3357 3357 case TCSETX: str = "TCGETX"; break;
3358 3358 case TCSETXW: str = "TCGETX"; break;
3359 3359 case TCSETXF: str = "TCGETX"; break;
3360 3360 default: str = "unknown"; break;
3361 3361 }
3362 3362
3363 3363 return (str);
3364 3364 }
3365 3365 #endif
3366 3366 /*
3367 3367 * Polled IO support
3368 3368 */
3369 3369
3370 3370 /* called once by consconfig() when polledio is opened */
3371 3371 static int
3372 3372 usbser_polledio_init(usbser_port_t *pp)
3373 3373 {
3374 3374 int err;
3375 3375 usb_pipe_handle_t hdl;
3376 3376 ds_ops_t *ds_ops = pp->port_ds_ops;
3377 3377
3378 3378 /* only one serial line console supported */
3379 3379 if (console_input != NULL)
3380 3380 return (USB_FAILURE);
3381 3381
3382 3382 /* check if underlying driver supports polled io */
3383 3383 if (ds_ops->ds_version < DS_OPS_VERSION_V1 ||
3384 3384 ds_ops->ds_out_pipe == NULL || ds_ops->ds_in_pipe == NULL)
3385 3385 return (USB_FAILURE);
3386 3386
3387 3387 /* init polled input pipe */
3388 3388 hdl = ds_ops->ds_in_pipe(pp->port_ds_hdl, pp->port_num);
3389 3389 err = usb_console_input_init(pp->port_usp->us_dip, hdl,
3390 3390 &console_input_buf, &console_input);
3391 3391 if (err)
3392 3392 return (USB_FAILURE);
3393 3393
3394 3394 /* init polled output pipe */
3395 3395 hdl = ds_ops->ds_out_pipe(pp->port_ds_hdl, pp->port_num);
3396 3396 err = usb_console_output_init(pp->port_usp->us_dip, hdl,
3397 3397 &console_output);
3398 3398 if (err) {
3399 3399 (void) usb_console_input_fini(console_input);
3400 3400 console_input = NULL;
3401 3401 return (USB_FAILURE);
3402 3402 }
3403 3403
3404 3404 return (USB_SUCCESS);
3405 3405 }
3406 3406
3407 3407 /* called once by consconfig() when polledio is closed */
3408 3408 /*ARGSUSED*/
3409 3409 static void usbser_polledio_fini(usbser_port_t *pp)
3410 3410 {
3411 3411 /* Since we can't move the console, there is nothing to do. */
3412 3412 }
3413 3413
3414 3414 /*ARGSUSED*/
3415 3415 static void
3416 3416 usbser_polledio_enter(cons_polledio_arg_t arg)
3417 3417 {
3418 3418 (void) usb_console_input_enter(console_input);
3419 3419 (void) usb_console_output_enter(console_output);
3420 3420 }
3421 3421
3422 3422 /*ARGSUSED*/
3423 3423 static void
3424 3424 usbser_polledio_exit(cons_polledio_arg_t arg)
3425 3425 {
3426 3426 (void) usb_console_output_exit(console_output);
3427 3427 (void) usb_console_input_exit(console_input);
3428 3428 }
3429 3429
3430 3430 /*ARGSUSED*/
3431 3431 static void
3432 3432 usbser_putchar(cons_polledio_arg_t arg, uchar_t c)
3433 3433 {
3434 3434 static uchar_t cr[2] = {'\r', '\n'};
3435 3435 uint_t nout;
3436 3436
3437 3437 if (c == '\n')
3438 3438 (void) usb_console_write(console_output, cr, 2, &nout);
3439 3439 else
3440 3440 (void) usb_console_write(console_output, &c, 1, &nout);
3441 3441 }
3442 3442
3443 3443 /*ARGSUSED*/
3444 3444 static int
3445 3445 usbser_getchar(cons_polledio_arg_t arg)
3446 3446 {
3447 3447 while (!usbser_ischar(arg))
3448 3448 ;
3449 3449
3450 3450 return (*console_input_start++);
3451 3451 }
3452 3452
3453 3453 /*ARGSUSED*/
3454 3454 static boolean_t
3455 3455 usbser_ischar(cons_polledio_arg_t arg)
3456 3456 {
3457 3457 uint_t num_bytes;
3458 3458
3459 3459 if (console_input_start < console_input_end)
3460 3460 return (B_TRUE);
3461 3461
3462 3462 if (usb_console_read(console_input, &num_bytes) != USB_SUCCESS)
3463 3463 return (B_FALSE);
3464 3464
3465 3465 console_input_start = console_input_buf;
3466 3466 console_input_end = console_input_buf + num_bytes;
3467 3467
3468 3468 return (num_bytes != 0);
3469 3469 }
↓ open down ↓ |
3240 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX