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