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