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