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