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