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