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